最近在做一个 Vue 项目的时候,突然发现了一个有意思的知识点。
有几位客服反馈说在点击某个链接跳转的时候,老是没得反应,导致选不了选项。我就很奇怪,内网环境下是没有问题的,所以代码出问题的可能性不大,怎么外网就有这种问题呢?后来仔细看了一下才发现,原来是运维那边出了点纰漏导致外网有些客户的 JavaScript 资源加载不出来,进而导致无法跳转。这里涉及到了 Vue 的异步组件知识,只有当切换到某个组件时,其单独打包的资源才会被加载。不同于统一打包的情况,这样做可以利用代码切割减少首屏加载时的资源大小,能够提升一定的加载速度,优化用户体验。接下来就自己重新做一下这个异步组件。
以下命令行操作均在 Linux 环境下进行。
一、搭建项目
先切换到你的项目根目录下,此时应该是一个空文件夹。
然后用 npm 命令初始化,添加具有一些默认选项的 package.json 文件。
$ npm init -y
然后开始创建必要的文件:
$ sudo touch .babelrc index.html
index.html 中写入一下代码,作为固定模板:
<!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 转译器的,等会再来配置。
接下来创建必要的文件夹:
$ sudo mkdir -p build dist src/components src/routers
在 build 目录下创建三个文件,作为 Webpack 打包的配置文件:
- webpack.base.conf.js
- webpack.dev.conf.js
- webpack.prod.conf.js
然后安装必要的依赖:
$ 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
$ npm i -S vue vue-router
然后把下面的配置代码扔到对应的配置文件中:
// 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()
]
};
// 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'
});
// 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 中写入以下内容:
{ "presets": [ "babel-preset-env" ] }
然后就可以准备开发了。
二、开始 Vue 开发。
在 src 目录下创建一个 index.js 文件作为打包入口文件,然后:
// /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 代码:
<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 中,代码如下:
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 目录下写我们对应的三个组件:
// java.vue
<template>
<h1>Java</h1>
</template>
<script>
export default {
name: 'java'
}
</script>
// javascript.vue
<template>
<h1>JavaScript</h1>
</template>
<script>
export default {
name: 'javascript'
}
</script>
// python.vue
<template>
<h1>Python</h1>
</template>
<script>
export default {
name: 'python'
}
</script>
修改 npm scripts
npm scripts 的定义如下:
"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"
},
最后运行起来本地测试服务器:
$ npm run dev
打开浏览器的开发者工具,切换到 Network 选项卡,点击不同的链接,可以看到在加载切换路由时,会加载对应打包出来的 js 资源。
运行 npm run build
,可以看到打包出来了多个 js 资源文件:
总结
-
是一个 Webpack 打包 Vue 项目的优化点,通过异步组件,可以切割我们的代码,提升用户体验。
-
异步组件切割代码实现简单,只需要改变配置 Vue-Router 的方式即可,指定路由对应的组件时,使用如下方式:
{ path: '/XXX', component: resolve => { require(['./XXX.vue'], resolve); } }