Vue.js, Webpack, Vueitify, Electron, and vue-cli
Introduction
Vue.js is a reactive progressive framework that allows the creation of Javascript apps. It is very similar to React.
This tutorial is a guide to using vue-cli
(which is similar to
create-react-app
) in order to create a project that supports Material
Design (thru Vuetify), Electron, and Webpack. Here’s
another tutorial that serves as an introduction to Vue.
Starter project repo
Here’s a GitHub repo that I created as the
end result of going thru this tutorial. This project can be used as a starter project that is built using vue-cli-3
which allows for the use of Webpack, Vue, Vuetify (Material Design), and Electron (along w/ lodash
, and axios
).
Run the project
Task | Command |
---|---|
Project setup | npm install |
Compiles and hot-reloads for development | npm run serve |
Compiles and minifies for production | npm run build |
Lints and fixes files | npm run lint |
Step by step guide to buiding this starter project
Instructions on getting started w/ Vue-cli3, electron, vuetify. The following steps will guide you thru creating this project from scratch if you choose, instead of getting the GitHub repo.
Install vue-cli-3
fix-brew.sh
npm install -g @vue/cli
Setup the new project
Run the project (in browser or Electron)
- in electron -
npm run serve:electron
- in browser -
npm run serve
Add dependencies
npm add axios lodash
- Use them by doing a simple import (eg in main.js,
import _ from 'lodash';
)
References / Documentation
- Step by step tutorial of using vue-cli, etc
- Single file components (.vue files)
- Developing apps generated by
vue-cli
- Tool for theming and customizing Vuetify
Deep dive into the code
Now that we have the mechanics of creating this project out of the way, let’s look at how this project is organized and some of the interesting elements in it. Here are some files that we are going to cover in depth.
src/
+--- main.js
+--- App.vue
+--- components/
+--- HelloWorld.vue
+--- plugins
+--- vuetify.js
main.js
Webpack takes all the HTML, CSS, and JS files in the project, packages and minifies them. This main.js
file ends up
being the main entry point for the code in our project.
1. Mounting to the DOM
new Vue({ render: (h) => h(App) }).$mount("#app");
There’s an index.html
file in the public/
folder which has a div
with id
of app
. The line of code above mounts
the root Vue component App
to this div
.
2. State or application object model
The first thing that I do here is setup the data which serves as the application model or shared state between all the Vue components that are created.
export const appData = {
app_icon: "code",
body_message: "Hello world!",
footer_message: "Made with ❤️ in Mountain View, California",
title: "Vue, Vuetify, Webpack",
time: new Date(),
};
The appData
object is the state of the application. And when this data changes, Vue components in this project will
react and refresh themselves to stay up to date w/ the data in this object.
setInterval(() => {
appData.time = new Date();
}, 1000);
The code above updates the value of appData.time
every second w/ the current date. When you run the code, you will see
that the footer of the web app shows the current time updating every second. Let’s take a look at the root Vue component
App
to see how this is accomplished.
App.vue
In main.js
you will find the following import statement.
import App from "./App.vue";
This loads the App
Vue component to be mounted to the DOM. Let’s take a closer look at this root Vue component. The
App.vue
file has 3 things in one place:
<template>
that contains the template that will be used to stamp out this component in the DOM.<script>
that contains the JS code that is associated w/ this component. There are some interesting things that you should watch out for as you write functions in this block (especially with regards to howthis
is handled in functions that you write within these<script
> tags).<style>
that contains CSS fragments that you can apply only to this component and not pollute the rest of your DOM.
1. Script
In the case of App.vue
, here’s the <script>
section.
import HelloWorld from "./components/HelloWorld";
import { appData } from "./main";
export default {
name: "App",
components: {
HelloWorld,
},
data: () => {
return appData;
},
};
The main thing to note here is that an object is exported via default
. This is the object which was imported in
main.js
and mounted to the DOM. This object represents options that are used by Vue to create the Vue component itself
(new Vue({render: h => h(App)}).$mount('#app');
) in main.js
.
The data
function provides access to all the state information that will be available to App
component, and portions
of this state will be passed around as props to other components that are needed. In this case, we have HelloWorld
component that is needed by App
. You can see that this HelloWorld
component is loaded using an import statement
above.
You can see the HelloWorld
tag used in the <template>
section below.
2. Template
And here’s the <template>
section.
<v-app dark>
<v-toolbar app dark color="primary">
<v-icon>{{app_icon}}</v-icon>
<v-toolbar-title>{{title}}</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<v-content>
<HelloWorld v-bind:msg="body_message" />
</v-content>
<v-footer app>
<v-spacer></v-spacer>
<span class="surface--text"> {{footer_message}} ⏱ {{time}} </span>
<v-spacer></v-spacer>
</v-footer>
</v-app>
The App
component is the root, which is why it provide data
. You will see in the HelloWord
component below, that
it doesn’t have any data
. Instead it has to rely on the use of props in order to get information.
3. Props
The HelloWorld
component is declared and passed a props msg
via v-bind:
attribute, and the body_message
object
is passed to it. This body_message
object is loaded from the Vue component’s data, that is just prodding access to the
appData
object which was declared in main.js
.
Vue actually wraps the underlying appData
object w/ a proxy, which is how the ‘reactivity’ is implemented in the Vue
framework.
There are some other places in the template where you see code appearing between {{
and }}
. These are all references
to objects that are made available by the Vue component’s data
property (which just provides access to appData
).
4. Material Design and Theming
And there are quite a few tags like v-app
and v-toolbar
etc. These are all part of the Vuetify Material Design
library. Here’s a quick rundown of what these do.
v-app
This is the root tag for any Vuetify application. Thedark
attribute marks this to have the dark theme. Vuetify doesn’t really manage themes in the way that I thought it would. Eg: overriding the theme doesn’t really propagate the color choices, etc to existing components. More on this below.v-toolbar
This is the toolbar component, to which I’ve added some attributes for styling. Even though I provided a custom theme to Vuetify which is loaded viavuetify.js
inmain.js
, my color choices forprimary
,secondary
, etc didn’t propagate to the existing components 😡. So I had to explicitly provide attributes to each tag to specify my color choices. In this case I applied the background color toprimary
and then applieddark
so that the icon and text colors would be inverted, so that they would have good contrast. I shouldn’t have to do this, and will be exploring other Material Design libraries for Vue in the future (that are not Vuetify).v-content
This holds the main content of the app between the header and the footer. This is where theHelloWorld
component is rendered.v-footer
This holds the footer of the app, and has the time which gets updated. One interesting thing to note here, related to themeing is that I created a color calledsurface
in my custom them (vuetify.js
). In order to apply this color to the text, I do this:
<span class="surface--text"></span>
However, in the code you could also have done something like this:
<span class="primary--text"></span>
Get the code
You can get the code used in this tutorial in the vue_webpack GiHub repo.