記一次webpack4+react+antd項目優化打包文件體積的過程

背景

  最近本身整了一個基於webpack4和react開發的博客demo項目,一路整下來磕磕碰碰但也實現了功能,就準備發到阿里雲上面去看看,借用了同事的阿里雲小水管服務器,配置完成以後首頁加載花了十幾秒,打開控制檯network查看資源,打包的js體積有將近6M,及其影響訪問體驗,因而就開始了優化的路。javascript

 

緣由和解決方法

  在webpack的配置文件中,對公共js作了抽取,分別會打包出react-verdor.js和antd-verdor.js,優化前的antd-verdor足足有4m大小,估計是把antd組件所有加載下來了,順着這個思路查找解決方案。css

optimization.splitChunks: { chunks: 'all', cacheGroups: { "react-vendor": { test: (module) => (/react/.test(module.context) || /redux/.test(module.context) || /classnames/.test(module.context) || /prop-types/.test(module.context)), priority: 3, reuseExistingChunk: false }, "antd-vendor": { // || /[\\/]node_modules[\\/]/.test(module.context)
          test: (module) => (/antd/.test(module.context)), priority: 2, reuseExistingChunk: false }, } }

 

antd官方推薦按需加載,我開始也是根據官方推薦作的,在.babelrc作以下配置html

{ "plugins": [ ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css"
 }] ] }

不過事實是打包文件有4M,那確定是配置錯了,繼續查找別的配置方法,終於找到一個管用的,在webpack配置文件中作以下配置(本質上仍是本身太菜,不理解.babelrc)java

{ test: /\.(js|jsx)/, use: { loader:'babel-loader', options: { presets: ["env", "react", 'stage-0'], plugins: [ ['import', [{ libraryName: 'antd', style: true }]] ] } }, include: resolve('src') },

配置完成後進行打包,體積明顯變小了,antd-vendor.js的大小變成200多K。antd按需引入的問題解決後,看別的文件仍是挺大的,因而決定把REACT中的組件也作成按需加載的方式,拆分更多的js出來,這裏使用了react-loadable實現,拆分完成以後繼續打包,發現部分子js的體積明顯過大,繼續查找緣由。node

在瀏覽器中跳轉到對應的頁面查看加載的js,查看js文件中的註釋,發現有兩個第三方插件被我所有import進來了了,其實我永不到那麼多,分別是react

crypto和highlightjs,crypto是一個加密算法庫,提供md5和sha 256等經典加密算法,我這個項目中只在登陸時用到了一次加密密碼,而那個頁面對應的js有500多k,問題顯而易見,經過下面這個修改把問題解決了
//修改前
 import crypto from ('crypto') module.exports = { MD5_SUFFIX: 'sskjtxdywdddzyjknn', md5: function (pwd) { let md5 = crypto.createHash('md5'); return md5.update(pwd).digest('hex') }, } //修改後
 const md5 = require("crypto-js/md5") module.exports = { MD5_SUFFIX: 'sskjtxdywdddzyjknn', md5: function (pwd) { return md5.update(pwd).digest('hex') }, }

 

解決引入highlightjs後文件的過大的的思路和上面相似,我選擇了直接加載hightlightjs保留核心功能後的壓縮代碼,size只有30k,而以前的默認import後的size有將近1Mwebpack

 

還能優化嗎

前面發現的問題不外乎是由第三方庫形成的,解決了前面的問題後,此時的js體積已經從以前的6M降到1.8M了。那麼還能繼續經過webpack配置來優化打包後的文件大小嗎?抱着這個疑問繼續查找解決方案,最後決定試一試這個文章說明的方法 web

https://zhuanlan.zhihu.com/p/36280323算法

一頓操做下來打包出來的文件只減少了30K,最後再放上配置文件js的完整代碼,但願能有大佬提出建議,很是json

//webpack.base.config.js
 module.exports = { /*entry: { app: './src/index.jsx', },*/ output: { publicPath: process.env.NODE_ENV === config.prod.ENV ? config.prod.assetsPublicPath : config.dev.assetsPublicPath }, resolve: { extensions: ['.js', '.jsx', '.json'], alias: { '@components': path.resolve(__dirname, '../src/components'), '@': resolve('src'), } }, module: { rules: [ { test: /\.(js|jsx)/, use: { loader: 'babel-loader', options: { presets: ["env", "react", 'stage-0'], plugins: [ ['import', [{ libraryName: 'antd', style: true }]] ] } }, include: resolve('src') }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: assetsPath('img/[name].[ext]') } }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: assetsPath('media/[name].[ext]') } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: assetsPath('font/[name].[ext]') } }, { test: /\.css$/, use: [{ loader: 'style-loader' }, { loader: "css-loader", options: { name: "[path][name].[ext]", } }] }, { test: /\.less$/, exclude: /node_modules/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'less-loader', ] }, { test: /\.less$/, include: /node_modules/, use: [ MiniCssExtractPlugin.loader, 'css-loader', { 'loader': 'less-loader', options: { javascriptEnabled: true } } ] } ] }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].css' }), new LodashModuleReplacementPlugin ] } //webpack.prod.config.js
 const webpackConfig = merge(baseWebpackConfig, { entry: { app: './src/index.jsx', }, mode: 'production', devtool: false, output: { path: config.prod.assetsRoot, filename: assetsPath('js/[name].[chunkhash].js'), chunkFilename: assetsPath('js/[name].[chunkhash].js'), }, plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', title: pkg.description, template: path.resolve(__dirname, '../index.html'), inject: true, minify: { removeComments: true, collapseWhitespace: true, removeRedundantAttributes: true, useShortDoctype: true, removeEmptyAttributes: true, removeStyleLinkTypeAttributes: true, keepClosingSlash: true, minifyJS: true, minifyCSS: true, minifyURLs: true, }, }), new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../src/static'), to: config.prod.assetsSubDirectory, } ]) ], optimization: { minimizer: [ new UglifyJsPlugin(), new OptimizeCSSAssetsPlugin(), new TerserPlugin({ terserOptions: { parse: { ecma: 8, }, compress: { ecma: 5, warnings: false, comparisons: false, inline: 2, }, mangle: { safari10: true, }, output: { ecma: 5, comments: false, ascii_only: true, }, }, // Use multi-process parallel running to improve the build speed
        // Default number of concurrent runs: os.cpus().length - 1
        parallel: true, // Enable file caching
        cache: true, sourceMap: false, }), ], splitChunks: { chunks: 'all', cacheGroups: { "react-vendor": { test: (module) => (/react/.test(module.context) || /redux/.test(module.context) || /classnames/.test(module.context) || /prop-types/.test(module.context)), priority: 3, reuseExistingChunk: false }, "antd-vendor": { // || /[\\/]node_modules[\\/]/.test(module.context)
          test: (module) => (/antd/.test(module.context)), priority: 2, reuseExistingChunk: false }, } } } })

 

感謝!

相關文章
相關標籤/搜索