As we try to build more complicated (client side of) a web app, we’ve to handle a growing number of source code files (including HTML, JavaScript and other assets). We need to break down a large JavaScript program into several modules for better management. We may also want to install and use modules from third-party libraries (e.g. the Element Plus desktop UI library).
To handle the complexity of such projects, web developers often apply build tools to facilitate the development and testing processes and automate the building of distributable. In this section, we introduce the Vite tool and demonstrate how to build an Vue project with components and third-party library.
We need to have basic understanding of several tools and programming concepts before we dive into the study of Vue components.
From its official page, “Node.js is a JavaScript runtime built on Chrome’s V8 JavaScript engine”. Node.js is commonly used to develop network services, and, in particular, application servers for web apps (which will be the main topic in chapter 4).
In this chapter, we’ll mainly use Node.js as a platform to run development tools of Vue projects. For now, install node from the official page. After installation, check the version as below.
$ node -v
A JavaScript project most likely contains more than one JavaScript files and other resources (e.g. HTML, images) placed in a folder. The folder contains a file package.json
which describes the project. You can create package.json
with the following steps. See online reference for the meaning of properties in the file.
$ mkdir proj01
$ cd proj01
$ npm init
Now, create a simple JavaScript program hello.js
in the project. Run it with the command node hello.js
.
// hello.js
console.log("Hello Node!");
Bundled with Node.js is a package manager called NPM, a command line tool to download (and manage) JavaScript packages from package registry. The default registry is npmjs.com, which has recently become the largest JavaScript registry for both server-side and client-side libraries and also tools written in JavaScript.
You can easily install a package into a Node project with the command line tool npm
. The following commands installs a toy tool called cowsay
locally in the current project, and then run it with the command line tool npx
.
Actually,
npx
will download a package on-the-fly if it cannot find the package locally. Refer to online reference for more information.
$ npm install cowsay
$ npx cowsay Hello npm!
A more useful tool is a simple web server http-server
written in JavaScript.
$ npm install http-server
$ npx http-server
By default, npm install
installs a package and its dependencies in the folder node_modules
inside the project folder. Check it out. Moreover, npm install
also automatically adds an entry in the package.json
.
{
"name": "proj1",
"version": "1.0.0",
"scripts": {
"web": "http-server",
"hello": "cowsay \"Hello npm script!\""
},
"dependencies": {
"cowsay": "^1.5.0",
"http-server": "^13.0.1"
}
}
With the dependencies of a project listed in package.json
, you can install all the required package for a project with a simple command in the future.
$ npm install
You can also create scripts in package.json
to run commands with npm run
. Download the sample package c37-proj01.zip and watch the demo in class.
In the next few sections, we will use a build tool called Vite (official site) to develop, test and build Vue applications.
Using a build tool has several advantages, compared to our previous approach of loading JavaScript libraries from CDN and writing JavaScript code in a single *.js
file.
npm
). A package manager can automatically install dependencies of a package, and take care of versioning of packages.<script>
element in HTML. They can bundle multiple JavaScript files into one (or a few) file, and this can reduce the time that a web browser will load the web application.We will use a simple Node project c37-sfc.zip
to illustrate how to use Vite to develop a Vue project. First, download the example and expand the zip in a working folder. The following in the package.json
of the project.
{
"name": "c37-sfc",
"version": "0.1.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"vue": "^3.2.6"
},
"devDependencies": {
"@vitejs/plugin-vue": "^1.6.0",
"@vue/compiler-sfc": "^3.2.6",
"vite": "^2.5.2"
}
}
This project has two kinds of dependencies. dependencies
refers to packages that are required by the application itself. Execution of the application requires these packages. In this example, we have only vue 3. But if you use other libraries (e.g. Element Plus), you should install them into the project (e.g. npm install element-plus
).
The other kind of dependencies is devDependencies
. These packages are not necessary while we’re developing the project. You can install packages for development with npm install packageName --save-dev
.
Another config file in the project is vite.config.js
. This configures the Vite build tool. For our purpose, we mostly only need to change the input to the bundler.
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
rollupOptions: {
input: {
// list all HTML files that contain Vue components
index: './index.html',
}
}
}
})
The Vue application in this example (c37-sfc.zip) consists of three files. The HTML file is index.html
, a browser loads this file to run the web app. The HTML file loads the JavaScript module main.js
, which creates a Vue app using createApp()
. The root component of the app is provided by a SFC app.vue
.
We can run a development web server to test the app.
$ npm run dev
Open a browser to connect to the URL that is given by the above command. Can you run the web app?
Vite also supports live reload. When you make some changes to the source code, the browser will reload automatically to show the update. Try to make some changes to the HTML or JavaScript code and see that the browser refreshes to show the up-to-date version of the app.
When you’re reading to deploy the web app to a production web server, you can run npm run build
to build an application bundle in the folder dist
. Check the content of the folder.
$ npm run build
$ npm run serve
Vite also includes a simple web server to test the application bundle. Run npm run serve
to start the testing web server.
Vite uses ES modules (online reference) to manage the Vue components and other JavaScript files in a project. For example, index.html
loads main.js
with the following line.
<div id="app"></div>
<!-- Loading main.js as a JavaScript module -->
<script type="module" src="./main.js"></script>
main.js
sets up the Vue application. The first import
statement imports a function createApp
from the Vue package previously installed by npm install
. The second import
statement imports an options object of the root component from a SFC called app.vue
. main.js
then creates a Vue app according to the options object, and mounts it to the <div>
with id app
in the HTML file.
// import 'createApp' from the Vue library as a module
import { createApp } from "vue";
// import the options object from the SFC
import opts from "./app.vue";
createApp(opts).mount('#app');
Next, let’s look at the content of the SFC file app.vue
, which contains the root component of the app. There are three sections in a SFC: the template, the CSS style and the JavaScript code.
The template section provides the template code of the component.
The JavaScript section exports the options object of the component, which is imported by main.js
earlier.
<template>
The time now is
<div class='clock'>{{ timeNow }}</div>
</template>
<script>
export default {
data() {
return { timeNow: undefined }
},
created() {
this.timeNow = (new Date()).toLocaleTimeString();
setInterval( ()=>{
this.timeNow = (new Date()).toLocaleTimeString();
}, 1000);
}
};
</script>
<style scoped>
.clock { padding: 2px; width: 6em; border: 1px solid gray; text-align: center; }
</style>
SFC may also include a section for style. SFC allows us to restrict the style rules for this component only with <style scoped>
.
In this section, we go through the source code of another web app, which integrates the three UI component examples in the previous lecture. The link c37-feature provides a deployed version of the web app, which you can run in browser. The source code can be downloaded at c37-feature.
First, notice that package.json
adds Element-Plus as dependencies.
"dependencies": {
"element-plus": "^1.1.0-beta.8",
"vue": "^3.2.6"
},
This app has four components. The root component app.vue
includes three other components, comp01.vue
, comp02.vue
, comp03.vue
. The three child components correspond to the three examples in the previous lecture about common component features.
Notice several things in the following listing of app.vue
:
<template>
<el-card>
<template #header>Properties / Attributes</template>
<comp-part1></comp-part1>
</el-card>
<el-card>
<template #header>Bi-directional binding</template>
<comp-part2></comp-part2>
</el-card>
<el-card>
<template #header>Slots</template>
<comp-part3></comp-part3>
</el-card>
</template>
<script>
import { ElCard } from "element-plus";
import 'element-plus/dist/index.css';
import CompPart1 from "./comp01.vue";
import CompPart2 from "./comp02.vue";
import CompPart3 from "./comp03.vue";
export default {
components: { ElCard, CompPart1, CompPart2, CompPart3 }
};
</script>
import
s the options object (as default) from the SFC of each child component. The variable name (e.g. CompPart1
) is arbitrary, but should follow the Pascal case.components: { CompPart1 }
). Without this, you cannot use the child component in the template.components: { CompPart1 }
is a shorthand for components: { CompPart1: CompPart1 }
. Because element names in HTML are case-insensitive, Vue will convert the PascalCase CompPart1
to kebab-case comp-part1
in the template.<comp-part1></comp-part1>
.<el-card>
from the Node module element-plus
, which we has installed earlier using npm install
.import 'element-plus/dist/index.css'
to tell Vue to refer to that CSS in the HTML page that includes this component (the root component).Next, examine the source code of the child component comp01.vue
. Similar to the situation in the root component, here, we need to import <el-input>
and <el-progress>
from element-plus
, and register them in this component. We also import the Element-Plus CSS in this SFC because this component is using components from the library. The Vite build tool will only import the CSS once in the HTML page.
<template>
<el-input placeholder="what's up?"
suffix-icon="el-icon-chat-dot-round"
v-model="message"></el-input>
<el-progress :text-inside="true" :stroke-width="30"
:percentage="progress" :color="customColors">
</el-progress>
<el-button type="primary" @click="changeProgress">Change progress</el-button>
</template>
<script>
import { ElInput, ElProgress, ElButton } from "element-plus";
import 'element-plus/dist/index.css';
export default {
components: {
ElInput: ElInput,
ElProgress: ElProgress,
ElButton: ElButton,
},
data() { /* omitted */ },
methods: { /* omitted */ }
}
</script>
<style scoped>
.el-input, .el-progress { width: 300px; margin: 10px 10px; }
</style>