notes.dt.in.th

How about some interactivity inside a note?

...and here's the code that implements the above button:

<p>
  <button @click="count++" :disabled="!mounted">0</button>
</p>

<script>
  export default {
    setup() {
      const count = Vue.ref(0)
      const mounted = Vue.ref(false)
      Vue.onMounted(() => {
        mounted.value = true
      })
      return { hello: 'Hello, World', count, mounted }
    },
  }
</script>

Here's how it works:

  • The server-side code first converts Markdown to HTML using @vuepress/markdown. It automatically extracts out the <script> and <style> tags.
  • The HTML is then parsed as a Vue template and compiled into render functions using vue-template-compiler as JavaScript source code.
  • The <script> tag is compiled using esbuild into a JavaScript source code.
  • The resulting source codes are then used to assemble a Vue component. This happens both on the client and on the server. The server then renders a static HTML version of the component, and the client then hydrates it.

The compilation process

Archive — How it works in the previous version of notes.dt.in.th (Nuxt-based)

Here's how it works:

  • In the contents API, when the Markdown file is parsed, @vuepress/markdown automatically extracts out the <script> and <style> tags. I assume that there will be only one <script> tag. If one is found, then the contents of the <script> tag is compiled down to ES6 + CommonJS using esbuild. This compiled JavaScript is then returned over the wire.

  • In the Nuxt app, if a component module is included in the response, Nuxt will compile that code as part of the Vue component, on-the-fly, at runtime.

This results in the following markup:

For full changes, see the pull request.