當前位置:
首頁 > 最新 > webpack2終極優化

webpack2終極優化

webpack是當下最流行的js打包工具,這得益於網頁應用日益複雜和js模塊化的流行。webpack2增加了一些新特性也正式發布了一段時間,是時候告訴大家如何用webpack2優化你的構建讓它構建出更小的文件尺寸和更好的開發體驗。

優化輸出

打包結果更小可以讓網頁打開速度更快以及簡約寬頻。可以通過這以下幾點做到

壓縮css

css-loader 在webpack2里默認是沒有開啟壓縮的,最後生成的css文件里有很多空格和tab,通過配置

css-loader?minimize參數可以開啟壓縮輸出最小的css。css的壓縮實際是是通過cssnano實現的。

tree-shaking

tree-shaking 是指藉助es6 import export 語法靜態性的特點來刪掉export但是沒有import過的東西。要讓tree-shaking工作需要注意以下幾點:

配置babel讓它在編譯轉化es6代碼時不把import export轉換為cmd的module.export,配置如下:

"presets": [ [ "es2015", { "modules": false } ] ]

大多數分布到npm的庫里的代碼都是es5的,但是也有部分庫(redux,react-router等等)開始支持tree-shaking。這些庫發布到npm里的代碼即包含es5的又包含全採用了es6 import export 語法的代碼。

拿redux庫來說,npm下載到的目錄結構如下:

├── es │ └── utils ├── lib │ └── utils

其中lib目錄里是編譯出的es5代碼,es目錄里是編譯出的採用import export 語法的es5代碼,在redux的package.json文件里有這兩個配置:

main": "lib/index.js", "jsnext:main": "es/index.js",

這是指這個庫的入口文件的位置,所以要讓webpack去讀取es目錄下的代碼需要使用jsnext:main欄位配置的入口,要做到這點webpack需要這樣配置:

module.exports = { resolve: { mainFields: [ jsnext:main , main ], } };

這會讓webpack先使用jsnext:main欄位,在沒有時使用main欄位。這樣就可以優化支持tree-shaking的庫。

優化 UglifyJsPlugin

webpack --optimize-minimize 選項會開啟 UglifyJsPlugin來壓縮輸出的js,但是默認的UglifyJsPlugin配置並沒有把代碼壓縮到最小輸出的js里還是有注釋和空格,需要覆蓋默認的配置:

new UglifyJsPlugin({ // 最緊湊的輸出 beautify: false, // 刪除所有的注釋 comments: false, compress: { // 在UglifyJs刪除沒有用到的代碼時不輸出警告 warnings: false, // 刪除所有的 `console` 語句 // 還可以兼容ie瀏覽器 drop_console: true, // 內嵌定義了但是只用到一次的變數 collapse_vars: true, // 提取出出現多次但是沒有定義成變數去引用的靜態值 reduce_vars: true, } })定義環境變數 NODE_ENV=production

很多庫里(比如react)有部分代碼是這樣的:

if(process.env.NODE_ENV !== production ){ // 不是生產環境才需要用到的代碼,比如控制台里看到的警告 }

在環境變數 NODE_ENV 等於 production 的時候UglifyJs會認為if語句里的是死代碼在壓縮代碼時刪掉。

使用 CommonsChunkPlugin 抽取公共代碼

CommonsChunkPlugin可以提取出多個代碼塊都依賴的模塊形成一個單獨的模塊。要發揮CommonsChunkPlugin的作用還需要瀏覽器緩存機制的配合。在應用有多個頁面的場景下提取出所有頁面公共的代碼減少單個頁面的代碼,在不同頁面之間切換時所有頁面公共的代碼之前被載入過而不必重新載入。這個方法可以非常有效的提升應用性能。

在生產環境按照文件內容md5打hash

webpack編譯在生產環境出來的js、css、圖片、字體這些文件應該放到CDN上,再根據文件內容的md5命名文件,利用緩存機制用戶只需要載入一次,第二次載入時就直接訪問緩存。如果你之後有修改就會為對應的文件生產新的md5值。做到以上你需要這樣配置:

{ output: { publicPath: CND_URL, filename: [name]_[chunkhash].js , }, }

知道以上原理後我們還可以進一步優化:利用CommonsChunkPlugin提取出使用頁面都依賴的基礎運行環境。比如對於最常見的react體系你可以抽出基礎庫react react-dom redux react-redux到一個單獨的文件而不是和其它文件放在一起打包為一個文件,這樣做的好處是只要你不升級他們的版本這個文件永遠不會被刷新。如果你把這些基礎庫和業務代碼打包在一個文件里每次改動業務代碼都會導致瀏覽器重複下載這些包含基礎庫的代碼。以上的配置為:

// vender.js 文件抽離基礎庫到單獨的一個文件里防止跟隨業務代碼被刷新 // 所有頁面都依賴的第三方庫 // react基礎 import react ; import react-dom ; import react-redux ; // redux基礎 import redux ; import redux-thunk ;// webpack配置 { entry: { vendor: ./path/to/vendor.js , }, }DedupePlugin 和 OccurrenceOrderPlugin

在webpack1里經常會使用 DedupePlugin 插件來消除重複的模塊以及使用 OccurrenceOrderPlugin 插件讓被依賴次數更高的模塊靠前分到更小的id 來達到輸出更少的代碼,在webpack2里這些已經這兩個插件已經被移除了因為這些功能已經被內置了。

除了壓縮文本代碼外還可以:

用imagemin-webpack-plugin 壓縮圖片

用webpack-spritesmith 合并雪碧圖

對於支持es6的js運行環境使用babili

以上優化點只需要在構建用於生產環境代碼的時候才使用,在開發環境時最好關閉因為它們很耗時。

優化開發體驗

優化開發體驗主要從更快的構建和更方便的功能入手。

更快的構建縮小文件搜索範圍

webpack的resolve.modules配置模塊庫(通常是指node_modules)所在的位置,在js里出現import redux 這樣不是相對也不是絕對路徑的寫法時會去node_modules目錄下找。但是默認的配置會採用向上遞歸搜索的方式去尋找node_modules,但通常項目目錄里只有一個node_modules在項目根目錄,為了減少搜索我們直接寫明node_modules的全路徑:

module.exports = { resolve: { modules: [path.resolve(__dirname, node_modules )] } };

除此之外webpack配置loader時也可以縮小文件搜索範圍。

loader的test正則表達式也應該儘可能的簡單,比如在你的項目里只有.js文件時就不要把test寫成/.jsx?$/

loader使用include命中只需要處理的文件,比如babel-loader的這兩個配置:

項目目錄下的所有js都會進行babel編譯,包括龐大的node_modules下的js

{ test: /.js$/, loader: babel-loader }開啟 babel-loader 緩存

babel編譯過程很耗時,好在babel-loader提供緩存編譯結果選項,在重啟webpack時不需要創新編譯而是復用緩存結果減少編譯流程。babel-loader緩存機制默認是關閉的,打開的配置如下:

module.exports = { module: { loaders: [{ test: /.js$/, loader: babel-loader?cacheDirectory , }] } };使用 alias

resolve.alias 配置路徑映射。

發布到npm的庫大多數都包含兩個目錄,一個是放著cmd模塊化的lib目錄,一個是把所有文件合成一個文件的dist目錄,多數的入口文件是指向lib裡面下的。

默認情況下webpack會去讀lib目錄下的入口文件再去遞歸載入其它依賴的文件這個過程很耗時,alias配置可以讓webpack直接使用dist目錄的整體文件減少文件遞歸解析。配置如下:

module.exports = { resolve: { alias: { moment : moment/min/moment.min.js , react : react/dist/react.js , react-dom : react-dom/dist/react-dom.js } } };使用 noParse

module.noParse 配置哪些文件可以脫離webpack的解析。

有些庫是自成一體不依賴其他庫的沒有使用模塊化的,比如jquey、momentjs、chart.js,要使用它們必須整體全部引入。

webpack是模塊化打包工具完全沒有必要去解析這些文件的依賴,因為它們都不依賴其它文件體積也很龐大,要忽略它們配置如下:

module.exports = { module: { noParse: /node_modules/(jquey|moment|chart.js)/ } };

除此以外還有很多可以加速的方法:

使用happypack多進程並行構建

使用DllPlugin復用模塊

更方便的功能模塊熱替換

模塊熱替換是指在開發的過程中修改代碼後不用刷新頁面直接把變化的模塊替換到老模塊讓頁面呈現出最新的效果。

webpack-dev-server內置模塊熱替換,配置起來也很方便,下面以react應用為例,步驟如下:

在啟動webpack-dev-server的時候帶上--hot參數開啟模塊熱替換,在開啟--hot後針對css的變化是會自動熱替換的,但是js涉及到複雜的邏輯還需要進一步配置。

配置頁面入口文件

import App from ./app ; function run(){ render(,document.getElementById( app )); } run(); // 只在開發模式下配置模塊熱替換 if (process.env.NODE_ENV !== production ) { module.hot.accept( ./app , run); }

當./app發生變化或者當./app依賴的文件發生變化時會把./app編譯成一個模塊去替換老的,替換完畢後重新執行run函數渲染出最新的效果。

自動生成html

webpack只做了資源打包的工作還缺少把這些載入到html里運行的功能,在龐大的app裏手寫html去載入這些資源是很繁瑣易錯的,我們需要自動正確的載入打包出的資源。

webpack原生不支持這個功能於是我做了一個插件 web-webpack-plugin

具體使用點開鏈接看詳細文檔,使用大概如下:

demo(https://github.com/gwuhaolin/web-webpack-plugin/tree/master/demo/out-html)

webpack配置

module.exports = { entry: { A: ./a , B: ./b , }, plugins: [ new WebPlugin({ // 輸出的html文件名稱,必填,注意不要重名,重名會覆蓋相互文件。 filename: index.html , // 該html文件依賴的entry,必須是一個數組。依賴的資源的注入順序按照數組的順序。 requires: [ A , B ], }), ] };

將會輸出一個index.html文件,這個文件將會自動引入 entry A 和 B 生成的js文件,

輸出的html:

輸出的目錄結構

├── A.js ├── B.js └── index.html管理多頁面

雖然webpack適用於單頁應用,但複雜的系統經常是由多個單頁應用組成,每個頁面一個功能模塊。webpack給出了js打包方案但缺少管理多個頁面的功能。 web-webpack-plugin的AutoWebPlugin會自動的為你的系統里每個單頁應用生成一個html入口頁,這個入口會自動的注入當前單頁應用依賴的資源,使用它你只需如下幾行代碼:

查看web-webpack-plugin的文檔了解更多

分析輸出結果

如果你對當前的配置輸出或者構建速度不滿意,webpack有一個工具叫做webpack analyze 以可視化的方式直觀的分析構建,來進一步優化構建結果和速度。要使用它你需要在執行webpack的時候帶上--json --profile2個參數,這代表讓webpack把構建結果以json輸出並帶上構建性能信息,使用如下:

webpack --json --profile > stats.json

會生產一個stats.json文件,再打開webpack analyze 上傳這個文件開始分析。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 推酷 的精彩文章:

IntelliJ IDEA 2017.1 JDK 8 性能調優
深入理解CSS外邊距摺疊
話說PHP的Memcache&Memcached這兩個擴展之間的關係,你都摸清楚了嗎?
收納,本是一件簡單的事

TAG:推酷 |

您可能感興趣

windows下安裝python及第三方庫numpy、scipy、matplotlib終極版
2018 Victoria s Secret:Behati、Candice回歸,Adriana Lima「終極一秀」
終極之戰:Linux&Windows
中國怪獵世界steam or wegame 成就終極贏家:日本Capcom
Alex Kipman談HoloLens 3、消費級產品及終極願景
終極聯乘?Air Jordan 1 x fragment design x LV 定製鞋款曝光!
對話Rony Abovitz:Magic Leap的終極目標是什麼?
義大利設計公司 Pininfarina 推出終極跑車 Hypercar Battista
NECA 漫威 Ultimate Deadpool 終極死侍 1:4 可動人偶
「死侍」Deadpool 再次惡搞亂入《Avengers: EndGame》終極預告
三星 Galaxy Note 9 終極爆料
習武之人的終極神器,戴爾 Latitude 7424 Rugged Extreme評測
化身007,Oculus獨佔遊戲《Defector》讓你體驗終極間諜的超能力
終極之後是否還有究極?ThinkPad X1 Carbon 2018評測
榮耀Magic2/小米MIX 3終極對決 你pick誰
三星 Galaxy Note 10 終極爆料
deb系Linux終極對決,debian還是ubuntu,你怎麼選?
Surface Headphones的終極選擇題:你要的是Surface,還是耳機?
聯想在IFA展出終極輕薄筆記本ThinkPad X1 Extreme
Arctis系列的終極版?Steelseries Arctis Pro開箱