DEV Community

Arswaw
Arswaw

Posted on • Edited on

Use Vue to create a SPA without any Node modules

In this guide I will show you to create a static single-page application with VueJS and ES6 Modules.

A friend of mine was trying to use AWS Cloud9 to build his SPA, but he found working with Node to be cumbersome due to the way Cloud9 works. I had designed a way to build a complex web application without using Node at all while at work. I passed the knowledge on to him and he took to it.

The idea is that you can build a "static-first" web application with optional build tooling later if you wish.

Rather than using Node's module system, you can use the one that's built into JavaScript. This module system shipped in version 6.

This allows you to send your files to the browser exactly as they are. There is no setup. You can clone a git repository directly to /var/www/html on Apache and start developing.

You can use Vanilla JavaScript, but I've found Vue.js does the heavy lifting that I'd have to do anyway in a moderately complex app.

You will need a server to host your static files. I recommend fenix.

You will need to use a browser that supports ES6, such as Opera.

You can see the final code here.

I have encountered problems with Edge when using this methodology, but Rollup.js has been very useful when preparing the app to work cross-browser.

I am in the process of building a CLI that will automate these steps.

Step 1 - Creating your index.html file.

For the most part, your index.html file will remain untouched as most of your work will be done in JavaScript.

  1. Create a project folder with a name of your choosing. Serve it from whatever static fileserver you wish.
  2. Inside the project folder, create an index.html file.
  3. Add html, head, and body tags, then include this line of code between your body tags:
<script type="module" src="main.js">
Enter fullscreen mode Exit fullscreen mode

You can optionally include 'crossorigin' if you run into a 499 error in the console. There is more information in this forum post.

  1. Above the line of code you just wrote, add the following:
<div id="app"></div>
Enter fullscreen mode Exit fullscreen mode

You can call the id whatever you want, as long as it matches with the Vue instance we're about to create.

Step 2 - App entry point, and Vue integration.

Vue can be imported as an ES6 module. All components will be able to make use of it.

You should be in a directory that a single file, which is the index.html file you just created.

  1. Create a main.js file.
  2. Create a vue.js file.
  3. Go to this cdn and select vue.esm.browser.js
  4. Copy and paste the JavaScript code into the vue.js file you just created in your project.
  5. Go to main.js and enter the following code:
import Vue from './vue.js'
Enter fullscreen mode Exit fullscreen mode

Alternatively, you can do this:

import Vue from 'https://cdn.jsdelivr.net/npm/vue@latest/dist/vue.esm.browser.min.js'
Enter fullscreen mode Exit fullscreen mode

Thanks to Mohamed Safouan Besrour on Github for the suggestion and Pull Request!

  1. Immediately after this line, add the Vue instance:
new Vue({
  el: '#app', // This should be the same as your <div id=""> from earlier.
  components: {
    'navbar': Navbar
  },
  template: MainTemplate
})
Enter fullscreen mode Exit fullscreen mode

We've referenced two external files, one component, and one template. We will be importing both. The 'navbar' component has its own template, which it will import on its own, without it having to be imported into main.js

This is important as we want to practice separation of concerns within our componentized app.

Step 3 - Adding templates.

For the apps I have built with this methodology, I have kept all templates in a separate folder structure that mirrors the component folder structure. You can change this around if you want. There is no reason why you can't give each component its own folder with template, and .js file. This is similar to the approach taken by Angular.

  1. Create a templates directory. This should be the only subfolder in your application directory.
  2. Create a file called main-template.js
  3. Add the following code:
// Note that these are backticks.

const MainTemplate = `
    <div>
    <navbar></navbar>
    All content will appear below the horizontal line.
    <hr>
    </div>
`

export { MainTemplate }
Enter fullscreen mode Exit fullscreen mode
  1. In the templates folder, create a navbar-template.js file.
  2. Add the following code:
const NavbarTemplate = `<nav>

<a href="#/">Home</a>
<a href="#/about">About</a>

</nav>`

export { NavbarTemplate }
Enter fullscreen mode Exit fullscreen mode

We have finished creating our templates.

Step 4 - Adding components.

We need a navbar component to attach our template to.

  1. In the root directory of your project, create a 'components' directory.
  2. Create a navbar.js file.
  3. Add the following code:
import { NavbarTemplate } from '../templates/navbar-template.js'

const Navbar = {
  template: NavbarTemplate,
}

export { Navbar }
Enter fullscreen mode Exit fullscreen mode
  1. Return to main.js

Step 5 - Importing our components.

We are almost ready to view the first version of our web application.

  1. In main.js, add the following code between the Vue import, and the Vue instantiation:
import {
  Navbar
} from './components/navbar.js'

import {
  MainTemplate
} from './templates/main-template.js'
Enter fullscreen mode Exit fullscreen mode
  1. Save the file and view your web application in your browser. The URL will depend on your server settings.

We have a web application that can optionally be turned into a SPA. We will do this now.

Step 6 - Adding routing.

We need to import Vue Router. This is optional, but again it does much of the heavy lifting for you when it comes to routing.

  1. Navigate to the vue-router CDN. There doesn't appear to be an ES6 Modules compatible version, so we'll import as CDN.
  2. Copy the link, and add it as a dependency in index.html above the module import:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.js"></script>
Enter fullscreen mode Exit fullscreen mode
  1. Return to main.js and add the following code:
Vue.use(VueRouter)

const router = new VueRouter({
  routes: [{
    path: '/about',
    component: About,
    name: "About Us Page"
  }]
})
Enter fullscreen mode Exit fullscreen mode
  1. In the Vue instance add 'router' above main template:
router,
template: MainTemplate
Enter fullscreen mode Exit fullscreen mode
  1. Create an about template, an about component, and then import the component into main.js
  2. Underneath the hr tag in main-template.js, add:
<router-view></router-view>
Enter fullscreen mode Exit fullscreen mode
  1. Look at your app home page, and then use the navbar to route to the about page.

Add new components and templates to expand your app.

Check the console. If you see any errors, or the app is not rendering the way you expected, check that you followed the steps correctly. If it still does not work, leave a comment below the post.

The main point of this methodology is to show that you don't necessarily need to setup a complex build environment with Node in order to develop a SPA. I believe that this type of development will become more sustainable as module developers release ES6-compatible versions of their software.

A future blog post will focus on using Rollup.js to package this type of app, and setting up CI/CD.

I found another bug with the V2 editor. It causes the numbering to reset after a code block. Notice how my numbers are now 1. after every code block is closed. I will reach out to DEV on Twitter concerning the bug.

I hope this helps anyone who was hoping to build a complex web application with just HTML, CSS, and JavaScript.

Thank you.

Oldest comments (72)

Collapse
 
priteshusadadiya profile image
Pritesh Usadadiya

this is pure gold. I was just looking for something like this.

Collapse
 
arswaw profile image
Arswaw

Thank you for the appreciation!

Collapse
 
dtrillo profile image
David Trillo

Thank you for the solution, when NodeJS is not available.

Collapse
 
limweb profile image
Thongchai Lim (样生海) • Edited

after dev parcel main.js bundle to minifile it works

my sample vuevm.shopsthai.com

Collapse
 
arswaw profile image
Arswaw

What is that sample?

Collapse
 
mahmudul95 profile image
Mahmudul Hasan

Sir,
I see your sample "vuevm.shopsthai.com", its awesome,
Can you share the code of your sample, Please ......!!!

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
arswaw profile image
Arswaw

Vue is just code loaded into a .js file in my example. What I mean is there is no node_modules folder or any dependence on Node at all.

Collapse
 
nssimeonov profile image
Templar++

Can you share this code as a github repo?

Collapse
 
arswaw profile image
Arswaw • Edited

Good idea. I will work on this tomorrow.

Collapse
 
arswaw profile image
Arswaw

It is now hosted here.

Collapse
 
nssimeonov profile image
Templar++

Out of curiosity - why are you loading the router like this:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.js"></script>

but not vue.js too?

Thread Thread
 
arswaw profile image
Arswaw • Edited

Because the developers don't include an ES6 compatible version of the router. Only Vue.

EDIT: Now they do.

Collapse
 
josepadron712 profile image
José Padrón

Nice article

Collapse
 
pablocamelcase profile image
Pablo Espinosa • Edited

This is amazing, thanks a lot for it.
Just a question, how would you add styles/css to the independent components? 🤓

Collapse
 
arswaw profile image
Arswaw • Edited

That's a really good question. For now I've just been using global styles and then applying specific classes to the template files. An example:


<div class="specific-component-class">

This class is only used for this component, but is stored in a global file like style.css

CSS Modules might be the key, if we can use them without Node.js

Collapse
 
pablocamelcase profile image
Pablo Espinosa

Hey
I've found out that you can use scoped CSS to solve that issue. And works flawlessly.
vue-loader.vuejs.org/guide/scoped-...

Collapse
 
arswaw profile image
Arswaw

I was recently informed by Jay that you can use Goober CSS as a lightweight ES6-compatible way to add scoped CSS to each component while still avoiding Node.js!

Here's an example that Jay made.

plnkr.co/edit/tjhkcfNO15aTNhsU

Collapse
 
belcross090 profile image
Carlos Ernesto

Great! Thanks a lot it is very very helpful! Can you explain how to install Vue CLI without any package manager? Is that even possible?

Thanks in advance.

Collapse
 
arswaw profile image
Arswaw

I wouldn't bet on it. I will look into it for you, but I will probably end up having to finish a lightweight CLI for non-Node environments.

Collapse
 
belcross090 profile image
Carlos Ernesto • Edited

Your lightweight CLI for non-Node environments will have to be installed with any package manager? About look for if it's possible to install Vue CLI without any package manager, I'm sorry I don't want to waste your time, I just ask because I have googled about installing Vue CLI but everything I've found it's using package managers. My problem with package managers is that I've installed Node (and Yarn) but when I try to install any package I always get errors about SSL wrong versions or other kind. I also tried to find how to fix this but none of the 'solutions' I find works for me. *And I want to jump directly into learn how to develop using Vue or use other frameworks in my projects without becoming an expert in package managers.

Thread Thread
 
arswaw profile image
Arswaw

I would make it independent of a package manager if I could.

It's unfortunate that you're having so much trouble with NPM. Are you using Windows? Try running command prompt in administrator mode.

You can use the methodology in my article to jump right into Vue development.

Collapse
 
arswaw profile image
Arswaw

I see that you are right! I don't know why I didn't notice your comment before.

I added the fix. Thank you!

Collapse
 
eric_dolecki profile image
 Eric E. Dolecki

Quick question. So I can create CSS that isn't SCSS (and scoped to each component). That's very workable. However, how can I assign properties, data, methods, etc. to my components when they are .js files (.vue can include these things, but I'm trying to avoid npm as your solution does).

Collapse
 
arswaw profile image
Arswaw

I'm glad you have your CSS down.

You are able to use anything you expect in the .js file that you could do with any Vue component.

If you find something that doesn't work, I would like to know.

I've tested this extensively. I've put watchers, computed, event listeners, and child components.

Does that answer your question?

Collapse
 
eric_dolecki profile image
 Eric E. Dolecki

Can you paste in an example of the contents of a simple component implementation that has data like an array and property associated with it? In your example stuff there is const with HTML and then an export, but looking for the syntax that's more like what's in a Vue file

Thread Thread
 
arswaw profile image
Arswaw

A very large example from a personal project:

github.com/arswaw/happyweather/blo...

Another example with props and child components:

github.com/arswaw/happyweather/blo...

I even have an example of mixin use. I will have to find it.

Thread Thread
 
eric_dolecki profile image
 Eric E. Dolecki

Yes, that's perfect! Thank you!!

Some comments may only be visible to logged-in visitors. Sign in to view all comments.