Introduction

Not long ago I wrote a brief article describing how to create a simple Vue JS application without any build pipeline. It was received with a lot of interest and feedback. Many readers have asked whether a similar feat would be possible with the upcoming Vue 3 release of the framework. The answer turns out to be positive. Also with Vue 3 one can go quite far and enjoy the powers of the progressive web framework without any build process.

The original article about Vue 2 version can be found at https://letsdebug.it/post/minimalistic-vue. Below we describe how a similar setup can be realized with Vue 3.

Source code for the article can be found at https://bitbucket.org/letsdebugit/minimalistic-vue-3. You can run the sample application here.

Application Design

Similar to the Vue 2 example, we will create a small one-page web application with a header, content area and a footer. In the content area there’s a message and a button. When user clicks on the button, the message changes. The UI is made of Vue components represented by custom HTML tags.

Project structure

The project is structured identically as Vue 2 version:

index.html
index.js
index.css
header/
    header.js
    header.css
content/
    content.js
    content.css
footer/
    footer.js
    footer.css

Our logical UI components are clearly reflected in the physical structure of the project. There are changes though inside the components’ code, as described below.

Bootstrapping

When browser loads index.html, the following happens:

  • Vue JS v.3 library is fetched from CDN repository at https://unpkg.com/[email protected].
  • Component stylesheets are fetched
  • Application module is imported from index.js and executed

Notice that at the moment of writing Vue 3 still hasn’t been oficially released. Therefore we’re use here the newest available version 3.0.0-rc.8. When official release comes, you will have to change the URL accordingly.

When index.js is executed, it imports and registers subsequent modules which contain our components:

  • Content from /content/content.js
  • Header from /header/header.js
  • Footer from /footer/footer.js

Finally it creates application instance and mounts it into <main> tag inside index.html file.

Components

With the new version of the framework we can utilize the new functional programming model a.k.a. Composition API. Instead of data, computed and methods sections we will use the setup() function, which will wire up all the internals of the components. To ensure propagation of data to UI and reaction to changes, we will use reactive and computed wrappers provided by the Composition API.

Component code is structured as follows:

const template = `
  <div>
  ...
  </div>
`

export default {
  template,

  setup () {
  }
}

As an example, we present footer component which displays some text on the left and a ticking clock on the right:

const { reactive, computed } = Vue

const template = `
  <footer>
    <div class="left">
      <slot></slot>
    </div>
    <div class="middle">
    </div>
    <div class="right">
      Current time: <b>{{ state.nowString }}</b>
    </div>
  </footer>
`

export default {
  template,

  setup () {
    const state = reactive({
      now: new Date(),
      nowString: computed(() => state.now.toTimeString().substr(0, 8))
    })

    window.setInterval(() => {
      state.now = new Date()
    }, 1000)

    return { state }
  }
}

The main application component is in the index.js file. Its task is to assign custom HTML tags such as <app-header> or <app-footer> to all our components.

import Header from './header/header.js'
import Content from './content/content.js'
import Footer from './footer/footer.js'

const { createApp } = Vue

const App = createApp({
  components: {
    'app-header': Header,
    'app-content': Content,
    'app-footer': Footer
  }
}

window.addEventListener('load', () => {
  App.mount('main')
})

These custom tags are then used to build our application UI in index.html file. We ended up with a UI which is trivially simple to read:

<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>Minimalistic Vue 3</title>
  <link rel="stylesheet" href="index.css">
  <link rel="stylesheet" href="header/header.css">
  <link rel="stylesheet" href="content/content.css">
  <link rel="stylesheet" href="footer/footer.css">
  <script src="https://unpkg.com/[email protected]"></script>
  <script src="index.js" type="module"></script>
</head>

<body>
  <main>
    <app-header bg-color="#c5cae2">
    </app-header>

    <app-content>
    </app-content>

    <app-footer>
      (c) Tomasz Waraksa, Dublin, Ireland
    </app-footer>
  </main>
</body>

</html>

Summary

In the end, we have nearly the full power of Vue 3 including the awesome Composition API, all without any complexities of a build process. To deploy this application we would simply copy the files to a web server.

References

The article is also available on my blog Let’s Debug It.

The complete source code can be found at https://bitbucket.org/letsdebugit/minimalistic-vue-3. Feel free to clone and reuse this code. Any suggestions or questions are most welcome!

All credits and thanks go to the creators of the awesome Vue JS framework.

LICENSE

Copyright 2020, Tomasz Waraksa

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.