前端工程webpack打包优化方法
为提高前端工程webpack打包速度,对工程进行改造
第一部分:vue-cli2工程
可以采用js分包+压缩混淆升级+CDN加速+gzip压缩等手段进行加速
(1)分包,在webpack的配置中添加
module.exports = { externals: { vue: \'Vue\', moment: \'moment\', rxjs: \'Rx\', ramda: \'R\', \'vue-router\': \'VueRouter\', jquery: \'jQuery\', \'element-ui\': \'ELEMENT\', axios: \'axios\', qs: \'Qs\', vuex: \'Vuex\', \'echarts\': \'echarts\', lodash: { //如果我们的库运行在Node.js环境中,import _ from \'lodash\'等价于const _ = require(\'lodash\') commonjs: "lodash", commonjs2: "lodash", //同上 amd: "lodash", //如果我们的库使用require.js等加载,等价于 define(["lodash"], factory); root: "_", //如果我们的库在浏览器中使用,需要提供一个全局的变量‘_’,等价于 var _ = (window._) or (_); } }, }
(2)分包后,这些被排除的包将不会被打包进入vendor中去,那么我们就必须使用CDN来提供这些包的功能
在入口文件index.html中添加对应的js文件
使用CDN的优点:
1.可以充分利用客户端缓存,大大减少每次webpack打包的vendor的体积,提高打包速度
2.每次工程迭代时,这些包将不需要更新,也不需要客户端重新加载3
3.用户在第一次加载之后,后面的版本迭代大部分文件将直接读缓存,不需要再次加载外部依赖文件
缺点:工程部署必须能够连接外网,内网部署的工程将不能够使用CDN,可以通过在内网维护一个自己的简单的CDN库来解决
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link crossorigin="anonymous" href="https://lib.baomitu.com/element-ui/2.3.9/theme-chalk/index.css" rel="stylesheet"> </head> <body> <div ></div> <!-- built files will be auto injected --> <script src="https://lib.baomitu.com/jquery/3.2.1/jquery.min.js"></script> <script src="https://lib.baomitu.com/vue/2.5.2/vue.js"></script> <script src="https://lib.baomitu.com/vue-router/2.7.0/vue-router.min.js"></script> <script src="https://lib.baomitu.com/moment.js/2.18.1/moment.min.js"></script> <script src="https://lib.baomitu.com/moment.js/2.18.1/locale/zh-cn.js"></script> <script src="https://lib.baomitu.com/rxjs/5.4.3/Rx.min.js"></script> <script src="https://lib.baomitu.com/ramda/0.24.1/ramda.min.js"></script> <script crossorigin="anonymous" src="https://lib.baomitu.com/lodash.js/4.17.0/lodash.min.js"></script> <script crossorigin="anonymous" src="https://lib.baomitu.com/element-ui/2.3.9/index.js"></script> <script crossorigin="anonymous" src="https://lib.baomitu.com/axios/0.16.2/axios.min.js"></script> <script crossorigin="anonymous" src="https://lib.baomitu.com/vuex/3.0.1/vuex.min.js"></script> <script crossorigin="anonymous" src="https://lib.baomitu.com/qs/6.5.1/qs.min.js"></script> <script crossorigin="anonymous" src="https://lib.baomitu.com/xlsx/0.14.2/xlsx.min.js"></script> </body> </html>
(3)使用uglifyjs-webpack-plugin,新版的uglifyjs-webpack-plugin能够支持es6语法
在webpack.prod.config.js中添加
const UglifyJsPlugin = require(\'uglifyjs-webpack-plugin\') module.exports= { // 其他配置..., plugins:[ new UglifyJsPlugin({ cache: true, uglifyOptions: { compress: { drop_debugger: true, drop_console: true, }, ecma: 6, output: { comments: false, beautify: false, }, warnings: false, }, sourceMap: false, parallel: true, }), ] }
(4)使用开发环境资源缓存,提高第二次及以后的启动速度
在webpack.dev.conf.js中,添加配置
const HardSourceWebpackPlugin = require(\'hard-source-webpack-plugin\') module.exports = { // ...其他配置 plugins: [ // 缓存加速二次构建速度 new HardSourceWebpackPlugin({ // Either an absolute path or relative to webpack\'s options.context. // 设置缓存在磁盘中存放的路径 cacheDirectory: \'./../disk/.cache/hard-source/[confighash]\', // Either a string of object hash function given a webpack config. recordsPath: \'./../disk/.cache/hard-source/[confighash]/records.json\', configHash: function (webpackConfig) { // node-object-hash on npm can be used to build this. return require(\'node-object-hash\')({ sort: false }).hash(webpackConfig); }, // An object. info: { // \'none\' or \'test\'. mode: \'none\', // \'debug\', \'log\', \'info\', \'warn\', or \'error\'. level: \'debug\', }, // Clean up large, old caches automatically. cachePrune: { // Caches younger than `maxAge` are not considered for deletion. They must // be at least this (default: 2 days) old in milliseconds. maxAge: 2 * 24 * 60 * 60 * 1000, // All caches together must be larger than `sizeThreshold` before any // caches will be deleted. Together they must be at least this // (default: 50 MB) big in bytes. sizeThreshold: 100 * 1024 * 1024 }, }), ] }
第二部分:vue/cli3+版本
vue/cli3+版本里面的webpack配置作者进行了内置
我们需要在vue.config.js中进行配置
(1)
const path = require(\'path\') const webpack = require(\'webpack\') const AddAssetHtmlPlugin = require(\'add-asset-html-webpack-plugin\') const HardSourceWebpackPlugin = require(\'hard-source-webpack-plugin\') // 拼接路径 function resolve (dir) { return path.join(__dirname, dir) } const baseUrlObject = { development: \'\', beta: \'//fezz.wormpex.com/ripei-fe-web\', prod: \'//fezz.blibee.com/ripei-fe-web\', production: \'//fezz.blibee.com/ripei-fe-web\' } const env = process.env.NODE_ENV || \'production\' // 基础路径 注意发布到生产环境之前要先修改这里 const baseUrl = baseUrlObject[env] || process.env.VUE_APP_BASE_URL const IS_DEV = process.env.VUE_APP_NODE_ENV === \'development\' console.log(process.env.NODE_ENV) console.log(process.env.VUE_APP_BASE_URL) console.log(baseUrl) // 用于开发环境下,缓存第一次编译的文件,提高二次构建速度 const devPlugins = [ // 缓存加速二次构建速度 new HardSourceWebpackPlugin({ // Either an absolute path or relative to webpack\'s options.context. // 设置缓存在磁盘中存放的路径 cacheDirectory: \'./../disk/.cache/hard-source/[confighash]\', // Either a string of object hash function given a webpack config. recordsPath: \'./../disk/.cache/hard-source/[confighash]/records.json\', configHash: function (webpackConfig) { // node-object-hash on npm can be used to build this. return require(\'node-object-hash\')({ sort: false }).hash(webpackConfig); }, // An object. info: { // \'none\' or \'test\'. mode: \'none\', // \'debug\', \'log\', \'info\', \'warn\', or \'error\'. level: \'debug\', }, // Clean up large, old caches automatically. cachePrune: { // Caches younger than `maxAge` are not considered for deletion. They must // be at least this (default: 2 days) old in milliseconds. maxAge: 4 * 24 * 60 * 60 * 1000, // All caches together must be larger than `sizeThreshold` before any // caches will be deleted. Together they must be at least this // (default: 50 MB) big in bytes. sizeThreshold: 100 * 1024 * 1024 }, }), new HardSourceWebpackPlugin.ExcludeModulePlugin([ { test: /mini-css-extract-plugin[\\/]dist[\\/]loader/ } ]) ] const configPlugins = [ new webpack.ProvidePlugin({ $: \'jquery\', jQuery: \'jquery\', \'windows.jQuery\': \'jquery\' }), new webpack.DllReferencePlugin({ context: process.cwd(), manifest: require(\'./public/vendor/vendor-manifest.json\') }), // 将 dll 注入到 生成的 html 模板中 new AddAssetHtmlPlugin({ // dll文件位置 filepath: path.resolve(__dirname, \'./public/vendor/*.js\'), // dll 引用路径 publicPath: `${baseUrl}/vendor`, // dll最终输出的目录 outputPath: \'./vendor\' }) ] module.exports = { publicPath: baseUrl, // 根据你的实际情况更改这里 lintOnSave: true, configureWebpack: { // 引入jquery // externals: { // 引入百度地圖 // \'BMap\': \'BMap\' // }, plugins: IS_DEV ? configPlugins.concat(devPlugins) : configPlugins }, devServer: { https: false, publicPath: baseUrl, // 和 baseUrl 保持一致 // 代理设置 proxy: { } }, // webpack 设置 chainWebpack: config => { // 修复HMR config.resolve.symlinks(true) // svg const svgRule = config.module.rule(\'svg\') svgRule.uses.clear() svgRule .include .add(resolve(\'src/assets/svg-icons/icons\')) .end() .use(\'svg-sprite-loader\') .loader(\'svg-sprite-loader\') .options({ symbolId: \'d2-[name]\' }) .end() // image exclude const imagesRule = config.module.rule(\'images\') imagesRule .test(/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/) .exclude .add(resolve(\'src/assets/svg-icons/icons\')) .end() // 重新设置 alias config.resolve.alias .set(\'@\', resolve(\'src\')) // babel-polyfill 加入 entry const entry = config.entry(\'app\') entry .add(\'babel-polyfill\') .end() } }
(2)使用DllPlugin进行包的拆分
在根目录下创建webpack.dll.conf.js
/** * 配置vue-cli4工程的DllPlugins,用以减少热更新和打包时的文件数量,提高热更新和打包的速度 * 参考文献:https://blog.csdn.net/DongFuPanda/article/details/104866788 * 步骤 */ const path = require(\'path\') const webpack = require(\'webpack\') const { CleanWebpackPlugin } = require(\'clean-webpack-plugin\') // dll文件存放的目录 const dllPath = \'public/vendor\' module.exports = { entry: { // 需要提取的库文件 vendor: [\'vue\', \'vue-router\', \'vuex\', \'axios\', \'jquery\', \'moment\', \'ramda\', \'element-ui\', \'core-js\', \'lodash\'] }, output: { path: path.join(__dirname, dllPath), filename: \'[name].[hash].dll.js\', // vendor.dll.js中暴露出的全局变量名 // 保持与 webpack.DllPlugin 中名称一致 library: \'[name]_[hash]\' }, plugins: [ // 清除之前的dll文件 new CleanWebpackPlugin(), // 设置环境变量 new webpack.DefinePlugin({ \'process.env\': { NODE_ENV: JSON.stringify(\'production\') } }), // manifest.json 描述动态链接库包含了哪些内容 new webpack.DllPlugin({ path: path.join(__dirname, dllPath, \'[name]-manifest.json\'), // 保持与 output.library 中名称一致 name: \'[name]_[hash]\', context: process.cwd() }) ] }
在package.json中添加
"scripts": { "start": "vue-cli-service serve --open --mode development", "serve": "vue-cli-service serve --open --mode development", "build": "vue-cli-service build", "beta": "vue-cli-service build --mode beta", "lint": "vue-cli-service lint", "dll": "webpack -p --progress --config ./webpack.dll.conf.js" },
使用webpack-bundle-analyzer 进行代码打包体积分析
const BundleAnalyzerPlugin = require(\'webpack-bundle-analyzer\').BundleAnalyzerPlugin module.exports = { // ...其他配置 plugins:[ // new BundleAnalyzerPlugin() ] }
- 上一篇 »利用webpack搭建的前端工程化环境
- 下一篇 »常用的webpack优化方法