Webpack 打包優化之速度篇

在前文 Webpack 打包優化之體積篇中,對如何減少 Webpack 打包體積,作了些探討;固然,那些法子對於打包速度的提高,也是大有裨益。然而,打包速度之於開發體驗和及時構建,至關重要;因此有必要對其作更爲深刻的研究,以便完善工做流,這就是本文存在的原因。html

Webpack Package optimizationWebpack Package optimization前端

減少文件搜索範圍

在使用實際項目開發中,爲了提高開發效率,很明顯你會使用不少成熟第三方庫;即使本身寫的代碼,模塊間相互引用,爲了方便也會使用相對路勁,或者別名(alias);這中間若是能使得 Webpack 更快尋找到目標,將對打包速度產生非常積極的影響。於此,咱們須要作的即:減少文件搜索範圍,從而提高速度;實現這一點,能夠有以下兩法:vue

配置 resolve.modules

Webpack的resolve.modules配置模塊庫(即 node_modules)所在的位置,在 js 裏出現 import 'vue' 這樣不是相對、也不是絕對路徑的寫法時,會去 node_modules 目錄下找。可是默認的配置,會採用向上遞歸搜索的方式去尋找,但一般項目目錄裏只有一個 node_modules,且是在項目根目錄,爲了減小搜索範圍,能夠直接寫明 node_modules 的全路徑;一樣,對於別名(alias)的配置,亦當如此:node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function resolve (dir) {
return path.join(__dirname, '..', dir)
}

module.exports = {
resolve: {
extensions: ['.js', '.vue', '.json'],
modules: [
resolve('src'),
resolve('node_modules')
],
alias: {
'vue$': 'vue/dist/vue.common.js',
'src': resolve('src'),
'assets': resolve('src/assets'),
'components': resolve('src/components'),
// ...
'store': resolve('src/store')
}
},
...
}

須要額外補充一點的是,這是 Webpack2.* 以上的寫法。在 1.* 版本中,使用的是 resolve.root,現在已經被棄用爲 resolve.modules;同時被棄用的還有resolve.fallbackresolve.modulesDirectorieswebpack

設置 test & include & exclude

Webpack 的裝載機(loaders),容許每一個子項均可以有如下屬性:git

test:必須知足的條件(正則表達式,不要加引號,匹配要處理的文件)
exclude:不能知足的條件(排除不處理的目錄)
include:導入的文件將由加載程序轉換的路徑或文件數組(把要處理的目錄包括進來)
loader:一串「!」分隔的裝載機(2.0版本以上,」-loader」不能夠省略)
loaders:做爲字符串的裝載器陣列es6

對於include,更精確指定要處理的目錄,這能夠減小沒必要要的遍歷,從而減小性能損失。一樣,對於已經明確知道的,不須要處理的目錄,則應該予以排除,從而進一步提高性能。假設你有一個第三方組件的引用,它確定位於node_modules,一般它將有一個 src 和一個 dist 目錄。若是配置 Webpack 來排除 node_modules,那麼它將從 dist 已經編譯的目錄中獲取文件。不然會再次編譯它們。故而,合理的設置 include & exclude,將會極大地提高 Webpack 打包優化速度,好比像這樣:github

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
module: {
preLoaders: [
{
test: /\.js$/,
loader: 'eslint',
include: [resolve('src')],
exclude: /node_modules/
},
{
test: /\.svg$/,
loader: 'svgo?' + JSON.stringify(svgoConfig),
include: [resolve('src/assets/icons')],
exclude: /node_modules/
}
],
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader',
include: [resolve('src')],
exclude: /node_modules\/(?!(autotrack|dom-utils))|vendor\.dll\.js/
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url',
exclude: /assets\/icons/,
query: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
}
]
}

加強代碼代碼壓縮工具

Webpack 默認提供的 UglifyJS 插件,因爲採用單線程壓縮,速度頗慢 ;推薦採用 webpack-parallel-uglify-plugin 插件,她能夠並行運行 UglifyJS 插件,更加充分而合理的使用 CPU 資源,這能夠大大減小的構建時間;固然,該插件應用於生產環境而非開發環境,其作法以下,web

1
2
3
4
5
6
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
})

 

替換如上自帶的 UglifyJsPlugin 寫法爲以下配置便可:正則表達式

1
2
3
4
5
6
7
8
9
10
11
12
var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS:{
output: {
comments: false
},
compress: {
warnings: false
}
}
})

固然也有其餘同類型的插件,好比:webpack-uglify-parallel,但根據本身實踐效果來看,並無 webpack-parallel-uglify-plugin 表現的那麼卓越,有興趣的朋友,能夠更全面的作下對比,擇優選用。須要額外說明的是,webpack-parallel-uglify-plugin 插件的運用,會相對 UglifyJsPlugin 打出的包,看起來略大那麼一丟丟(其實能夠忽略不計);若是在你使用時也是如此,那麼在打包速度跟包體積之間,你應該有本身的抉擇。

用 Happypack 來加速代碼構建

你知道,Webpack 中爲了方便各類資源和類型的加載,設計了以 loader 加載器的形式讀取資源,可是受限於 nodejs的編程模型影響,全部的 loader 雖然以 async 的形式來併發調用,可是仍是運行在單個 node 的進程,以及在同一個事件循環中,這就直接致使了些問題:當同時讀取多個loader文件資源時,好比`babel-loader`須要 transform 各類jsx,es6的資源文件。在這種同步計算同時須要大量耗費 cpu 運算的過程當中,node的單進程模型就無優點了,而 Happypack 就是針對解決此類問題而生的存在。

Webpack-HappypackWebpack-Happypack

Happypack 的處理思路是:將原有的 webpack 對 loader 的執行過程,從單一進程的形式擴展多進程模式,從而加速代碼構建;本來的流程保持不變,這樣能夠在不修改原有配置的基礎上,來完成對編譯過程的優化,具體配置以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var HappyPack = require('happypack');
var happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

module: {
loaders: [
{
test: /\.js[x]?$/,
include: [resolve('src')],
exclude: /node_modules/,
loader: 'happypack/loader?id=happybabel'
}
]
},
plugins: [
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader'],
threadPool: happyThreadPool,
cache: true,
verbose: true
})
]

能夠研究看到,經過在 loader 中配置直接指向 happypack 提供的 loader,對於文件實際匹配的處理 loader,則是經過配置在 plugin 屬性來傳遞說明,這裏 happypack 提供的 loader 與 plugin 的銜接匹配,則是經過id=happybabel來完成。配置完成後,laoder的工做模式就轉變成了以下所示:

Webpack-HappypackWebpack-Happypack

Happypack 在編譯過程當中,除了利用多進程的模式加速編譯,還同時開啓了 cache 計算,能充分利用緩存讀取構建文件,對構建的速度提高也是很是明顯的;更多關於 happyoack 箇中原理,可參見 @淘寶前端團隊(FED) 的這篇:happypack 原理解析。若是你使用的 Vue.js 框架來開發,也可參考 vue-webpack-happypack 相關配置。

設置 babel 的 cacheDirectory 爲true

babel-loader is slow! 因此不只要使用excludeinclude,儘量準確的指定要轉化內容的範疇,並且要充分利用緩存,進一步提高性能。babel-loader 提供了 cacheDirectory特定選項(默認 false):設置時,給定的目錄將用於緩存加載器的結果。

將來的 Webpack 構建將嘗試從緩存中讀取,以免在每次運行時運行潛在昂貴的 Babel 從新編譯過程。若是值爲空(loader: ‘babel-loader?cacheDirectory’)或true(loader: babel-loader?cacheDirectory=true),node_modules/.cache/babel-loader 則 node_modules 在任何根目錄中找不到任何文件夾時,加載程序將使用默認緩存目錄或回退到默認的OS臨時文件目錄。實際使用中,效果顯著;配置示例以下:

1
2
3
4
5
6
7
8
9
rules: [
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory=true',
exclude: /node_modules/,
include: [resolve('src'), resolve('test')]
},
... ...
]

設置 noParse

若是你肯定一個模塊中,沒有其它新的依賴,就能夠配置這項, Webpack 將再也不掃描這個文件中的依賴,這對於比較大型類庫,將能促進性能表現,具體能夠參見如下配置:

1
2
3
4
5
6
7
module: {
noParse: /node_modules\/(element-ui\.js)/,
rules: [
{
...
}
}

拷貝靜態文件

在前文 Webpack 打包優化之體積篇中提到,引入 DllPlugin 和 DllReferencePlugin 來提早構建一些第三方庫,來優化 Webpack 打包。而在生產環境時,就須要將提早構建好的包,同步到 dist 中;這裏拷貝靜態文件,你可使用 copy-webpack-plugin 插件:把指定文件夾下的文件複製到指定的目錄;其配置以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
var CopyWebpackPlugin = require('copy-webpack-plugin')

plugins: [
...
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]

固然,這種工做,實現的法子不少,好比能夠藉助 shelljs,能夠參見這裏的實現 vue-boilerplate-template

於深圳.南山 @17-08-10 Last Modify: @17-08-13

如若轉載,請保留原文連接: Webpack 打包優化之速度篇

相關文章
相關標籤/搜索