Interactivity

Having SSR is all fun and games, however sometimes you might want to have some dynamic or interactive content on your website. Since Atlet is primarily SSR focused, there is no builtin way to make components dynamic (unlike Deno's Fresh Interactive islands).

However, it doesn't stop you from using popular libraries, such as petite-vuealpine.js, or even a full-fledged Vue, with small caveats.

First example

Here is an example of using petite-vue in Atlet page.

/**@jsx h */
/**@jsxFrag Fragment */
import { Props, h, Fragment } from 'https://deno.land/x/atlet@1.2.0/mod.ts'

export default function Page(props: Props) {
  props.page.head.push(
    <script src="/petite-vue.js" />,
  )

  return (
    <div v-scope="{ count: 0 }">
      <!-- {{ count }} in this example must be escaped, because -->
      <!-- otherwise it will get evaluated on the server. -->
      <p>Current count is {'{{ count }}'}</p>

      <!-- In case of petite-vue, you can't use event listeners with '@' prefix, -->
      <!-- because having '@' in JSX is not valid, hence leading to an error. -->
      <button v-on:click="count++">Increment</button>
    </div>
  )
}

Result:

Current count is {{{ count }}}

Second example

Here is a bit more complex example of sending a request without a full page refresh

fetch.js
import { createApp } from './petite-vue.js'

createApp({
  randomNumber: null,
  loading: false,
  async getRandomNumber() {
    this.loading = true
    const response = await fetch('/api/random').then(r => r.json())
    this.loading = false
    this.randomNumber = response.randomNumber
  }
}).mount()
main.tsx
/**@jsx h */
/**@jsxFrag Fragment */
import { serve } from 'https://deno.land/std/http/server.ts'
import { createHandler, Props, h, Fragment, json } from 'https://deno.land/x/atlet@1.2.0/mod.ts'

const handler = await createHandler({
  '/api/random': async () => {
    await new Promise(r => setTimeout(r, 1000))
    return json({
      randomNumber: 1 + Math.random() * 100 | 0,
    })
  },
  '/': (props: Props) => {
    props.page.head.push(
      <script src="/demo/fetch.js" type="module"></script>,
    )

    return (
      <div v-scope>
        <h1 v-if="randomNumber">Random number is {'{{ randomNumber }}'}</h1>
        <button 
          v-bind:disabled="loading"
          v-on:click="getRandomNumber">
          {'{{ loading ? "Loading ..." : "Get random number" }}'}
        </button>
      </div>
    )
  }
}, {
  static: './static'
})

// you can also use Deno.serve which is available in Deno 1.35
serve(handler)

Result:

Random number is {{{ randomNumber }}}