Progressive Vue

Bringing in Vue via CDN

Adding Vue to HTML

Let's add Vue.js to the HTML from the previous chapter.
All it takes is an Import Map and <script type="module">.

<script type="importmap">
  {
    "imports": {
      "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
    }
  }
</script>
<script type="module">
  import { createApp } from 'vue'
  // ...
</script>

No npm install, no node_modules, no package.json.
Just import Vue using the browser's native ESM (ES Modules).

What Is Import Map?

Import Map tells the browser: "the name 'vue' refers to this URL."
It's the HTML equivalent of Node.js's node_modules — declared in a <script> tag.

Creating a Vue Application

Once Vue is loaded, we create an application and mount it to the HTML.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>My App</title>
  <style>
    body {
      font-family: sans-serif;
      max-width: 600px;
      margin: 40px auto;
      padding: 0 20px;
    }
    .card {
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      padding: 20px;
      margin-bottom: 16px;
    }
    .card h2 { margin-top: 0; }
    .tag {
      display: inline-block;
      background: #edf2f7;
      border-radius: 4px;
      padding: 2px 8px;
      font-size: 0.85em;
      margin-right: 4px;
    }
  </style>
</head>
<body>

  <div id="app">
    <h1>My Bookshelf</h1>
    <p>A record of recently read books.</p>

    <div class="card">
      <h2>Readable Code</h2>
      <p>Practical techniques for writing readable code.</p>
      <span class="tag">programming</span>
      <span class="tag">practices</span>
    </div>

    <div class="card">
      <h2>Fundamentals of Programming Languages</h2>
      <p>Learn the fundamental concepts behind language design.</p>
      <span class="tag">cs</span>
      <span class="tag">language</span>
    </div>

    <div class="card">
      <h2>Web Browser Security</h2>
      <p>A systematic guide to browser security.</p>
      <span class="tag">security</span>
      <span class="tag">browser</span>
    </div>
  </div>

  <script type="importmap">
    {
      "imports": {
        "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
      }
    }
  </script>
  <script type="module">
    import { createApp } from 'vue'

    createApp({}).mount('#app')
  </script>

</body>
</html>

Open it in your browser. It looks exactly the same as before.

This is what "Progressive" means.
Adding Vue doesn't break existing HTML.
You just wrap it in <div id="app"> and call createApp({}).mount('#app').
You've only specified a "mount point" — the content inside remains just HTML.

Moving Data to JavaScript

Now Vue starts to shine.
We'll move the hard-coded data from HTML into JavaScript.

We use Vue's ref() to create reactive data.

<script type="module">
  import { createApp, ref } from 'vue'

  createApp({
    setup() {
      const books = ref([
        {
          title: 'Readable Code',
          description: 'Practical techniques for writing readable code.',
          tags: ['programming', 'practices']
        },
        {
          title: 'Fundamentals of Programming Languages',
          description: 'Learn the fundamental concepts behind language design.',
          tags: ['cs', 'language']
        },
        {
          title: 'Web Browser Security',
          description: 'A systematic guide to browser security.',
          tags: ['security', 'browser']
        }
      ])

      return { books }
    }
  }).mount('#app')
</script>

Inside the setup() function, we define data with ref() and expose it to the template via return.
return { books } — now the template can access books by name.

But we're not using this data in the template yet.
We'll do that in the next chapter.

File Structure So Far

Let's step back and look at our file structure.

index.html   ← that's it

There's just one file.
The framework loads from a CDN via ESM.
No build step.
No local server needed (just double-click the file).

Summary

  • Vue.js can be added with CDN + Import Map — no npm required
  • import { createApp } from 'vue' — loaded via browser-native ESM
  • Just wrap existing HTML in <div id="app"> and mount
  • Nothing changes visually — that's Progressive
  • Use ref() inside setup() to define reactive data
  • Still just a single index.html file

Related

Back to book