最近接手在作一個chrom瀏覽器插件的項目,開發過程當中發現項目打包的時間很長,足足有30多秒,這是讓人很難接受的,並且構建的顯示了幾條包體積過大的提示信息:
[image:073CB50B-06EB-4779-84FE-D11087B12BD7-47140-0000087E666F3C39/1967FDC4-F9FA-44F3-922E-5406A46415FB.png]html
能夠看到,打包後有三個包超過了建議的體積,是什麼致使了打包時間長和包的體積過大呢?下面經過一些具體方法來分析緣由和解決這個問題。前端
爲了分析是什麼致使構建包爲何會變得這麼大,能夠安裝 webpack-bundle-analyzer 插件,經過它能夠直觀地查看構建包中全部項目的大小。vue
npm install —save-dev webpack-bundle-analyzerreact
對應的須要在webpack 中作以下配置:
webpack.config.jsjquery
const { BundleAnalyzerPlugin } = require(‘webpack-bundle-analyzer’) plugins: [ ..., new BundleAnalyzerPlugin({ analyzerPort: 8081, }), ]
配置完成後再次運行構建 npm start,瀏覽器會自動打開 127.0.0.1:8001,在網頁上能夠看到每一個依賴的詳細信息。從圖中能夠找出影響體積的罪魁禍首有:
jquery
Moment
xlsx
mammoth
html2canvas
dexiewebpack
那麼這些體積龐大的依賴庫都須要打到項目的運行包裏面嗎?固然不是的。那咱們逐步來優化這些依賴。git
momentgithub
[image:A18EEFD0-B8CD-441D-BE54-9B9CEB44F4A5-47140-000008A7697860CB/Screen Shot 2019-08-05 at 11.12.01 AM.png]web
moment 在包中佔用了 545k 的體積,查看分析圖能夠看到,庫文件中主要是各類用於支持語言版本的的locale文件,可是項目中並不須要這部分功能,所以這部分數據是應該優化的。npm
[image:88A706F4-B93A-4E35-B0F1-1B01CA3F9E9B-47140-000008AD50A28B13/Screen Shot 2019-08-05 at 11.13.07 AM.png]
查看項目中引入moment 的方式
import moment form ‘moment’;
這樣會將整個 moment 包都導入到文件中,爲了不導入沒必要要的文件,能夠這麼寫:
import moment from ‘moment/src/moment’
可是這麼寫會有個問題,若是項目中有新成員加入,極大的可能他不會這樣寫,而是像原來同樣導入了整個 moment 包,所以爲了不這樣的問題,能夠考慮在 webpack 中建立一個別名,這樣每次導入 moment 的時候就默認只導入文件夾下面的 moment.js 文件了,以下:
Alias: { moment: 'moment/src/moment', }
好了,從新啓動服務進行打包,報錯提示沒法找到 ./locale,
[image:BBCBFA75-E5E1-4110-A22B-8D98C3D110BD-47140-00000DA8C3052930/Screen Shot 2019-08-05 at 1.31.58 PM.png]
查看 moment 的官方 issue 發現這是一個存在已久的問題:moment.js 老是會加載 locales,還假定 locales 存在。你不能讓 moment 只加載日期操做函數。
[image:795841EB-7214-4530-B2F1-7804B23DE6C7-47934-0000ADDDAF534A3D/Screen Shot 2019-08-14 at 2.24.15 PM.png]
官方提供的解決方案是把 package.json 中的 Moment 的版本改爲 2.18.1,不過在 Stack Overflow 上找到了另外一種解決方案,就是直接忽略這個報錯:
[image:39119BD5-E067-47F0-B6FD-5760F4417818-47934-0000AE002AE61EFB/69AE8969-0014-40E4-AA34-955676B4D3AD.png]
嘗試一下:
plugins:[ new Webpack.IgnorePlugin(/\.\/locale/,/moment/), //moment這個庫中,若是引用了./locale/目錄的內容,就忽略掉,不會打包進去 ]
按照上面的方法,減少了moment的打包體積,同時也避免了報錯,可是若是項目中須要用到語言包該怎麼辦呢?很簡單,手動引入一下就能夠了:
import moment from 'moment' //設置語言 //手動引入所須要的語言包 import 'moment/locale/zh-cn'; moment.locale('zh-cn'); let r = moment().endOf('day').fromNow(); console.log(r);
Ok,這麼一來可以顯示中文,又把沒必要要的語言包都忽略打包了,從新構建一下,看一下體積有沒有變化:
[image:B998DDA8-62AD-4FD1-9953-A03BDE08310D-47140-00000DF75A4BFE04/4D8F9D51-4DAE-4274-A3B2-73A2B6D50448.png]
能夠看到包已經縮減到了1.67M,打包時間縮短了29s(減小了4s),對應的觀察網頁上的顯示結果,moment 包的大小也從 545k 變成了 155.32k,小了不少,不是嗎?
[image:DE659EDD-8AE4-4DA8-932C-55D9ECE12866-47140-000008B0769A7E9C/Screen Shot 2019-08-05 at 11.21.55 AM.png]
在用 Webpack 打包的時候,對於一些不常常更新的第三方庫,好比 react,lodash,vue ,能夠將這些庫同項目代碼分離開來,提早打包,從而每次只打包項目自身的代碼,節省了打包時間。
如何使用 DllPlugin | webpack 中文網 呢?
首先在 webpack 文件夾下新建 webpack.dll.conf.js文件
配置以下:
const webpack = require('webpack') const path = require('path') module.exports = { entry: { // manifest 的前綴名,這裏會在webpack 文件下生成一個dll.manifest.json 文件 dll: [ 'react', 'react-dom', 'antd', 'classnames', 'jquery', 'xlsx', 'mammoth', 'html2canvas', 'dexie', 'cheerio', // 這些都是比較穩定,不常作修改的庫文件 ], }, output: { // 指定在 dist/static 下生成一個 dll.min.js 文件 path: path.join(__dirname, '../dist/static/'), filename: '[name].min.js', library: '[name]', }, plugins: [ new webpack.DllPlugin({ // 指定在當前文件夾下生成 manifest 文件 path: path.resolve(__dirname, './dll.manifest.json'), name: '[name]', context: __dirname, }), // 壓縮,讓包更小一點 new webpack.optimize.UglifyJsPlugin({ minimize: true }), ], }
配置完成後對應的須要在 webpack.config.js 中作以下修改:
const manifest = require('./dll.manifest.json') plugins: [ new webpack.DllReferencePlugin({ context: __dirname, manifest, }) ]
而後在入口文件中引入 dll.min.js
<script src=「./dist/static/dll.min.js」></script>
對應的,爲了方便啓動,在 package.json 中添加快捷命令:
"scripts": { "dll": "webpack —config webpack/webpack.dll.js", }
到這裏,DllPlugin 的相關配置就完成了,打包的時候執行 npm run dll 會在webpack 目錄下生成 dll.manifest.json 文件,在 dist/static 目錄下會生成 dll.min.js 文件,在打包過程當中, webpack 會將 webpack.dll.js 中配置包含的庫作一個索引,並寫在 manifest 文件中,而引用 dll 的代碼在打包的時候,只要讀取這個 manifest 獲取對應的庫就能夠了。
最後執行 npm run build 測試打包速度:
[image:C682B1B1-1C7E-4DC4-B999-39B5758D0564-47934-0000B256C82EE788/boundle info after.png]
發現如今的打包時間不到19秒,相比於原來的33s減小了將近一半,對應兩個比較大的包體積也各自減小了2/3 還多。因此使用了 DllPlugin 以後,對項目的打包效率的提高仍是很明顯的。
[image:D11BD337-2369-4498-8D11-E12D087CE884-47934-0000B28971579A82/summary after.png]
項目最開始開始構建,打包後須要將近 4M 的空間,經過手動修改 moment 庫的引入方式和引入 webpack 的 DllPlugin 進行優化,打包後最終體積減小到了 1.2M,壓縮了一半多,對應打包時間也縮短了將近一半,因此經過 webpack 進行打包優化仍是頗有效果的。這給個人啓發式,在實際開發和打包上線過程當中,須要細緻地評估項目的構建體積和打包時間,經過 webpack-bundle-analyzer 能夠直觀的觀察構建包的構成和體積分佈,而且根據分析的結果有針對性地進行優化,以此來精簡項目體積,提高應用效率。固然,打包優化的方式不只限於此,還能夠經過 HappyPack 利用 Node 的多線程充分使用電腦多核來提高構建速度(可是實際效果不必定會變快),此外,還可使用 webpack 的 externals 不打包某些文件,而在其餘地方經過 cdn 引入,利用緩存下載 cnd 文件達到減小打包時間的目的,有興趣能夠在項目中嘗試,相信你會有不少收穫。
參考:
使用webpack的插件DllPlugin加快打包速度 - 前端下午茶 - SegmentFault 思否
DllPlugin | webpack 中文網
DllPlugin提高webpack打包速度 - 簡書