AI 摘要
开发阶段
这个项目是一款中后台管理系统,所以当时以 Vue.js 作为主框架进行开发,然后使用了 iView 作为 UI 框架。其中,其它部分就是 Vue 的生态了,例如 Vue Router 和 Vuex 等。
生成项目结构
最近 @vue/cli 发布了正式版 Vue CLI 3,但其实早在 3 月份就发布了测试版,所以当初使用了测试版 CLI 生成了项目结构。最近也升级成和最新版一致的了。CLI 工具还增加非常强大的功能,包括安装插件、可视化界面、配置文件等。
// 生成项目结构
vue create project-name
// 使用 UI 界面
vue ui
这部分就比较简单,关于项目结构,CLI 文档也有说明。
配置开发环境
最新版的 CLI 工具支持自定义配置,如果你在项目根目录下提供一个 vue.config.js
文件,cli 在启动项目时会自动加载这些配置项。这部分应该是比较有趣的一部分,而且把这些东西配置好之后,开发效率可以嗖嗖嗖的提升。
这一项里面,我最常用的是端口号和代理这两项,webpack-dev-server 支持的配置项都可以集成进来。需要代理的原因是前后台是分离式开发,需要解决跨域问题(如果后台配置了 CORS,则不需要这项配置)。
module.exports = {
//...
devServer: {
port: 8081,
proxy: 'http://localhost:8080',
},
//...
}
使用 webpack 插件
使用 webpack 插件比较简单,例如使用 webpack-bundle-analyzer 来分析打包后各个模块的体积大小:
const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
plugins: [new BundleAnalyzerPlugin()],
}
webpack 链式操作 chainWebpack
这个配置项允许你对内部的 webpack 配置做出一些修改,例如添加一个新的 loader、修改插件的配置、为其它目录添加 vue 的支持等。但是 问题在于你可能不知道内部使用的 loader,那么这时候 vue inspect
这个命令会将内部配置输出在控制台,你可以查看想要修改的规则。看一下这个 🌰:
// vue.config.js
// 修改 index.html 和 favicon.png 的路径
module.exports = {
chainWebpack: (config) => {
config.plugin('html').tap((args) => {
args[0].template = 'path/to/index.html'
args[0].favicon = 'path/to/favicon.png'
return args
})
},
}
这个功能使用了 webpack-chain 的 API。
使用环境变量
如果你想在项目中使用环境变量,可以在项目的根目录下增加以下文件:
.env
所有环境加载.env.local
所有环境 加载,会被 git 忽略.env.[mode]
在特定环境中加载.env.[mode].local
在特定环境中加载,会被 git 忽略
其中 mode 的值 可以是:development
/production
/test
。
如何使用呢?假如在项目根目录下存在 .env
文件:
VUE_APP_TITLE=Hello World
此时,在项目代码中就可以这样访问它:
console.log(process.env.VUE_APP_TITLE) // Hello World
如果运行 yarn build
进行构建,那么这个环境变量将会直接被替换对应的值。
浏览器兼容
如果要兼容 IE 则 需要安装 babel-polyfill
。
// main.js
import 'babel-polyfill';
// ...
使用 JSX
提到 JSX,最先想到的是 React。其实 JSX 是可以独立存在的,它只是一种语法糖而已。所以在 Vue 中也可以使用。在 Vue CLI 3 中可以直接使用 JSX,而 2.x 版本则需要安装相应的依赖(babel-plugin-transform-vue-jsx)。
我们项目的 UI 框架是 iView,在使用 Table 组件时经常要使用 render
函数,如下:
export default {
data() {
return {
columns: [
{
title: '操作',
key: 'action',
render: (h, params) => {
return h('div', [h('Button', '编辑'), h('Button', '删除')])
},
},
],
}
},
}
但是如果 render
函数要处理很多元素的时候,它会显得非常臃肿,而且不易维护。那此时我们就可以使用 JSX 来优化代码:
export default {
data() {
return {
columns: [
{
title: '操作',
key: 'action',
render: (h, params) => {
return (
<div>
<i-button>编辑</i-button>
<i-button>删除</i-button>
</div>
)
},
},
],
}
},
}
注:如果你使用的是 Webstorm,可能会出现语法错误之类的警告。可以通过设置
Settings -> Languages & Frameworks -> Javascript -> Javascript language version -> React JSX
来解除报错。
性能优化
代码分割 & 路由懒加载
代码分割是什么意思呢?正常来说,在你使用 yarn build
构建之后, dist
文件下会生成一个如几个文件,默认情况下没有开启代码分割。
例如有如下路由:
import Home from './views/Home.vue'
import About from './views/About.vue'
const routes = [
{
path: '/home',
name: 'home',
component: Home,
},
{
path: '/about',
name: 'About',
component: About,
},
]
export default routes
这是我们经常使用的路由加载方式,没有代码分割。那我们如何使用代码分割功能呢? 这时我们就可以根据路由对代码进行分割了:
const routes = [
{
path: '/home',
name: 'home',
component: () => import(/* webpackChunkName: "home" */ './views/Home.vue'),
},
{
path: '/about',
name: 'About',
component: () =>
import(/* webpackChunkName: "about" */ './views/About.vue'),
},
]
export default routes
这样改造完之后,我们再运行 yarn build
:
在原来的基础上又增加了 2 个 js 文件和 2 个 css 文件,这正是代码分割的作用。只有在访问相应路由时再去加载对应的 js 和 css 文件。
分析并压缩代码体积
在编写大型程序时,难免会遇到打包后 js 文件体积过大的问题,因为项目可能会引入第三方依赖,在一定程度上加重了这个问题。那如何解决呢?
- 代码分割,按需加载
- 分析打包后的代码
- 剥离第三方库
首先,代码分割上面已经说了。
如何分析打包后的代码呢?运行 yarn build
时提供参数 --report
:
yarn build --report
运行上述命令之后,会在 dist
下生成 report.html
,打开它可以看到:
各个色块代表了相应的 js 所占用的空间。面积越大的体积就越大。
那如何优化呢?在使用了路由懒加载之后,性能会有比较明显的提升。但是我们还需要进一步优化:剥离第三方库。
何为剥离?因为项目使用 iView 作为 UI 框架,然后还有 Vuex 和 vue-router 这几个 依赖框架。 正常情况下,这些框架和其他一些依赖都会被打包进 dist/chunk-venders.[hash].js
中,因此, 可能会得到一个很大(5M+)的 js 文件。但是我们可以通过将这些 js 以 CDN 的方式引入,这样 就可以避免 chunk-venders.[hash].js
文件过大:
// vue.config.js
module.exports = {
// ...
configureWebpack: {
externals: {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter',
iview: 'iview',
},
},
}
在 public/index.html
中添加以下内容:
<!DOCTYPE html>
<html lang="en">
<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" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<!-- 要添加的 css -->
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/dist/styles/iview.css"
/>
<!-- 要添加的 css -->
<title>vue-test-demo</title>
</head>
<body>
<noscript>
<strong
>We're sorry but vue-test-demo doesn't work properly without JavaScript
enabled. Please enable it to continue.</strong
>
</noscript>
<div id="app"></div>
<!-- 要添加的 js -->
<script src="https://unpkg.com/[email protected]/dist/vue.runtime.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuex.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-router.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/iview.js"></script>
<!-- 要添加的 js -->
<!-- built files will be auto injected -->
</body>
</html>
如果是其它的第三方库,写法都一样。再次运行 yarn build
之后, 可以看到 chunk-venders.[hash].js
文件的体积会明显变小。
启用 gzip
HTTP 协议中的 gzip 是用来改进性能的,它的压缩比率大概在 3 到 10 倍之间,可以大幅节省网络带宽,但是会增加服务器 CPU 的负担。目前主流浏览器都支持 gzip 解码,所以一般只需要服务端启用 gzip 即可。