1、生成打包报告
**目的:**打包时,为了直观地发现项目中存在的问题,可以在打包时生成报告。生成报告的方式有两种:
方式1:通过命令行参数的形式生成报告
// 通过 vue-cli 的命令选项可以生成打包报告
// --report 选项可以生成 report.html 以帮助分析包内容
vue-cli-service build --report
方式2:通过可视化的UI面板直接查看报告**(推荐)**
在可视化的UI面板中,通过控制台和分析面板,可以方便的看到项目中所存在的问题
2、通过 vue.config.js 修改 webpack 的默认配置
**原因:**通过 vue-cli 3.0 工具生成的项目,默认隐藏了所有 webpack 的配置项。
**目的:**是为了屏蔽项目的配置过程,让程序员把工作重心,放到具体功能和业务逻辑的实现上。
如果程序员有修改 webpack 默认配置的需求,可以在项目根目录中,按需创建 vue.config.js 这个配置文件,从而对项目的打包发布过程做自定义的配置(具体配置参考https://cli.vuejs.org/zh/config/#vue-config-js)。
// vue.config.js
// 这个文件中,应该导出一个包含了自定义配置选项的对象
module.exports = { // 选项… }
2.1、为开发模式与发布模式指定不同的打包入口
**原因:**默认情况下,Vue项目的开发模式与发布模式,公用一个打包入口文件(src/mian.js)
**目的:**为了将项目的开发过程与发布过程分离,我们可以分为两种模式,各自指定打包的入口文件
**分离目的:**比如production移除代码中的console语句,development不移除代码中的console语句
开发模式的入口文件为 src/main-dev.js
发布模式的入口文件为 src/main-prod.js
2.2、webpack下的两个属性:configureWebpack、chainWebpack
**使用属性的原因:**如果要修改默认的打包入口,在 vue.config.js 这个文件,会导出一个配置对象
**目的:**可以通过配置对象中的 configureWebpack 和 chainWebpack 节点,来自定义 webpack 的打包配置。
它们的作用完全相同,唯一的区别是它们 修改的方式(用法)不同:
chainWebpack 通过链式编程的形式,来修改默认的 webpack 配置
configureWebpack 通过操作对象的形式,来修改默认的 webpack 配置
两者具体的使用差异,可以参考下面的网址:
https://cli.vuejs.org/zh/guide/webpack.html#webpack-%E7%9B%B8%E5%85%B3
**chainWebpack执行过程:**通过chainWebpack自定义打包入口,通过module.exports向外暴漏了一个配置对象,在这个对象中,用chainWebpack声明了一个apage节点,它指向的值是一个处理函数,在函数中通过config来接受默认的Webpack的配置对象,然后通过config.when函数来判断当前处于什么编译模式,是开发阶段还是产品发布阶段,如果满足这个条件就会执行后面对应的回调函数。
如果当前处于production阶段,可以通过config.entry(‘app’)方法得到默认的打包入口,然后通过clear()方法将默认打包入口清空掉,再通过add(’./src/main-prod.js’)新增一个自己的打包文件。
在vue.config.js文件中,写入如下代码:
module.exports = {
chainWebpack: config => {
// production 发布阶段
config.when(process.env.NODE_ENV === 'production', config => {
config.entry('app').clear().add('./src/main-prod.js') )
// devlopment 开发阶段
config.when(process.env.NODE_ENV === 'development', config => {
config.entry('app').clear().add('./src/main-dev.js') )
}
}
3、通过 externals 加载外部CDN资源
**原因:**默认情况下,通过 import 语法导入的第三发依赖包,最终会被打包合并到同一个文件中,从而导致打包成功后,单文件体积过大的问题。
**目的:**为了解决这个问题,可以通过 webPack 的 externals 节点,来配置并加载外部的 CDN 资源。凡是声明在 externals 中的第三方依赖包,都不会被打包合并。
把第三方依赖包放在externals节点中,在打包期间 webPack 会先检查,有没有在externals 中声明一些第三方依赖包,如果有就不会打包,而是在用第三方依赖包时,在window全局对象下找现成的对象使用。
在vue.config.js文件中,发布模式下,写入如下代码:
config.set('externals',{
vue:'Vue',
'vue-router':'VueRouter',
axios:'axios',
lodash:'_',
echarts:'echarts',
'vue-quill-editor':'VueQuillEditor'
})
同时,需要在 public/index.html 文件的头部,添加对应的CDN资源(css、js)引用:
<!-- externals中对应的 js 文件 -->
...
<!-- externals中对应的 css 文件 富文本编辑器 的样式表文件 -->
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.core.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.snow.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.bubble.min.css" />
4、通过 CDN 形式优化 ElementUI 中组件的打包过程
**原因:**通过上面的方法,资源文件体积已经缩小很多,但是当前文件体积因为 Element UI 组件的关系,体积还是有点大。
**目的:**进一步压缩文件体积,把 Element UI 抽出来,配置为外部 CDN 资源
具体操作流程如下
在 main-prod.js 中,注释掉 element-ui 按需加载的代码
在 index.html 的头部区域中,通过 CDN 加载 element-ui 的 js 和 css 样式
5、首页内容定制
**原因:**不同的打包环境下,首页内容可能会有所不同。比如:开发环境中 title 标签中是 dev- 后台管理系统,发布环境中 title 标签中是后台管理系统。
**解决方法:**我们可以通过插件的方式进行定制,插件配置如下:
chainWebpack: (config) => {
// production 发布阶段
config.when(process.env.NODE_ENV === 'production', (config) => {
config.plugin('html).tap(args => {
args[0].isProd = true
return args
})
})
// development 开发阶段
config.when(process.env.NODE_ENV === 'development', (config) => {
config.plugin('html).tap(args => {
args[0].isProd = false
return args
})
})
}
**执行过程:**在 chainWebpack 里面通过 config.plugin()函数,找到 html 插件,通过tap() 可以修改插件里面固定的配置项,tap() 中回调函数 通过 args 拿到当前 html 插件里面的相关的参数,之后听过 args[0] , 追加一个自定义的属性字段 isProd ,如果处于发布模式,让参数中的 isProd = true,如果处于开发模式,让参数中的 isProd = false,这样在 public/index.html 首页中,可以根据 isProd 的值,来决定如何渲染页面的结构:
<!-- 按需渲染页面的标题 -->
<title><%=htmlWebpackPlugin.options.isProd ? '' : 'dev - ' %>后台管理系统</title>
<!-- 按需加载外部 CDN 资源 -->
<%= if(htmlWebpackPlugin.options.isProd) { %>
<!-- 通过 externals 加载的外部 CDN 资源 -->
<% } %>
<!-- htmlWebpackPlugin 插件的具体名称
.options 常见中的参数项
.isProd 在vue.config.js中自定义的参数
-->
6、路由的懒加载
**原因:**当打包构建项目时,JavaScript包会变得非常大,影响页面加载。
**目的:**把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样可以更加高效。
具体实施步骤:
安装@babel/plugin-syntax-dynamic-import包。
在babel.config.js配置文件中声明该插件。
“plugins”: ["@babel/plugin-syntax-dynamic-import"]
在router.js文件下将路由改为按需加载的形式,示例代码如下:
const Foo = () => import ( /* webpackChunkName: “group-foo” / ‘./Foo/vue’ )
const Bar = () => import ( / webpackChunkName: “group-foo” / ‘./Foo/vue’ )
const Baz = () => import ( / webpackChunkName: “group-boo” */ ‘./Foo/vue’ )
- 导入三个路由对应的组件 Foo、Bar、Baz
- 使用 import() 形式导入
- /* webpackChunkName: “group-foo” */ 代表路由的分组
- ‘./Foo/vue’ 代表组件对应的存放路径
- 这种语法必须安装@babel/plugin-syntax-dynamic-import插件才会支持
其中 Foo 和 Bar 的 webpackChunkName 的值都是 group-foo,最后打包时 Foo 和 Bar 会打包到一个文件中,代表请求 Foo 组件同时也会请求 Bar 组件。
通过 webpackChunkName 可以实现组件的分组,可以把多个组件打包到同一个 js 文件中
路由懒加载参考文档:https://router.vuejs.org/zh/guide/advanced/lazy-loading.html