02-手工构建模块化Vue项目

Catalogue
  1. 1. 目标
  2. 2. 分模块前
  3. 3. vue和webpack的关系
  4. 4. 安装webpack
  5. 5. 改造模块化
  6. 6. 组件化

目标

最近在学习vue的过程中发现网上的vue教程总有些不同的问题,有的教程上来只说语法,有的教程上来就用vue-cli来建项目,但是vue-cli是整合了webpack等多个插件的工具,不利于我们学习原理。我觉得一个好的教程应该具备以下几点:

  • 浅显易懂,说人话
  • 每节课都是一个完整的可以运行的例子
  • 由浅入深的介绍知识点,中间不能有断层
  • 所以我打算写一个我自己的vue入门教程。我们先从一个土得掉渣的例子开始吧

分模块前

  1. 新建一个空文件夹learn-vue,在该空文件夹中新建index.html,其完整的页面代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">

<!-- 1. 引入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>learn-vue</title>
</head>
<body>

<!-- 3. 取值,注意此处的id为app,要和第2步中的el属性值匹配 -->
<div id="app">
<p>{{ message }}</p>
</div>

<!-- 2. 创建一个Vue实例 -->
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})
</script>
</body>
</html>

保存后刷新页面,你将会看到Hello Vue.js!

实际开发中我们不可能把整个网站的js和html全写到一个页面上在下一个例子中我们将会对这个例子进行改造。

vue和webpack的关系

很多教程上来把webpack跟vue绑在一起教,让很多原本不懂webpack的人以为webpack是vue的组成部分,或者是必不可少的部分。在这里我要声明一句:

webpack不是vue的必须组成,只是webpack可以让你的js文件看起来更结构化。

webpack是一个js打包工具,使用webpack你可以在一个js文件中使用 import 或者 require 来引用另外一个js文件中定义的组件。这样你就可以把js组件分文件存放了。

虽然vue的基础例子提供了vue-cli,使用这个工具会自动调用webpack来帮你打包js并自动插入js到html。但是这不利于我们学习技术。我们现在从最基本的webpack使用开始了解webpack如何跟vue一起工作。

安装webpack

  1. 新建package.json

    1
    2
    3
    4
    {
    "name": "learn-vue",
    "version": "1.0.0"
    }

    现在我们的learn-vue文件夹下有两个文件了,index.html和package.json

  2. 安装webpack

1
npm i --save-dev webpack webpack-cli

运行完该指令后,npm自动将webpack和webpack-cli写到了package.json中。此时的package.json的内容如下

1
2
3
4
5
6
7
8
{
"name": "learn-vue",
"version": "1.0.0",
"devDependencies": {
"webpack": "^4.25.1",
"webpack-cli": "^3.1.2"
}
}

我们的learn-vue文件夹下也自动生成了 node_modules和package-lock.json文件

改造模块化

通过webpack就可以把多个js文件打包成一个js文件。使用了webpack就可以使用import语句来导入别的js文件,这样做有两个好处

  • 不需要将公共库的js引用写到页面上来了,比如vue的引用就不需要写到index.html页面上了。
  • 你可以将你的所有js脚本可以按模块来分文件存放了
  1. 提取main.js

我们首先来试试把index.html上的js脚本抽取到一个js文件中。新建一个src文件夹,并在其中建立main.js。 并将index.html中的js语句移动到这个文件中,文件的内容为:

1
2
3
4
5
6
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})

我们将index.html中的这段语句换成js引用

1
<script src="src/main.js"></script>

完整index.html如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>learn-vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
<div id="app">
<p>{{ message }}</p>
</div>
<script src="src/main.js"></script>
</body>

</html>

然后记得再次访问页面,保证我们还能看到Hello Vue.js!字样。到此为止,我们还没有用到webpack。不用急,我们这就把webpack用上。

  1. 新建webpack.config.js文件,内容如下
1
2
3
4
5
6
7
8
9
10
var path = require('path');

module.exports = {
mode: 'development',
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};

简单的讲解一下这个webpack.config.js

  • mode: 主要用到的模式有production和development。开发时使用development,所以我们现在用development,其实你就算用production对我们的例子也没什么影响。
  • entry: 入口js,之前不是说过使用了webpack之后就可以引用import来导入别的js文件么?那么你可以想象一下,你项目中的js可以构成一个引用树。这个引用树总要有一个树根的,这个树根是不会被任何js所引用的,所有引用最后都可以回溯到它。这里的entry就是webpack的js引用树树根文件
  • output:定义了打包后文件要存放的路径和文件名

从output我们可以知道最终的文件会被存放在dist文件夹中。所以我们还需要建立dist文件夹,最后,我们来看看webpack究竟能干什么。在项目根目录下运行

1
npx webpack

如果你看到类似以下的输出

1
2
3
4
5
6
7
8
$ npx webpack
Hash: 5b16bee4aec18c534801
Version: webpack 4.12.1
Time: 62ms
Built at: 2018-06-27 01:00:04
Asset Size Chunks Chunk Names
bundle.js 3.84 KiB main [emitted] main
[./src/main.js] 77 bytes {main} [built]

那么恭喜你,你成功的构建了第一个webpack打包文件。

然后我们修改index.html页面上对main.js的引用为对bundle.js的引用

1
<script src="dist/bundle.js"></script>

然后再访问页面,确保你能看到Hello Vue.js!

  1. 安装vue

看看目录结构,是不是开始有点结构化了呢?有点意思吧。

接下来,我们来做更有意思的事情:将以下的vue的引用从页面上去除

1
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

我们来写你的第一个import语句。修改main.js脚本,在头部加上

1
import Vue from 'vue'

我们的main.js就变为了

1
2
3
4
5
6
7
8
import Vue from 'vue'

new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})

这个import怎么起作用呢?它总不会自己知道要去下载vue的源码吧?!当然没那么神奇了,你需要自己使用npm来安装vue

1
$ npm i --save vue

运行完后,我们的package.json中自动新增了vue

1
2
3
4
5
6
7
8
9
10
11
{
"name": "learn-vue",
"version": "1.0.0",
"devDependencies": {
"webpack": "^4.12.1",
"webpack-cli": "^3.0.8"
},
"dependencies": {
"vue": "^2.5.16"
}
}

node_modules文件夹下也增加了vue的包。

我们再使用webpack来构建一次项目

1
2
3
4
5
6
7
8
9
10
$ npx webpack
Hash: cd3c4ea4c7c76aeb5beb
Version: webpack 4.12.1
Time: 410ms
Built at: 2018-06-27 01:16:20
Asset Size Chunks Chunk Names
bundle.js 235 KiB main [emitted] main
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 489 bytes {main} [built]
[./src/main.js] 100 bytes {main} [built]
+ 4 hidden modules

构建完毕了,此时我们打开dist/bundle.js看看。你会发现它把整个vue库都压缩了并写入了bundle.js文件。这样你的页面在打开时就可以一次性的把所有js库所有的依赖库都下载好了。

我们再刷新一次页面,确保你还能看到Hello Vue.js!

额。。。这回什么都没有。打开控制台可以看到以下警告信息

1
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

这是因为如果你直接写 import Vue from ‘vue’ 那么调用的是运行时的vue版本,这个版本不带模板解析包。我们之前在index.html页面上引用的也不是运行时版本。所以在这个例子中正确的做法应该是

1
import Vue from 'vue/dist/vue.js'

再打包一次,这回我们就能够看到Hello Vue.js了。

组件化

如果你在网上看vue的教程,肯定经常会看到component组件这个概念。真正投入市场的产品都是由组件构成的。那么什么是vue的组件呢?

  1. 单文件组件(SFC)

每一个vue的组件都采用单文件组件的格式来组织组件文件。英文是  single file component 简称SFC。SFC文件的后缀名是 .vue。简单的说就是一个 .vue文件就是一个组件,它的结构由三部分组成

  • html模板
  • js脚本
  • css样式
  1. 新建HelloVue组件

组件放哪都行,不过业界的习惯是把组件放到 src/components文件夹下。所以我们在src下建立component文件夹

然后在src目录下建立一个新的组件HelloVue.vue,然后把之前写在index.html和main.js的代码搬到HelloVue.vue里面

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<p>{{ message }}</p>
</template>
<script>
export default {
name: 'HelloVue',
data: function() {
return {
message: 'Hello Vue.js!'
}
}
}
</script>

大家会发现跟之前的代码比起来有几个不同点:

  • 不需要执行 new Vue了,只需要用export default {…} 来定义组件即可
  • data属性变成一个方法了,该方法可以通过一串预处理过程得出一个json对象。此处我们没有预处理过程,所以直接返回对象咯
  • 没有