Content
Introduction
In this article, I'm going to present you step by step what tools I use.
You can follow along, but it's more important to understand "why I am doing this" rather than "what I am doing".
A good advice is, try to do the same step alongside me in this tutorial. Then, try to change a few bigger and bigger things. Finally, at the end, you should be able to do everything again on your own.
You can find all the produced code over at the Github repository.
Disclaimer
First of all, and this is really important, all of this is my own bias opinion on development. We all have our unique way at looking at things.
Web development is a huge and complex topic. This post is not meant to describe the easiest or quickest methods.
However, this is the methods I grew up preferring (for reasons I'll get to), and the one I'm most capable of explaining in details.
From here, I assume you have basic Javascript and Vue understanding. I'm also not going to detail how to install Node.js and how to use NPM.
Languages
With that out of the way, let's start with languages.
I have worked with Javascript for about 10 years. It has a lot of detractors, but it was and still is the language I enjoy the most.
It's easy to use, has one of the largest community and can power huge application.
Of course, I'm also writing everything in English. Although it's not my mother tongue, it's recognize as the international language.
Installation
Node.js is installed on my computed, so I'll use NPM to install all my JS dependencies.
The first thing I always do when starting a new project is
$ npm init
This will create the package.json
file.
Then I manually create a readme.md
and .gitignore
file as well as a src
directory that will be useful later.
Vue
I like Vue and that's what I mostly use. The installation is straightforward
$ npm install vue
Bundler
I like the modular template syntaxe that Vue offer. However, this is not native JS that a browser can understand.
So, it needs to be transformed before it can be used.
I use Webpack for that. The installation is not as simple because we need a lot more modules.
First, let's start with Webpack itself and its CLI interface
$ npm install webpack webpack-cli
Then, I need to add the plugin that handle Vue files with its compiler
$ npm install vue-loader vue-template-compiler
Finally, chances are that I'm going to write CSS, so I need another pair of plugins to handle CSS code
$ npm install css-loader style-loader
Now, I need to configure Webpack. This is the least fun part, but we need to understand this step to solve possible future issues.
Webpack can be configured with a file named webpack.config.js
, so let's create it.
Here is the bare minimum. We'll come back later if we need to expand it.
// Get the vue-loader plugin
const VueLoaderPlugin = require("vue-loader/lib/plugin");
// This is what the file exports
module.exports = {
// My entry point
entry: "./src/index.js",
module: {
rules: [
// All Vue files use the vue-loader
{
test: /\.vue$/,
loader: "vue-loader",
},
// All CSS files use css than style loaders
{
test: /\.css$/,
use: [
"style-loader",
"css-loader"
]
},
],
},
plugins: [
// Register the vue-loader plugin
new VueLoaderPlugin(),
],
};
With all that out of the way, I just need to run in my terminal
$ webpack
to see my project being entirely compacted and minified. This will fail for now, don't worry.
Optionals
These tools are out of scope for this article. Maybe I'll go in more details in the next one.
I always use Eslint to check for potential mistakes in my code.
In order to use it with my personal configuration I run
$ npm install eslint eslint-plugin-vue @gmartigny/eslint-config
I try to test my code to catch regression and be sure that I cover most use cases. I use AVA for the test and NYC for the code coverage.
$ npm install ava nyc
Development
That's already a lot of steps, and I haven't even write a single line of code. All of that looks like a lot, but trust me, it will make you go faster in the future.
The most attentives around you would remember that in my Webpack configuration, the entry file was ./src/index.js
. So, let's start there.
I create an index.js
file in src
and add a few lines of code to call Vue (with ESM).
// Import Vue, I prefer the ESM syntaxe
import Vue from "vue/dist/vue.esm.js";
// Create a new Vue instance targeted at the element with the id "app"
new Vue({
el: "#app",
});
With this bare-bones JS file, I can safely run
$ webpack --mode=development --watch
to trigger Webpack in development mode (slower but more descriptive on errors) with watch (will rebuild every time I change the code).
This will create a new main.js
file within a dist
directory. It's the file that my final users will use.
I now create a index.html
file (usually in a public
directory, but it doesn't matter).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<!-- My target element -->
<main id="app"></main>
<!-- The JS file from webpack -->
<script src="../dist/main.js"></script>
</body>
</html>
Opening this file in your browser will show nothing as expected, but this is all working. This is the state of my project so far.
Adding views and components
Your Vue files should be split between views (an individual screen, eg: Menu, About ...) and components (composing your views, eg: Button, Footer ...)
Both works the same, but don't have the same concerns. So let's add two directories (views
and components
) in src
to sort them out.
Views
Let's begin by creating a new view. This is going to be the homepage, so I'll call the file Home.vue
.
I used a capital letter in the file name to show that it's a class as in other OOP language like Java.
<template>
<h1>Home</h1>
</template>
<script>
export default {
name: "Home",
};
</script>
In order to go into that view, I have to tell my Vue instance to render it. In the index.js
file, I'll add the necessary lines.
import Vue from "vue/dist/vue.esm.js";
// Import the view
import Home from "./views/Home.vue";
new Vue({
el: "#app",
// Declare it as a components I'll use (I know, views are treated as components by Vue)
components: {
Home,
},
// Render the view
template: "<Home/>",
});
In order to have more views, you need navigation between the views, so you need vue-router
. We're not going to talk about it for now.
Components
Imagine I want to have a simple card (title + text) for each film I want to see, I don't want to duplicate the code for each cards. A good rule is DRY (Don't Repeat Yourself).
If you write something more than twice, it should be factorized in one place.
Again, I create a new file called Film.vue
in the components
directory.
<template>
<div class="film">
<h2>Title</h2>
<p>Text</p>
</div>
</template>
<script>
export default {
name: "Film",
};
</script>
<!-- scoped because I don't want to interfere with any other component -->
<style scoped>
.film {
border: 1px solid blue;
}
</style>
And use it in Home.vue
.
<template>
<div>
<!-- Use the component -->
<Film />
<Film />
<Film />
</div>
</template>
<script>
// Import the component
import Film from "../components/Film.vue";
export default {
name: "Home",
components: {
// Declare the component
Film,
},
};
</script>
As you should already see, I have 3 cards with the same title and text.
Which is not what I want to do.
If I add properties to my card component and write data in my home view, it will allow me to define value for each individual card.
<template>
<div class="film">
<!-- Use properties here -->
<h2>{{ title }}</h2>
<p>{{ text }}</p>
</div>
</template>
<script>
export default {
name: "Film",
// Properties list declaration
props: ["title", "text"],
};
</script>
<style scoped>
.film {
border: 1px solid blue;
}
</style>
<template>
<div>
<!-- Loop through my data -->
<Film v-for="(film, index) in films" :key="index"
:title="film.title" :text="film.text"/>
</div>
</template>
<script>
import Film from "../components/Film.vue";
export default {
name: "Home",
components: {
Film,
},
// data should be a function
data () {
// that return a set of values
return {
films: [
{
title: "Alien",
text: "It follows the crew of the commercial space tug Nostromo, who encounter the eponymous Alien, an aggressive and deadly extraterrestrial set loose on the ship.",
},
{
title: "Interstellar",
text: "In a dystopian future where humanity is struggling to survive, it follows a group of astronauts who travel through a wormhole near Saturn in search of a new home for mankind.",
},
{
title: "Reservoir Dogs",
text: "Diamond thieves whose planned heist of a jewelry store goes terribly wrong.",
},
],
};
},
};
</script>
With that in place, any changes applied to my data will be reflected on screen.
Dynamic page
I can, for example, fetch data from an API or allow the user to edit the page (or both 😉).
Fetch from API
First, I'll fetch my data from a mock API online. In order to do that, I start by emptying the data array.
Then, according to the Vue lifecycle, I can use mounted
function to execute code when the view appears on screen.
<template>
<!-- ... -->
</template>
<script>
import Film from "../components/Film.vue";
export default {
name: "Home",
components: {
Film,
},
data () {
return {
// Emtpy film list
films: [],
};
},
async mounted () {
// Fetch from mock API
const response = await fetch("https://mock-film-api-t0jk5mabvwnt.runkit.sh/");
if (response.ok) {
// Load result into films list
this.films = await response.json();
}
},
};
</script>
User editing
In the same way, I can allow users to add new film to the list. A small HTML form that push a new entry when submitted will see the modifications reflected on the view.
<template>
<v-app>
<Film v-for="(film, index) in films" :key="index"
:title="film.title" :text="film.text"/>
<!-- Form that will call addFilm when submitted -->
<form @submit="addFilm">
<div>
<label for="title">Title</label>
<!-- v-model link the input value to a variable -->
<input type="text" v-model="inputTitle" id="title">
</div>
<div>
<label for="text">Text</label>
<input type="text" v-model="inputText" id="text">
</div>
<button type="submit">Add</button>
</form>
</v-app>
</template>
<script>
import Film from "../components/Film.vue";
export default {
name: "Home",
components: {
Film,
},
data () {
return {
films: [],
// Holds the value of each input
inputTitle: "",
inputText: "",
};
},
async mounted () {
// ...
},
methods: {
// New method
addFilm (event) {
// Stop the form from reloading the page (default behavior)
event.preventDefault();
// Add a new film to the list
this.films.push({
title: this.inputTitle,
text: this.inputText,
});
// Clear out input fields
this.inputTitle = "";
this.inputText = "";
},
},
};
</script>
This will of course not save anything online, and changes made will be lost when the page is reloaded.
You could improve this example by sending a request to a server that save the inputs in a database.
Component libraries
I'm lazy. Being an efficient developer often means being lazy.
Instead of creating all my components, I can use already existing libraries of components. That way, I can focus more on content instead of how to correctly design a datepicker.
Since I use Vue, I choose a Vue compatible library, Vuetify.
npm install vuetify
Really few changes are needed to activate it in index.js
.
import Vue from "vue/dist/vue.esm.js";
// Get Vuetify and its CSS
import Vuetify from "vuetify";
import "vuetify/dist/vuetify.min.css";
import Home from "./views/Home.vue";
// Prepare the usage of vuetify
Vue.use(Vuetify);
const vuetify = new Vuetify();
new Vue({
// Pass the instance to Vue
vuetify,
el: "#app",
components: {
Home,
},
template: "<Home/>",
});
Then I can use it everywhere in my application (here in Film.vue
).
<template>
<!-- All Vuetify components are prefixed with "v-" -->
<v-col cols="12">
<v-card shaped>
<v-card-title>{{ title }}</v-card-title>
<v-card-text>{{ text }}</v-card-text>
</v-card>
</v-col>
</template>
<script>
// ...
</script>
<!-- I don't need my crappy style anymore -->
Deployment
One of my favorite recent discovery is serverless. Basically, as long as your application is stateless (always return the same result with the same parameters), you don't need to have a complex, always running server. By leveraging the power of caching and ressource sharing you can reduce your server to almost nothing.
Using Vercel, I'm able to freely host, deploy and serve with a few clicks. All I need is for the project to be on Github.
Troubleshooting
You are using the runtime-only build of Vue where the template compiler is not available.
Your import of Vue is wrong. If you remember, there are many ways to import Vue. By default, import "vue"
will call the vue.runtime.common.js
file.
In my code here, I'm using the ESM with template (so I need the vue.esm.js
).
[Vuetify] Multiple instances of Vue detected / this.$vuetify is undefined
Your application and Vuetify didn't import the "same" Vue. As explain above, it's important to import the right Vue for your usage.
A nice solution to this is to create an alias in webpack.
// In webpack.config.js
module.exports = {
// This will tell all your code to use the same Vue.
resolve: {
alias: {
vue$: "vue/dist/vue.esm.js",
},
},
// ...
};
FAQ
Why do you don't use CLI to setup your app ? (like
vue-cli
orcreate-react-app
)
While these CLI are great ways to quickstart a project, they slow you down in the long run. They all use the same technologies I presented you today, but in a complex and confusing way.
Using create-react-app
install about 2000 packages. If something goes wrong, debugging that much code is not an easy task.
I've always preferred taking the longer road, but at the end of the day, understand what's going on.
Why don't you need to import each Vuetify components when you use them ?
When I do Vue.use(Vuetify);
in the index.js
, it activates it in the whole project.
It's possible to import only Vuetify components when you use them. But this requires a bit more work that is out of scope for this tutorial.
Why don't you use X instead of Y ?
I'm used to it. I'm sure you'll find better alternative to any tools or methods I describe above. But I know them.
At the end of the day, it's more important to deliver than endlessly learn new technologies.
What are my alternatives ?
Vue:
- React
- Angular
- Svelte
Vuetify:
- Material-UI
- Any CSS frameworks:
- Bootstrap
- Bulma
- Tailwind
Webpack:
- Rollup
- Skypack
Vercel:
- Netlify
- Heroku
Top comments (5)
Didn't plan on reading this because I don't do frontend, but somehow I got sucked in.😅 This is a really great post on how to get from scratch to app. Nice! Made Webpack and co feel less intimidating.
Also, Vue is awesome.🤘
Thanks for the kind words, glad you liked it.
Why do you use Vue?
For my personal taste, Vue is the best front-end framework on the market. The template component syntaxe, the two-ways variable binding, the great documentation, the OOP style, the ease of installation and use ...
Acctally Im happy to hear that, as a Vue developer.partytimes.herokuapp.com/#/
this is my last project.