We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
2018 / 03 / 10
2020 / 04 / 09
Quickstart guide for a new Vue.js project
An awesome way to start a brand new application
Opinions
In the time I have been delving into Vue.js I’ve come to really appreciate the framework, and its surrounding libraries.
This opinionated guide details the steps I take to start with a solid foundation for a new Vue.js project.
What particular opinions are you talking about? —you say
Glad you asked, well, for starters:
CLI tools
- Package manager: Yarn — Fast, reliable, and secure dependency management.
- Project generation tool: vue-cli — CLI for rapid Vue.js development.
UI
- UI CSS framework: TailwindCSS — A utility-first CSS framework for rapidly building custom designs.
- UI component framework: Vuetify — Material Design component framework.
- Material icons library: Material Design Icons — 4000+ Material Design Icons from the Community.
- Data visualization library: D3 — A JavaScript library for visualizing data using web standards.
Utility libraries
- HTTP client: Axios — Promise based HTTP client for the browser and Node.js.
-
Utility library: Lodash — A modern JavaScript utility library.
A good alternative could be Ramda. - State management pattern + library: Vuex — Centralized state management for Vue.js.
-
Date library: date-fns — Modern JavaScript date utility library.
Alternatives in this space: Moment.js, Luxon, Day.js.
Take a look at this: you don’t need momentjs.
Template and preprocessor languages
- HTML template engine: Pug — A robust, elegant, feature rich template engine for Node.js.
- CSS preprocessor language: Sass — Sass is the most mature, stable, and powerful professional grade CSS extension language in the world.
Vue plugins
- Common filters: vue2-filters — A collection of standard filters for Vue.js.
- i18n support: vue-i18n — Internationalization plugin for Vue.js.
- Form validation: Vuelidate — Simple, lightweight model-based validation for Vue.js.
Browser developer tools
Last, but definitely not least:
- Browser DevTools: Vue.js devtools
Set up a new Vue.js app
Here we’ll see how to set up a newly created app with vue-cli so it’ll be ready for us to start hacking on it right away.
Prerequisites
Install Node.js, Yarn and vue-cli
Generate a new project
vue create my-vuejs-project
My usual preset looks like this:
Vue CLI v4.3.1
? Please pick a preset:
Manually select features
? Check the features needed for your project:
Babel, PWA, Router, Vuex, CSS Pre-processors, Linter / Formatter, Unit, E2E
? Use history mode for router?
(Requires proper server setup for index fallback in production):
No
? Pick a CSS pre-processor
(PostCSS, Autoprefixer and CSS Modules are supported by default):
Sass/SCSS (with dart-sass)
? Pick a linter / formatter config:
ESLint + Standard config
? Pick additional lint features:
(Press <space> to select, <a> to toggle all, <i> to invert selection):
Lint on save
? Pick a unit testing solution:
Jest
? Pick a E2E testing solution:
Cypress (Chrome only)
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.?
In dedicated config files
? Save this as a preset for future projects?
No
? Pick the package manager to use when installing dependencies:
Yarn
Install app dependencies
I like having the power of Sass at my disposal when writing CSS rules.
I also like to write my templates using Pug for simplified —easy to read— views.
Let’s add Pug to our devDependencies section in our package.json file:
yarn add --dev pug pug-plain-loader
Here are some other project dependencies that I always end up installing at one point or another when working on a Vue.js project:
yarn add axios d3 date-fns lodash-es vue-i18n vue2-filters vuelidate
Initial configuration
Adjust ESLint rules
I like using stricter ESLint rules for all my Vue.js code:
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -4,7 +4,7 @@ module.exports = {
node: true
},
extends: [
- 'plugin:vue/essential',
+ 'plugin:vue/recommended',
'@vue/standard'
],
parserOptions: {
@@ -12,7 +12,8 @@ module.exports = {
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
- 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+ 'no-multiple-empty-lines': [2, { max: 2 }]
},
overrides: [
{
The plugin:vue/recommended enforces the rules found in the Priority C Rules: Recommended section of the Official Vue.js style guide.
The no-multiple-empty-lines change allows me to leave two consecutive blank lines between some elements inside my .js and .vue files.
For example, for .js files, I leave two spaces between the importing section and the code that follows.
For .vue files, I leave two spaces between <template>
,
<script>
and <style>
sections.
Lint the project
Take this opportunity to run the linter and fix anything that pops up:
yarn lint
If, when trying to add the latest changes to Git you’re greeted by:
fatal: CRLF would be replaced by LF in src/plugins/vuetify.js.
Fix it by opening that file in VSCode and change the End of Line Sequence from CRLF to LF —you’ll find the control for that near the bottom right corner.
Testing
If you run the tests right now, they all should be OK:
yarn test:unit
yarn test:e2e
But as you saw, the last command opens up a Chrome browser window and expects you to drive the testing process.
That’s why we will create a new script to run e2e tests in headless mode.
Headless e2e tests
This could prove useful for CI / CD pipelines:
--- a/package.json
+++ b/package.json
@@ -7,6 +7,7 @@
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e",
+ "test:e2e:headless": "vue-cli-service test:e2e --headless",
"lint": "vue-cli-service lint"
},
"dependencies": {
Try it, execute the following command:
yarn test:e2e:headless
Set up plugins
Remember the dependencies we added above?
Well, to be used they need to be imported somehow into the app.
The best way to do it is to have a separate file for each one, then
import them on src/main.js
.
Setup vue2-filters
Add a src/plugins/vue2-filters.js
file:
import Vue from 'vue'
import Vue2Filters from 'vue2-filters'
Vue.use(Vue2Filters)
Setup vuelidate
Add a src/plugins/vuelidate.js
file:
import Vue from 'vue'
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)
Setup vue-i18n
Add a src/plugins/vue-i18n.js
file:
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
const messages = {
de: {
message: {
hello: 'hallo welt'
}
},
en: {
message: {
hello: 'hello world'
}
},
es: {
message: {
hello: 'hola mundo'
}
}
}
export default new VueI18n({
fallbackLocale: 'en',
locale: 'es',
messages
})
Enable the plugins
Finally, import the plugins on src/main.js
.
Note that in order to be able to use translations, we need to pass the i18n plugin as a reference when instantiating the Vue app:
--- a/src/main.js
+++ b/src/main.js
@@ -4,10 +4,16 @@ import './registerServiceWorker'
import router from './router'
import store from './store'
+import i18n from './plugins/vue-i18n'
+import './plugins/vue2-filters'
+import './plugins/vuelidate'
+
+
Vue.config.productionTip = false
new Vue({
router,
store,
+ i18n,
render: h => h(App)
}).$mount('#app')
To display translated text in the current locale just use the $t
function in a view like this:
<template lang="pug">
h1 {{ $t("message.hello") }}
</template>
The code above, along with the current configuration, would display:
<h1>hola mundo</h1>
Expose useful information in the console
It’s good practice to update your version in package.json
when
you are working on your app.
If you do, you’ll always be able to tell what version is deployed on that server just by visiting the browser console —believe me, it helps, a lot.
You could also show any other piece of information that you deem important.
I usually add this to any brand new src/main.js
:
--- a/src/main.js
+++ b/src/main.js
@@ -7,8 +7,14 @@ import store from './store'
import i18n from './plugins/vue-i18n'
import './plugins/vue2-filters'
import './plugins/vuelidate'
+import { version } from '../package.json'
+/* eslint-disable no-console */
+console.log(`App v${version}`)
+console.log(`locale:${i18n.locale} | fallbackLocale:${i18n.fallbackLocale}`)
+/* eslint-enable no-console */
+
Vue.config.productionTip = false
new Vue({
Which will output this to the console:
App v0.1.0
locale:es | fallbackLocale:en
Build for production
To build your app just type:
yarn build
You’ll see something along the lines of:
File Size Gzipped
dist/js/chunk-vendors.fb283e83.js 174.07 KiB 57.57 KiB
dist/js/app.de4c34bc.js 7.99 KiB 2.81 KiB
dist/service-worker.js 1.05 KiB 0.61 KiB
dist/precache-manifest.e3a02d9da053574 0.75 KiB 0.35 KiB
fe196c018482e818a.js
dist/js/about.95da692c.js 0.44 KiB 0.31 KiB
dist/css/app.2462baa1.css 0.42 KiB 0.26 KiB
Images and other types of assets omitted.
These and other files will be put inside the dist
directory.
You can try out your production build locally like this:
cd dist/
python -m http.server
Now visit http://localhost:8000
.
Deploying to a subdirectory
When building your app for production the compiler assumes that your app is going to be deployed to / —a root directory.
If that is not the case and you are deploying to /some-other-dir
then you need to create a new vue.config.js file in your app’s
root directory defining a publicPath
attribute like this:
module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/some-other-dir/'
: '/'
}
You can find more info about vue.config.js here.
Extras
Import Lodash the right way
If you want to avoid importing the whole library into your code to decrease your app size, then you should import only the functions you use.
For example, if you’ll be using only the pick
and cloneDeep
functions
in a component, instead of this:
import _ from 'lodash'
// ...
const picked = _.pick(obj, ['attr1', 'attr2', 'attr2'])
const cloned = _.cloneDeep(someOtherObj)
You should do this:
import { cloneDeep, pick } from 'lodash-es'
// ...
const picked = pick(obj, ['attr1', 'attr2', 'attr2'])
const cloned = cloneDeep(someOtherObj)
Aye, it’s a bit tedious, but if you are trying to save some KBs, then it’s the right thing to do.
About UI frameworks
If you want a batteries included type of framework, then Vuetify is a solid choice.
Learn how to add Vuetify to Vue.js.
If you are after freedom, and want to create your own design system in a very pragmatic way using utility classes as building blocks, then Tailwind CSS is for you.
Learn How to add Tailwind CSS to Vue.js.
A note on Pug and the new slot syntax
If you are using Jest, in conjunction with Pug and the new slot syntax:
v-menu
template(#activator="{ on }")
v-btn(color="primary" v-on="on")
//- ...
template(#activator="{ on }")
is equivalent to:
template(v-slot:activator="{ on }")
but in shorthand syntax.
You might get an error that looks like this:
ERROR: Unexpected character '#' (...)
STACK: SyntaxError: Unexpected character '#' (...)
You can read more about it here.
To fix it, just add this to jest.config.js:
module.exports = {
// ...
globals: {
'vue-jest': {
pug: {
doctype: 'html'
}
}
}
}
Useful links
- Vue.js style guide
- Rethinking validations for Vue.js
- 7 secret patterns Vue consultants don’t want you to know
- Vuex: Getting Started
- Vue 2 & Vuex Tutorial Version 2 — on YouTube
- Comparison with other frameworks — vs React, AngularJS, Angular, Ember, Knockout, Polymer, Riot
That’s it!
Have a good one. :)