一、vueCli 查看打包后文件的大小占比
⚠️vue-cli2 应用 webpack-bundle-analyzer
// 用vue-cli2 构建的我的项目 中里曾经集成了 应用npm run build --report 命令即可
⚠️上面实用于:vue-cli3
1.1 装置依赖
$ npm install webpack-bundle-analyzer --save-dev
1.2 配置vue.config.js
chainWebpack: config => { // 查看打包文件体积大小 config .plugin('webpack-bundle-analyzer') .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin,[ { analyzerMode: 'server' } ]) } /** analyzerMode?: 'server' | 'static' | 'json' | 'disabled'; * Can be "server", "static" or "disabled". * Defaults to "server". * In "server" mode analyzer will start HTTP server to show bundle report. * In "static" mode single HTML file with bundle report will be generated. * In "json" mode single JSON file with bundle report will be generated * In "disabled" mode you can use this plugin to just generate Webpack Stats JSON file by setting "generateStatsFile" to true. */
1.3 配置打包脚本
在package.json
的scripts
中配置
$ "build": "vue-cli-service build --report"
执行命令:
$ npm run build
关上浏览器:http://127.0.0.1:8888 之后 就会看到一个【可视化】的文件占比
❗️扩大:终端如果报出正告: (资产大小限度244KIB,可能回影响网络性能)。
![[图片上传中...(20200428150718890.png-e3528-1624502443756-0)]
](https://upload-images.jianshu.io/upload_images/11846892-a979dcca61ef8edd.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
解决办法:在vue.config.js
中配置
module.exports = { //webpack配置 configureWebpack: { //敞开 webpack 的性能提醒 performance: { hints:false } // 或者 //正告 webpack 的性能提醒 performance: { hints:'warning', //入口终点的最大体积 maxEntrypointSize: 50000000, //生成文件的最大体积 maxAssetSize: 30000000, //只给出 js 文件的性能提醒 assetFilter: function(assetFilename) { return assetFilename.endsWith('.js'); } } }, // vue.config.js // configureWebpack: config => { // config.performance = { // hints: 'warning', // maxEntrypointSize: 50000000, // maxAssetSize: 30000000, // assetFilter: function(assetFilename) { // return assetFilename.endsWith('.js'); // } // } // }}
更多细节可参考:webpack中文文档-性能(performance)
二、移除console
如果你应用的是 webpack v5 或以上版本,你不须要装置这个插件。
webpack v5 自带最新的 terser-webpack-plugin
。
如果应用 webpack v4,则必须装置 terser-webpack-plugin
v4 的版本。
2.1 装置依赖
$ npm install terser-webpack-plugin -D
2.2 配置vue.config.js
const TerserPlugin = require('terser-webpack-plugin')module.exports = { chainWebpack: config => { if (process.env.NODE_ENV === 'production') { config.optimization.minimizer([ new TerserPlugin({ test: /\.js(\?.*)?$/i, terserOptions: { compress: { drop_console: true, pure_funcs: ['console.log'] } } }) ]) } else { // disable optimization during tests to speed things up config.optimization.minimize(false) } }}
更多细节可参考:webpack中文文档-TerserWebpackPlugin
❓❓❓如果报错:
Error: optimization.minimizer() no longer supports being passed an array. Either switch to the new syntax (https://github.com/neutrinojs/webpack-chain#config-optimization-minimizers-adding) or downgrade to webpack-chain 4. If using Vue this likely means a Vue plugin has not yet been updated to support Vue CLI 4+.
可重新配置
if (process.env.NODE_ENV === 'production') { config.optimization.minimizer('js') .use(require.resolve('terser-webpack-plugin'), [{ terserOptions: { // 打包删掉正文 comments: true, compress: { drop_console: true, drop_debugger: true // pure_funcs: ["console.log"] } } }]) } else { // disable optimization during tests to speed things up config.optimization.minimize(false) }
❗️扩大:为什么删除生产环境的console?
console.log:向web开发控制台打印一条音讯,罕用来在开发时调试剖析。有时在开发时,须要打印一些对象信息,但公布时却遗记去掉console.log语句,这可能造成内存泄露。
在传递给console.log的对象是不能被垃圾回收 ♻️,因为在代码运行之后须要在开发工具能查看对象信息。所以最好不要在生产环境中console.log任何对象。
实例代码:
<!DOCTYPE html><html lang="en"><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>Leaker</title></head><body> <input type="button" value="click"> <script> !function () { function Leaker() { this.init(); }; Leaker.prototype = { init: function () { this.name = '*'.repeat(1e5); console.log("Leaking an object %o: %o", (new Date()), this); // this对象不能被回收 } }; document.querySelector('input').addEventListener('click', function () { new Leaker(); }, false); }() </script></body></html>
这里联合Chrome的Devtools–>Performance
做一些剖析,操作步骤如下:
- 开启Performance的记录
- 执行CG按钮,创立基准参考线
- 屡次点击【click】按钮,新建Leaker对象
- 执行CG按钮
- 进行记录
能够看出【JS Heap】
线最初没有降回到基准参考线的地位,显然存在没有被回收的内存。如果将代码批改为
// console.log("Leaking an object %o: %o", (new Date()), this);
反复上述的操作步骤,剖析后果如下:
从比照剖析后果可知,console.log打印的对象是不会被垃圾回收器回收的。
因而最好不要在页面中console.log任何对象,包含warn、error等兄弟,这样可能会影响页面的整体性能,特地在生产环境中,这些细节须要特地的关注。
三、压缩图片
3.1 装置依赖
$ npm install terser-webpack-plugin -D
3.2 配置vue.config.js
config.module .rule('images') .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/) .use('image-webpack-loader') .loader('image-webpack-loader') .options({ bypassOnDebug: true, disable: process.env.NODE_ENV !== 'production' });
四、UI库按需加载
对于大多数零碎而言,都会应用一些一些UI组件库,例如Ant Design或者是Element UI,这些组件都是反对按需引入,咱们在应用这些组件时,如果只用到了其中一部分组件,能够配置按需加载,在main.js
中批改代码:
import { Pagination, Icon, Tabs,} from 'ant-design-vue'// import 'ant-design-vue/dist/antd.css' 曾经通过babel引入 这里就不全局引入了Vue.use(Pagination) .use(Icon) .use(Tabs)
而后批改babel.config.js,如下:
"plugins": [ ["import", { "libraryName": "ant-design-vue", "libraryDirectory": "es", "style": "css" }], // `style: true` 会加载 less 文件 ]
这样,组件对应的js和css文件就能够实现按需加载.
五、路由懒加载
对于个别比拟大型的B端管理系统我的项目,基本上都会应用Vue Router来治理路由,这些我的项目波及的页面都比拟多,所以为了避免首屏资源过大,须要采纳路由懒加载资源即Code Splitting,将每个页面的资源进行拆散,这个只需在router.js里配置即可:
// 采纳箭头函数和import进行懒加载解决$ component: () => import('./index.vue')
六、moment优化
6.1 问题形容
依据打包剖析图来看,次要是locale下moment的其余语言包占用体积较大。默认是en的语言包,所以在无需其余语言的状况下,能够间接疏忽掉locale下的文件不打包。
疏忽之前:
疏忽之后:
6.2 解决方案
用webpack自带的IgnorePlugin插件
// vue.config.jsvar webpack = require('webpack')module.exports = { // ...此处省略其余配置 chainWebpack: config => { config.plugin('ignore') .use(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)); //疏忽/moment/locale下的所有文件 } // ...此处省略其余配置}
6.3 解决方案-原理
在webpack编译阶段, 如果引入的文件门路匹配/^./locale$/,则会疏忽这个文件, 也就不会被打包进去。
- 搜寻moment包编译后的文件并未找到齐全匹配/^./locale$/这个正则的引入语句,只有aliasedRequire('./locale/' + name)这条语句和locale相干, 却又和正则匹配不上, 倒是在moment的src源文件中有import ... from './locale'。 然而在moment的package.json中main是指向编译后的文件并不是src文件,这就奇了怪了, 于是debug IgnorePlugin看了一下。
- 图中request真是./locale, 眼瞎了还是webpack的问题?依照dependencies的地位1853行查看moment编译后的文件, 定位到了的确是 aliasedRequire('./locale/' + name), 怎么回事?
- 原来webpack在编译时,遇到require('./locale/' + name)此类表达式时,webpack 会查找目录 './locale/' 下合乎正则表达式 /^.*.$/的文件。因为 name 在编译时还是未知的,webpack 会将每个文件都作为模块引入到 bundle 中, 这就是为什么引入moment之后, 编译完的文件为什么会那么大的起因。
6.4 增加IgnorePlugin后, 须要设置locale怎么办?
- 在增加webpack.IgnorePlugin之后, 文件大小是减小了, 然而在设置moment.locale('zh-cn')之后, format之后的日期依然是英文的,语言没有切换过去。
增加之前:打包之后蕴含momen.js的文件大小
增加之后:打包之后蕴含momen.js的文件大小
- 性能缺失必定是不能承受的, 怎么办?怎么办?
在moment文档上也提供了解决方案, moment-locales-webpack-plugin
$ npm install --save-dev moment-locales-webpack-plugin
// vue.config.jsnew MomentLocalesPlugin({ localesToKeep: ['zh-cn'],}) // const MomentLocalesPlugin = require('moment-locales-webpack-plugin') // config.plugin('moment-locales-webpack-plugin').use( // new MomentLocalesPlugin({ // localesToKeep: ['zh-cn'] // }) // );
- moment默认locale是en,它必然会被打包进去, 如果须要配置其余语言,能够通过localesToKeep来配置, 其余没用到的语言包也就不会被打包进去了。
vue.config.js配置如下代码
config.plugin('moment-locales-webpack-plugin').use( new MomentLocalesPlugin({ localesToKeep: ['es-us', 'ru', 'cs', 'hi', 'uk'] }) );
能够看到打包的时候都被打包删除掉了!
![[图片上传中...(下载 (3).png-2486c4-1624615311186-0)]
](https://upload-images.jianshu.io/upload_images/11846892-f582e7cb6b75a6c6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
6.5 moment-locales-webpack-plugin原理剖析
- 如果没有配置option, 用IgnorePlugin疏忽所有语言包(en除外)
如果设置option, 用 ContextReplacementPlugin插件设置webpack在编译阶段的查找规定,即查找指定的locale。
...if (localesToKeep.length > 0) { var regExpPatterns = localesToKeep.map(function(localeName) { return localeName + '(\\.js)?'; }); return new ContextReplacementPlugin( /moment[\/\\]locale/, new RegExp('(' + regExpPatterns.join('|') + ')$') // 配置webpack编译阶段的查找规定, 即指定语言包 );} else { return new IgnorePlugin(/^\.\/locale$/, /moment$/);}...
七、webpack反复打包同名依赖包
最近装置了webpack-bundle-analyzer插件来剖析打包形成,发现有一些包被反复的打包了屡次,这样会让构建进去的包分外的臃肿。这次要是因为咱们往往援用了很多的第三方包,而很多工具类的库也会被别的包间接的依赖,所以就导致了反复打包的景象,例如下图的bn.js。
7.1 解决方案
在webpack的resolve上面增加如下配置:
// 第一种办法module.exports = { resolve: { alias:{ 'bn.js': path.resolve(process.cwd(), 'node_modules', 'bn.js') } }};// 第二种办法module.exports = { configureWebpack:{ resolve:{ alias:{ 'bn.js': path.resolve(process.cwd(), 'node_modules', 'bn.js') } } }};// 第三种办法const path = require('path');//引入path模块function resolve(dir){ return path.join(__dirname,dir)//path.join(__dirname)设置绝对路径}module.exports={ chainWebpack: config =>{ config.resolve.alias .set("@", resolve("src")) }}
resolve.alias的作用其实就是增加包的别名并强行指定援用对立门路,配置完的成果如下,只能看到一个bn.js了。
优化之后
优化之前
八、有抉择的应用prefetch和preload
prefetch
<link rel="prefetch" ></link>
这段代码通知浏览器,这段资源将会在将来某个导航或者性能要用到,然而本资源的下载程序权重比拟低。也就是说prefetch通常用于减速下一次导航,而不是本次的。preload
<link rel="preload" ></link>
preload通常用于本页面要用到的要害资源,包含要害js、字体、css文件。preload将会把资源得下载程序权重进步,使得要害数据提前下载好,优化页面关上速度。
在应用Vue Cli生成的我的项目里,当咱们配置了路由懒加载后,默认状况下webpack在构建时会对所有的懒加载资源进行prefetch和preload,所以当你关上首页时,会看到大量的prefetch和preload申请,如下图:
// 禁止prefetch和preloadchainWebpack: (config) => { config.plugins.delete('prefetch') config.plugins.delete('preload')}// 有抉择的prefetch和preloadconfig.plugin('prefetch').tap(options => { options[0].fileBlacklist = options[0].fileBlacklist || [] options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/) return options})
下面代码批改vue.config.js的chainWebpack来增加配置。
总结:功败垂成✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️✌️
参考链接:
https://segmentfault.com/a/1190000012295395
https://zhuanlan.zhihu.com/p/362547907
https://www.jianshu.com/p/4f8f36944a46
https://juejin.cn/post/6844903987632685063
https://blog.csdn.net/u010352770/article/details/101538528