前言 Vue 项目打包优化 - CDN、配置分离、路由懒加载。
本例项目是之前写的一个后台管理系统,项目使用的库版本:
vue-cli
: @3.11.0
vue
: @2.6.10
vue-router
: @3.1.3
另外本项目还用到了 axios
、echarts
、element-ui
、nprogress
、vue-quill-editor
等,不优化直接打包会非常大。优化目的:
配置分离:开发模式使用本地资源,生产模式打包资源使用 CDN 引入。
路由懒加载:js 包过大会影响页面加载速度,路由被访问才加载对应组件更加高效。
生成打包报告 有两种方式:
命令行生成打包报告(build 命令后加 --report
)
利用 vue ui 工具(推荐,非常直观)
命令行生成报告 1 2 3 4 npmx vue-cli-service build --report npm run build
此方法会自动在 dist
目录下生成 report.html
,打开如下:
vue ui 图形化界面生成报告 vue-cli3
中自带了 vue ui
图形化界面,用于创建和管理项目。
【导入项目】-【任务】-【build】- 【运行】,效果如下:
优化一:配置分离 从打包报告中可以看出,依赖项大小还是挺大的,如 element-ui
、echarts
等,我们可以通过配置分离,在生产模式 打包时不要打包这些依赖以及一些 CSS 本地资源,在 html 模版中引入依赖的 CDN 资源。
需要了解的知识有:
分离配置 vue-cli3
中需要添加 vue.config.js
配置文件。
给不同模式定义不同的入口文件
需要 CDN 引入的依赖添加到 externals
中
给 htmlWebpackPlugin 添加一个参数变量来控制 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 30 31 32 33 34 35 module .exports = { chainWebpack: (config ) => { config.when(process.env.NODE_ENV === 'production' , (config) => { config.entry('app' ).clear().add('./src/main-prod.js' ) config.set('externals' , { vue: 'Vue' , 'vue-router' : 'VueRouter' , axios: 'axios' , lodash: '_' , echarts: 'echarts' , nprogress: 'NProgress' , 'vue-quill-editor' : 'VueQuillEditor' }) config.plugin('html' ).tap((args ) => { args[0 ].isProd = true return args }) }) config.when(process.env.NODE_ENV === 'development' , (config) => { config.entry('app' ).clear().add('./src/main-dev.js' ) config.plugin('html' ).tap((args ) => { args[0 ].isProd = false return args }) }) } }
注:vue-cli 中 html 模版是由 html-webpack-plugin
处理的,所以可以通过给插件属性添加一个变量,并且 html 模版可以通过插值的方式,根据变量来决定是否输出 CDN 资源。
定义不同的入口文件 原入口文件 main.js
复制两份分别命名 main-dev.js
、main-prod.js
。 在 main-prod.js
注释或删除 CDN 引入的 CSS。
html 模版引入 CDN public/index.html
引入 external 忽略的依赖和入口文件删除的 CSS 对应的 CDN 链接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <title > <%= htmlWebpackPlugin.options.isProd ? '' : 'DEV - ' %> 后台管理系统</title > <% if (htmlWebpackPlugin.options.isProd ) { %> <link rel ="stylesheet" href ="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" /> <link rel ="stylesheet" href ="https://cdn.staticfile.org/quill/1.3.7/quill.core.min.css" /> <link rel ="stylesheet" href ="https://cdn.staticfile.org/quill/1.3.7/quill.snow.min.css" /> <link rel ="stylesheet" href ="https://cdn.staticfile.org/quill/1.3.7/quill.bubble.min.css" /> <link rel ="stylesheet" href ="https://cdn.staticfile.org/element-ui/2.13.0/theme-chalk/index.css" /> <script src ="https://cdn.staticfile.org/vue/2.6.10/vue.min.js" > </script > <script src ="https://cdn.staticfile.org/vue-router/3.1.3/vue-router.min.js" > </script > <script src ="https://cdn.staticfile.org/axios/0.19.0/axios.min.js" > </script > <script src ="https://cdn.staticfile.org/lodash.js/4.17.13/lodash.min.js" > </script > <script src ="https://cdn.staticfile.org/echarts/4.6.0/echarts.min.js" > </script > <script src ="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js" > </script > <script src ="https://cdn.staticfile.org/quill/1.3.7/quill.min.js" > </script > <script src ="https://unpkg.zhimg.com/vue-quill-editor@3.0.6/dist/vue-quill-editor.min.js" > </script > <script src ="https://cdn.staticfile.org/element-ui/2.13.0/index.js" > </script > <% } %>
如上设置模版,即可通过变量 isProd
在不同模式下是否加载 CDN 资源,以及不同模式下有不同的 title。
优化二:路由懒加载 如上操作后可以一定程度减少打包大小,但此时所有组件仍会被打包到同一个 chunk-vendors.js
中,如果组件过多打包数据仍然会很大,从而影响首屏加载时间。
路由懒加载 可以将代码分割打包,且仅当路由被访问时才加载对应组件。
最简单方法:
1 2 const Login = () => import ('../views/Login.vue' )
以上方式有个缺点,会将每个路由组件单独打包。可以通过魔法注释 将部分组件打包在同个 chunk
中,相同 chunkName 为一个包。如下:
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 const Login = () => import ( '../views/Login.vue' )const Home = () => import ( '../views/Home.vue' )const Welcome = () => import ( '../components/home/Welcome.vue' )const Users = () => import ( '../components/users/Users.vue' )const RightsList = () => import ( '../components/rights/RightsList.vue' )const RolesList = () => import ( '../components/rights/RolesList.vue' )const GoodsCategories = () => import ( '../components/goods/GoodsCategories.vue' )const GoodsList = () => import ( '../components/goods/GoodsList.vue' )const CategoriesParams = () => import ( '../components/goods/CategoriesParams.vue' )const AddGoods = () => import ( '../components/goods/AddGoods.vue' )const OrdersList = () => import ( '../components/orders/OrdersList.vue' )const StatisticsReports = () => import ( '../components/statistics/StatisticsReports.vue' )
结果 此时重新打包生成报告:
另外 :如果服务器开启 Gzip,在 vue.config.js
配置中使用 Gzip 压缩,能得到更好的压缩效果,如何开启这里就不赘述了,自行 Google 吧。
参考文档: