Creating a Vue.js app using CDNs for Vue 3 and Vuex 4 (plus Node.js)

Lil Devvie
9 min readMar 13, 2023

--

Here is a simple Vue 3 app using a CDN (content delivery network). All it means is that you don’t have to install the Vue CLI (command line interface) to learn Vue, so it’s a good starting point to see if you like how it works.

# 1. The Vue intro

Vue is incredibly useful in writing clean and readable code. It works by extending the HTML, allowing you to place syntax that describes the data or actions within the same context.

Take this for example:

<!-- this is the same code as the image below,
but the dark background seems more readable-->
<div class="ml-2 test rounded-xl mt-10 mx-5 grid gap-3 grid-flow-row grid-cols-3 row-end-auto">
<div v-for="item in items" @click="testMethod" >{{item.text}}</div>
<div @click="boop"> Hi, click here for the boop </div>
</div>
Screenshot of a vue example div element

This div element uses Tailwind CSS classes but ignoring that, it contains a div using v-for, meaning it will show multiple divs per item in the data, like a for loop. It then renders this text within the data through item.text. This saves a bunch of duplicate code, but I find it easier to read than other frameworks. It compartmentalises the component from the data, so you can just focus on one part of the problem. This makes debugging a lot easier.

# 2.1 Node Intro

If you’ve already used node before, you can skip this section. Node is used to run your app and start the server to host your website. This example will be local. You can download it here https://nodejs.org/en/ with the recommended install. Follow the instructions in the installer (you may need to restart your computer afterwards).

Open up your terminal. Then type in node -v
to check it has installed. It should return your version number. Now you can create a folder. If you are in “C:/User/Documents’ and you want to create a folder here called testVue, you just need to type cd testVue
or to go further in another folder e.g. Projects, you can type cd Projects/testVue . If you need to go backwards, type cd ..
Now type npm init

You just need to enter a name for your app and then keep pressing enter. This initializes your package, where you can download modules (that are like helper functions). Finally type npm i express (i for install) and when fnished type npm i cors

# 2.2 Node index.js

Express allows you to send data back and forth from the server and saves the data if needed. This example just contains a simple GET request to get the contents of the public folder, which can be accessed in your browser at localhost:3000, but only when you run the server. To run the server you need to type (at the file location of index.js), npm run dev


const express = require('express');
const app = express();
const port = 3000;

const cors = require('cors');

app.use(express.static('./public'));
app.get('/', ( res) => {
res.send();
})

app.listen(port, () => {
console.log(`Example listening on port ${port}`);
})
Screenshot of index.js file

# 3 Folder structure

Here is the folder structure of the vue app.

public
> components
— test.js
> scripts
— main.js
> store
— store.js
index.html

structure of app

All the names in italics are folders. The test.js component exists inside the components folder, and the components folder exists inside the public folder. This is structured this way with consideration for growth. If the number of files you have grows unexpectedly, it’s much easier to find them when they’re appropriately filed.

# 4.1 The script tags of the HTML file

Here are the scripts you can copy right into a HTML file. This uses Tailwind but you don’t need to include this if you don’t want to. There is also a main.js script file to import the components as well as the store.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Test vue 3 app </title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://unpkg.com/vuex@4.0.0/dist/vuex.global.js"></script>
<script src="./scripts/main.js" type="module"></script>
</head>

# 4.2 The rest of the HTML and the body

You need to append this to the end of the HTML file you copied earlier. The important thing here is the parent div with the ID of “app” in order to get your project working. Then you can use event handling like “@click” to run your methods. This example uses the method boop and testMethod stored inside main.js.

    <body>
<div class="mt-5" id="app">
<div class="ml-2 test rounded-xl mt-10 mx-5 grid gap-3 grid-flow-row grid-cols-3 row-end-auto ">
<div>test 1 abcdefg skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf skdfjnadkfjanf</div>
<div>test 2</div>
<div>test 3</div>
<div>test 4</div>
<div>test 5</div>
<div>test 6</div>
<div>test 7</div>
<div>test 8</div>
<div>test 9</div>
<div>test 10</div>
<div v-for="item in items" @click="testMethod" >{{item.text}}</div>
<div @click="boop"> Hi, click here for the boop </div>
</div>
<test abc="This string is parsed from the index page" :storename="name"></test>
</div>

<style>
.test {
-moz-box-shadow: 4px 0px 30px 0px rgba(176,173,176,0.54);
box-shadow: 4px 0px 30px 0px rgba(176,173,176,0.54);
}
main :last-of-type {
-moz-box-shadow: 4px 0px 30px 0px rgba(176,173,176,0.54);
box-shadow: 4px 0px 30px 0px rgba(176,173,176,0.54);
}
</style>
</body>
</html>

Do you see all the 10 div elements? You now can loop them with v-for! It’s why the vue loop is so useful. You can parse the index inside the v-for v-for(item, index) in items and have {{index}} {{item.text}}

Notice the component test at the end of the main div? It parses in two props; abc with a string, and storename with the parsed variable ‘name’. Skip here if you want to see how it’s used, section 5 — using a component.

# 5. Using Vue with Vuex

Vuex is a way to manage the data. It isn’t needed, but it is incredibly useful alongside Vue in large applications. You can also use Pinia, but there is so much documentation with Vuex. The idea behind Vuex is that it’s a single source of truth; a reliable store of data that can’t be mutated unexpectedly.

export const store = new Vuex.Store({
state () {
return {
test: 0,
name: '',
}
},
mutations: {
increment(state) {
state.test++;
},
setName(state, payload) {
state.name = payload;
}
},
actions: {
pretendUpdate({state, commit}) { //can use state, commmit and dispatch
commit('increment');
console.log('pretend update', state.test);
},
}
});

Vuex is used to store information when navigating through different pages. You can also have it persist on refresh using localStorage, but we won’t be using it in this example.

The current store above is split into 3 sections;
state, mutations and actions.
The state is like declaring the data you want to store, whereas the mutations are used to update that data. Actions are just methods, where you can update the data or call other methods inside them.

In the action pretendUpdate(), you can see it uses state and commit inside the brackets {}, where state is used to get the variable, whereas commit is used to update the data. You can also use parameters with actions too. It has to be outside of the brackets (like val in the example below — note, you will have to edit the mutations so it parses in the payload, like setName()).

pretendUpdate({state, commit}, val) {
commit('increment', val); //using the mutation 'increment' to update test
}

You can use actions for all your fetch requests. Storing fetched data here instead of the pages or the components keeps your component methods separated clearly. I find it so much easier to debug this way.

# 6. Components

When using a CDN you have to use template literals to contain your HTML code. It isn’t the easiest to read, but it is great that you can use separate file components while creating your own CDN application.

const test = {
template:
`
<div class="ml-8 border-4 mr-8 pb-2 pl-2 rounded-lg border-green-200 hover:bg-blue-50" >Test template
<div class="bg-green-200 mr-3" @click="testClick">{{testData}}</div>
<div>{{abc}}</div>

<label for="testInput">Type your name:</label>

<!-- this input below is really important -->
<input class="ml-2 bg-gray-100 hover:bg-white" type="text" id="testInput" name="testInput"
:value="storename" @input="event => this.$store.commit('setName', event.target.value)"
>

<button class="block ml-2 mt-10 p-4 bg-green-200" type="button" @click="submitClick()">Click here to submit</button>
</div>
`,
props: {
abc: {
type: String,
required: true,
},
storename: {
type: String,
required: false,
}
},
data() {
return {
testData: 'Hellooo',
}
},
methods: {
testClick() {
console.log('this is a test click from component', this.$store.state.test);
this.$store.dispatch('pretendUpdate');
},
submitClick() {
console.log('Name in store', this.$store.state.name);
}
},
}
export default test;

The images of the above code is split into 2 sections. The first is the template and the second is the rest of the component features. I’ve called this component test.

Screenshot of the test component template
Rest of the test component
How the component looks in the browser

The test template has the ‘Helloo’ string from the data variable called testData. The next div is parsed from the HTML at abc in Section #4.2. The important part is the prop called storeName. On load the name ‘Jade’ is already in the input as it was set inside the store. This can be updated.

@input=”event => this.$store.commit(‘setName’, event.target.value)”

The above line uses the mutation set in the store to update the element when a user inputs their information. The store is updated without having to create an action or a method whenever the user types in the input box. When you press submit, it logs the data to show the store value with the updated string.

If you wanted, you could create a method here that uses an action in the store to update the database with a POST request.

# 7. Main.js

The final part of the app is the main.js file; the file that sets up your components with vue as well as your store.

import Test from '../components/test.js';

import { store } from '../store/store.js';

const { createApp } = Vue;

createApp({
data() {
return {
test: 'hihihihi'
}
},
computed: {
items() {
return this.$store.state.items;
},
name() {
return this.$store.state.name;
}
},
methods: {
testMethod() {
console.log('test', this.$store.state.test);
this.$store.dispatch('pretendUpdate');
},
boop() {
console.log('booop');
console.log('test', this.test);
},
}
,

})
.component('test', Test)
.use(store)
.mount("#app");
screenshot of the main.js file

The methods here are probably best suited for those that are used across multiple pages, but it’s all here just for example. The boop method uses data stored here instead of the Vuex store, so it will not persist as you navigate through different pages.

When importing your components and your store, make sure to check the structure of your application is the same here at Section #3 to make sure the file can be found. The components and the store need to be chained onto createApp and mounted to the #app div.

This is all you need to create your own app with Vue and Vuex!
Let me know if you’ve previously used Vue 2, or you just wanted to pick up Vue. Is there anything I’ve missed? Let me know 😄

--

--