Vue 异步组件


  1. 1. 一、搭建项目
  2. 2. 二、开始 Vue 开发。
  3. 3. 修改 npm scripts
  4. 4. 总结

最近在做一个 Vue 项目的时候,突然发现了一个有意思的知识点。

有几位客服反馈说在点击某个链接跳转的时候,老是没得反应,导致选不了选项。我就很奇怪,内网环境下是没有问题的,所以代码出问题的可能性不大,怎么外网就有这种问题呢?后来仔细看了一下才发现,原来是运维那边出了点纰漏导致外网有些客户的 JavaScript 资源加载不出来,进而导致无法跳转。这里涉及到了 Vue 的异步组件知识,只有当切换到某个组件时,其单独打包的资源才会被加载。不同于统一打包的情况,这样做可以利用代码切割减少首屏加载时的资源大小,能够提升一定的加载速度,优化用户体验。接下来就自己重新做一下这个异步组件。

以下命令行操作均在 Linux 环境下进行。

一、搭建项目

先切换到你的项目根目录下,此时应该是一个空文件夹。

然后用 npm 命令初始化,添加具有一些默认选项的 package.json 文件。

1
$ npm init -y

然后开始创建必要的文件:

1
$ sudo touch .babelrc index.html

index.html 中写入一下代码,作为固定模板:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="zh-ch">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Async Components</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

.babelrc 是配置 babel 转译器的,等会再来配置。

接下来创建必要的文件夹:

1
$ sudo mkdir -p build dist src/components src/routers

在 build 目录下创建三个文件,作为 Webpack 打包的配置文件:

  • webpack.base.conf.js
  • webpack.dev.conf.js
  • webpack.prod.conf.js

然后安装必要的依赖:

1
$ npm i -D babel-loader@7 babel-core babel-preset-env webpack webpack-cli clean-webpack-plugin css-loader html-webpack-plugin vue-loader vue-style-loader vue-template-compiler webpack-dev-server webpack-merge
1
$ npm i -S vue vue-router

然后把下面的配置代码扔到对应的配置文件中:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// webpack.base.conf.js
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const cleanWebpackPlugin = require('clean-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
target: 'web',
entry: {
index: path.resolve(__dirname, '../src/index.js')
},
output: {
filename: '[name].[hash].js',
path: path.resolve(__dirname, '../dist/')
},
resolve: {
extensions: ['.vue', '.js', '.json', '.css'],
alias: {
'@': path.resolve(__dirname, '../src'),
'vue': 'vue/dist/vue.js',
'components': path.resolve(__dirname, '../src/components')
}
},
node: {
fs: 'empty'
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader']
},
{
test: /\.vue$/,
use: 'vue-loader'
}
]
},
plugins: [
new htmlWebpackPlugin({
inject: true,
template: path.resolve(__dirname, '../index.html')
}),
new cleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../'),
verbose: true,
dry: false
}),
new VueLoaderPlugin()
]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// webpack.dev.conf.js
const merge = require('webpack-merge');
const path = require('path');
const baseConfig = require('./webpack.base.conf.js');

module.exports = merge(baseConfig, {
mode: 'development',
devServer: {
contentBase: path.resolve(__dirname, '../dist/'),
port: 8888,
open: true,
// hot: true
watchOptions: {
watch: true
}
},
devtool: 'inline-source-map'
});
1
2
3
4
5
6
7
8
9
// webpack.prod.conf.js
const merge = require('webpack-merge');
const path = require('path');
const baseConfig = require('./webpack.base.conf.js');

module.exports = merge(baseConfig, {
mode: 'production',
devtool: 'source-map'
});

具体怎么配置这里就不赘述了,之前也写过这类型的博客,可以参考一下:基于 Webpack 4 搭建 Vue 开发环境

然后配置 babel:

在 .babelrc 中写入以下内容:

1
2
3
4
5
{
"presets": [
"babel-preset-env"
]
}

然后就可以准备开发了。

二、开始 Vue 开发。

在 src 目录下创建一个 index.js 文件作为打包入口文件,然后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// /src/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App';
import routerConfig from '@/routers';

Vue.use(VueRouter);
const routers = new VueRouter(routerConfig);

new Vue({
el: '#app',
components: { App },
router: routers,
template: '<div><App/></div>'
});

其中引用了一个同级目录下的 App 作为子组件,App.vue 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div>
<router-view></router-view>
<router-link to="/javascript">JavaScript</router-link>
<router-link to="/java">Java</router-link>
<router-link to="/python">Python</router-link>
</div>
</template>

<script>
export default {
name: 'app'
}
</script>

<style scoped>
h1 {
color: blue
}
</style>

注意到我们的 Vue-Router 配置写在 /src/routers/index.js 中,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
mode: 'hash',
routes: [
{
path: '/javascript',
component: (resolve) => {require(['components/javascript'], resolve)}
},
{
path: '/java',
component: (resolve) => {require(['components/java'], resolve)}
},
{
path: '/python',
component: (resolve) => {require(['components/python'], resolve)}
},
{
path: '/*',
redirect: '/javascript'
}
]
}

然后在 components 目录下写我们对应的三个组件:

1
2
3
4
5
6
7
8
9
10
// java.vue
<template>
<h1>Java</h1>
</template>

<script>
export default {
name: 'java'
}
</script>
1
2
3
4
5
6
7
8
9
10
// javascript.vue
<template>
<h1>JavaScript</h1>
</template>

<script>
export default {
name: 'javascript'
}
</script>
1
2
3
4
5
6
7
8
9
10
// python.vue
<template>
<h1>Python</h1>
</template>

<script>
export default {
name: 'python'
}
</script>

修改 npm scripts

npm scripts 的定义如下:

1
2
3
4
5
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --config ./build/webpack.dev.conf.js",
"build": "webpack --config ./build/webpack.prod.conf.js"
},

最后运行起来本地测试服务器:

1
$ npm run dev

打开浏览器的开发者工具,切换到 Network 选项卡,点击不同的链接,可以看到在加载切换路由时,会加载对应打包出来的 js 资源。

截图

运行 npm run build,可以看到打包出来了多个 js 资源文件:

截图

总结

  • 是一个 Webpack 打包 Vue 项目的优化点,通过异步组件,可以切割我们的代码,提升用户体验。
  • 异步组件切割代码实现简单,只需要改变配置 Vue-Router 的方式即可,指定路由对应的组件时,使用如下方式:

    1
    2
    3
    4
    5
    6
    {
    path: '/XXX',
    component: resolve => {
    require(['./XXX.vue'], resolve);
    }
    }