徹底解決 webpack 打包文件體積過大問題
webpack 把我們所有的文件都打包成一個 JS 文件,這樣即使你是小項目,打包后的文件也會非常大。下面就來講下如何從多個方面進(jìn)行優(yōu)化。
去除不必要的插件
剛開始用 webpack 的時候,開發(fā)環(huán)境和生產(chǎn)環(huán)境用的是同一個 webpack 配置文件,導(dǎo)致生產(chǎn)環(huán)境打包的 JS 文件包含了一大堆沒必要的插件,比如 HotModuleReplacementPlugin, NoErrorsPlugin... 這時候不管用什么優(yōu)化方式,都沒多大效果。所以,如果你打包后的文件非常大的話,先檢查下是不是包含了這些插件。
提取第三方庫
像 react 這個庫的核心代碼就有 627 KB,這樣和我們的源代碼放在一起打包,體積肯定會很大。所以可以在 webpack 中設(shè)置
{ entry: { bundle: 'app' vendor: ['react'] } plugins: { new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js') } }
這樣打包之后就會多出一個 vendor.js 文件,之后在引入我們自己的代碼之前,都要先引入這個文件。比如在 index.html 中
<script src="/build/vendor.js"></script> <script src="/build/bundle.js"></script>
除了這種方式之外,還可以通過引用外部文件的方式引入第三方庫,比如像下面的配置
{ externals: { 'react': 'React' } }
externals 對象的 key 是給 require 時用的,比如 require('react'),對象的 value 表示的是如何在 global 中訪問到該對象,這里是 window.React。這時候 index.html 就變成下面這樣
<script src="http://cdn.bootcss.com/react/0.14.7/react.min.js"></script> <script src="/build/bundle.js"></script>
當(dāng)然,個人更推薦第一種方式。
目前推薦用 DLL 的方式提取第三方庫。
代碼壓縮
webpack 自帶了一個壓縮插件UglifyJsPlugin,只需要在配置文件中引入即可。
{ plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ] }
加入了這個插件之后,編譯的速度會明顯變慢,所以一般只在生產(chǎn)環(huán)境啟用。
另外,服務(wù)器端還可以開啟 gzip 壓縮,優(yōu)化的效果更明顯。
代碼分割
什么是代碼分割呢?我們知道,一般加載一個網(wǎng)頁都會把全部的 js 代碼都加載下來。但是對于 web app 來說,我們更想要的是只加載當(dāng)前 UI 的代碼,沒有點擊的部分不加載。
看起來好像挺麻煩,但是通過 webpack 的 code split 以及配合react router 就可以方便實現(xiàn)。具體的例子可以看下 react router 的官方示例huge apps。不過這里還是講下之前配置踩過的坑。
code split 是不支持 ES6 的模塊系統(tǒng)的,所以在導(dǎo)入和導(dǎo)出的時候千萬要注意,特別是導(dǎo)出。如果你導(dǎo)出組件的時候用 ES6 的方式,這時候不管導(dǎo)入是用 CommomJs 還是 AMD,都會失敗,而且還不會報錯!
當(dāng)然會踩到這個坑也是因為我剛剛才用 NodeJS,而且一入門就是用 ES6 的風(fēng)格。除了這個之外,還有一點也要注意,在生產(chǎn)環(huán)境的 webpack 配置文件中,要加上 publicPath
output: { path: xxx, publicPath: yyy, filename: 'bundle.js' }
不然的話,webpack 在加載 chunk 的時候,路徑會出錯。
設(shè)置緩存
開始這個小節(jié)之前,可以先看下大神的一篇文章:大公司里怎樣開發(fā)和部署前端代碼。
對于靜態(tài)文件,第一次獲取之后,文件內(nèi)容沒改變的話,瀏覽器直接讀取緩存文件即可。那如果緩存設(shè)置過長,文件要更新怎么辦呢?嗯,以文件內(nèi)容的 MD5 作為文件名就是一個不錯的解決方案。來看下用 webpack 應(yīng)該怎樣實現(xiàn)
output: { path: xxx, publicPath: yyy, filename: '[name]-[chunkhash:6].js' }
打包后的文件名加入了 hash 值
const bundler = webpack(config) bundler.run((err, stats) => { let assets = stats.toJson().assets let name for (let i = 0; i < assets.length; i++) { if (assets[i].name.startsWith('main')) { name = assets[i].name break } } fs.stat(config.buildTemplatePath, (err, stats) => { if (err) { fs.mkdirSync(config.buildTemplatePath) } writeTemplate(name) }) })
手動調(diào)用 webpack 的 API,獲取打包后的文件名,通過 writeTemplate 更新 html 代碼。完整代碼猛戳 gitst。
這樣子,我們就可以把文件的緩存設(shè)置得很長,而不用擔(dān)心更新問題。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
js刪除數(shù)組中的元素delete和splice的區(qū)別詳解
下面小編就為大家分享一篇js刪除數(shù)組中的元素delete和splice的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02JavaScript報錯:Uncaught TypeError: XXX is
在 JavaScript 編程中,“Uncaught TypeError: XYZ is not iterable” 是一種常見的錯誤,這種錯誤通常發(fā)生在試圖對一個非可迭代對象進(jìn)行迭代操作時,了解這種錯誤的成因和解決方法,對于編寫健壯的代碼至關(guān)重要,需要的朋友可以參考下2024-07-07JavaScript尾遞歸的實現(xiàn)及應(yīng)用場景
本文主要介紹了JavaScript尾遞歸的實現(xiàn)及應(yīng)用場景,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05javascript實現(xiàn)類似于新浪微博搜索框彈出效果的方法
這篇文章主要介紹了javascript實現(xiàn)類似于新浪微博搜索框彈出效果的方法,涉及javascript彈出搜索框的相關(guān)實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07