vuecli3+webpack4优化实践(删除console.log和配置dllPlugin)
本文主要介紹如何在vuecli3生成的項目中,打包輸出時刪除console.log和使用dllplugin,并記錄了配置過程中踩到的坑。 (本人水平有限~希望大家多多指出有誤的地方)
一、生產環境中刪除console.log
在開發代碼中寫的console.log,可以通過配置webpack4中的terser-webpack-plugin插件達成目的,compress參數配置如下:
module.exports = {optimization: {minimizer: [new TerserPlugin({terserOptions: {compress: {warnings: false,drop_console: true,drop_debugger: true,pure_funcs: ['console.log']},},}),],}, }; 復制代碼而@vue/cli-service的配置源碼也是使用了terser-webpack-plugin插件進行Tree Shaking,以下是@vue/cli-service/prod.js的源碼
module.exports = (api, options) => {api.chainWebpack(webpackConfig => {if (process.env.NODE_ENV === 'production') {const isLegacyBundle = process.env.VUE_CLI_MODERN_MODE && !process.env.VUE_CLI_MODERN_BUILDconst getAssetPath = require('../util/getAssetPath')const filename = getAssetPath(options,`js/[name]${isLegacyBundle ? `-legacy` : ``}${options.filenameHashing ? '.[contenthash:8]' : ''}.js`)webpackConfig.mode('production').devtool(options.productionSourceMap ? 'source-map' : false).output.filename(filename).chunkFilename(filename)// keep module.id stable when vendor modules does not changewebpackConfig.plugin('hash-module-ids').use(require('webpack/lib/HashedModuleIdsPlugin'), [{hashDigest: 'hex'}])// disable optimization during tests to speed things upif (process.env.VUE_CLI_TEST) {webpackConfig.optimization.minimize(false)} else {const TerserPlugin = require('terser-webpack-plugin')const terserOptions = require('./terserOptions')webpackConfig.optimization.minimizer([new TerserPlugin(terserOptions(options))])}}}) } 復制代碼在 vue.config.js 中的 configureWebpack 選項提供一個對象會被 webpack-merge 合并入最終的 webpack 配置,因此vue-cli3構建的項目中只需要修改terserOptions即可,vue.config.js配置如下:
module.exports = {publicPath: '/',outputDir: 'dist',devServer: {port: 8080,https: false,hotOnly: true,disableHostCheck: true,open: true,},productionSourceMap: false, // 生產打包時不輸出map文件,增加打包速度configureWebpack: config => {if (process.env.NODE_ENV === 'production') {config.optimization.minimizer[0].options.terserOptions.compress.warnings = falseconfig.optimization.minimizer[0].options.terserOptions.compress.drop_console = trueconfig.optimization.minimizer[0].options.terserOptions.compress.drop_debugger = trueconfig.optimization.minimizer[0].options.terserOptions.compress.pure_funcs = ['console.log']}} } 復制代碼配置完成后使用 vue inspect --mode=production > output.js 命令審查項目的 webpack 配置,optimization.minimizer的輸出如下:
optimization: {minimizer: [{options: {test: /\.m?js(\?.*)?$/i,chunkFilter: () => true,warningsFilter: () => true,extractComments: false,sourceMap: false,cache: true,cacheKeys: defaultCacheKeys => defaultCacheKeys,parallel: true,include: undefined,exclude: undefined,minify: undefined,terserOptions: {output: {comments: /^\**!|@preserve|@license|@cc_on/i},compress: {arrows: false,collapse_vars: false,comparisons: false,computed_props: false,hoist_funs: false,hoist_props: false,hoist_vars: false,inline: false,loops: false,negate_iife: false,properties: false,reduce_funcs: false,reduce_vars: false,switches: false,toplevel: false,typeofs: false,booleans: true,if_return: true,sequences: true,unused: true,conditionals: true,dead_code: true,evaluate: true,warnings: false, drop_console: true, drop_debugger: true, pure_funcs: ['console.log']},mangle: {safari10: true}}}}], } 復制代碼到此完成刪除console.log的配置,接下來記錄一下我踩到的坑~
坑1:在vue.config.js中直接使用terser-webpack-plugin后,通過vue inpect審查發現新增的compress參數并沒有直接進入原有的terserOptions,而是minimizer數組新增了一個對象。這樣導致vue-cli原有的terser-webpack-plugin配置失效。打包會以cache和parallel為false的配置下進行打包輸出,打包速度變慢,因此后來采取直接修改terserOptions。
minimizer數組新增了一個對象:
options: {test: /\.m?js(\?.*)?$/i,chunkFilter: () => true,warningsFilter: () => true,extractComments: false,sourceMap: false,cache: false, cacheKeys: defaultCacheKeys => defaultCacheKeys,parallel: false,include: undefined,exclude: undefined,minify: undefined,terserOptions: {output: {comments: /^\**!|@preserve|@license|@cc_on/i},compress: {warnings: false,drop_console: true,drop_debugger: true,pure_funcs: ['console.log']}} } 復制代碼坑2(未解決):在給.eslintrc.js的rules配置了no-console的情況下,修改代碼后的首次打包eslint-loader總會在終端上報 error: Unexpected console statement (no-console),雖然打包過程中報錯,但是最終的輸出代碼是沒有console.log的;(使用babel-plugin-transform-remove-console刪除console.log也會出現這種情況)
查看@vue/cli-plugin-eslint的源碼發現eslint的cache屬性為true,所以再次打包就不會對未修改的文件進行檢測。
Eslint Node.js API對cache參數解釋如下:
cache - Operate only on changed files (default: false). Corresponds to --cache.
cli-plugin-eslint使用eslint-loader的關鍵代碼如下:
api.chainWebpack(webpackConfig => {webpackConfig.resolveLoader.modules.prepend(path.join(__dirname, 'node_modules'))webpackConfig.module.rule('eslint').pre().exclude.add(/node_modules/).add(require('path').dirname(require.resolve('@vue/cli-service'))).end().test(/\.(vue|(j|t)sx?)$/).use('eslint-loader').loader('eslint-loader').options({extensions,cache: true, cacheIdentifier,emitWarning: options.lintOnSave !== 'error',emitError: options.lintOnSave === 'error',eslintPath: resolveModule('eslint', cwd) || require.resolve('eslint'),formatter:loadModule('eslint/lib/formatters/codeframe', cwd, true) ||require('eslint/lib/formatters/codeframe')})}) 復制代碼如果要終端不輸出eslint的錯誤,可以在vue.config.js配置lintOnSave: process.env.NODE_ENV !== 'production'生產環境構建時禁用,但是這樣與在eslintrc.js的rules中配置'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off'的目的自相矛盾。
那么是否有辦法讓eslint-loader在terser-webpack-plugin或者babel-plugin-transform-remove-console之后進行檢測呢?還是說配置了刪除console.log就沒必要配置'no-console'呢?希望有大神能回答我這個疑惑!
二、使用dllPlugin優化打包速度
網上已經有很多文章介紹dllPlugin的使用方法,這里就不介紹dllPlugin的詳細配置說明了。本文只介紹一下針對vue-cli3項目使用webapck-chain方式的配置代碼,所以就直接貼代碼啦~
新增webpack.dll.config.js,代碼如下:
const path = require('path') const CleanWebpackPlugin = require('clean-webpack-plugin') const webpack = require('webpack')module.exports = {mode: 'production',entry: {vendor: ['vue/dist/vue.runtime.esm.js', 'vuex', 'vue-router', 'element-ui'],util: ['lodash']},output: {filename: '[name].dll.js',path: path.resolve(__dirname, 'dll'),library: 'dll_[name]'},plugins: [new CleanWebpackPlugin(), // clean-wepback-plugin目前已經更新到2.0.0,不需要傳參數pathnew webpack.DllPlugin({name: 'dll_[name]',path: path.join(__dirname, 'dll', '[name].manifest.json'),context: __dirname})] } 復制代碼在vue.config.js添加DllReferencePlugin,最終代碼如下:
const webpack = require('webpack') const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin') const path = require('path')const dllReference = (config) => {config.plugin('vendorDll').use(webpack.DllReferencePlugin, [{context: __dirname,manifest: require('./dll/vendor.manifest.json')}])config.plugin('utilDll').use(webpack.DllReferencePlugin, [{context: __dirname,manifest: require('./dll/util.manifest.json')}])config.plugin('addAssetHtml').use(AddAssetHtmlPlugin, [[{filepath: require.resolve(path.resolve(__dirname, 'dll/vendor.dll.js')),outputPath: 'dll',publicPath: '/dll'},{filepath: require.resolve(path.resolve(__dirname, 'dll/util.dll.js')),outputPath: 'dll',publicPath: '/dll'}]]).after('html') }module.exports = {publicPath: '/',outputDir: 'dist',devServer: {port: 8080,https: false,hotOnly: true,disableHostCheck: true,open: true,},productionSourceMap: false, // 生產打包時不輸出map文件,增加打包速度chainWebpack: config => {if (process.env.NODE_ENV === 'production') {dllReference(config)}},configureWebpack: config => {if (process.env.NODE_ENV === 'production') {config.optimization.minimizer[0].options.terserOptions.compress.warnings = falseconfig.optimization.minimizer[0].options.terserOptions.compress.drop_console = trueconfig.optimization.minimizer[0].options.terserOptions.compress.drop_debugger = trueconfig.optimization.minimizer[0].options.terserOptions.compress.pure_funcs = ['console.log']}} } 復制代碼有3個地方需要說明一下:
1、webpack.dll.config.js文件中的entry.vendor使用'vue/dist/vue.runtime.esm.js'作為vue的入口,是根據vue inspect > output.js的文件中resolve.alias決定的;(vue.runtime.esm.js還是vue.esm.js取決于vue create構建時的選擇)
resolve: {alias: {'@': '/Users/saki_bc/bccgithub/vue-webpack-demo/src',vue$: 'vue/dist/vue.runtime.esm.js'}, } 復制代碼2、在開發環境中不使用dllPlugin是因為chrome的vue devtool是不能檢測壓縮后的vue源碼,使得沒辦法用vue devtool觀察vue項目的組件和數據狀態;
3、add-asset-html-webpack-plugin插件必須在html-webpack-plugin之后使用,因此這里要用webpack-chain來進行配置;至于為什么'html'代表html-webpack-plugin,是因為@vue/cli-servide/lib/config/app.js里是用plugin('html')來映射的,關鍵源碼片段如下:
const HTMLPlugin = require('html-webpack-plugin') webpackConfig.plugin('html').use(HTMLPlugin, [htmlOptions]) 復制代碼4、這里不使用在index.html里添加script標簽的方式引入dll文件,是因為當vue路由使用history模式,并且路由配置首頁重定向到其他url的情況下,在首頁刷新頁面后dll文件會以重定向后的url的根目錄引用,導致報錯找不到dll文件。 如:dll的正確引用情況是http://www.xxx.com/vendor.dll.js,刷新重定向后變成 http://www.xxx.com/xxx/vendor.dll.js;即使在index.html使用絕對路徑也是會出現這樣的情況,目前還不知道是不是html-webpack-plugin的bug;
結語
這次優化實踐仍然存在不少疑惑和且考慮的地方,webpack的更新發展也越來越快,vue-cli使用webpack-chain作為核心方式也增加了不少學習成本,接下來還需要閱讀相關源碼,發現項目中配置不合理的地方~
也希望各位大家能分享一下使用webpack4過程中踩到的坑~
相關文檔
webpack-chain文檔
add-asset-html-webpack-plugin文檔
vue-cli配置源碼
轉載于:https://juejin.im/post/5c84b709e51d4578ca71dde4
總結
以上是生活随笔為你收集整理的vuecli3+webpack4优化实践(删除console.log和配置dllPlugin)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浪潮服务器测试文档,ESXI6.7注入浪
- 下一篇: 华硕服务器显示模块,华硕远程管理模块 A