基礎篇
最基本的一個webpack配置
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: __dirname + "/app/main.js", //已多次提及的唯一入口檔案
output: {
path: __dirname + "/build",
filename: "bundle-[hash].js"
},
devtool: 'none',
devServer: {
contentBase: "./public", //本地伺服器所載入的頁面所在的目錄
historyApiFallback: true, //不跳轉
inline: true,
hot: true
},
module: {
rules: [{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader"
}
}, {
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [{
loader: "css-loader",
options: {
modules: true,
localIdentName: '[name]__[local]--[hash:base64:5]'
}
}, {
loader: "postcss-loader"
}],
})
}
}
]
},
plugins: [
new webpack.BannerPlugin(),
new HtmlWebpackPlugin({
template: __dirname + "/app/index.tmpl.html" //new 一個這個外掛的例項,並傳入相關的引數
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin("style.css")
]
};
複製程式碼
接下來基於這份配置進行一個優化:
首先我們得區分開發環境、生產環境以及測試環境(這個在國內用的公司少)
實現思路(參考vue-cil),通用配置可以設定一個base檔案然後exports,在其他的配置檔案中require進來。
上面這個配置中new webpack.optimize.UglifyJsPlugin()就可以放入webpack.prod.conf.js中,因為程式碼壓縮醜化只需要在生產環境中使用,在開發過程開啟的話,不僅編譯時間加長還不利於除錯。
module與entry、output這個就可以放到webpack.base.cong.js檔案中,這些配置是通用的不管在生產環境還是開發環境中都是用得到的。
devServer則是在開發過程中需要啟動一個伺服器然後再開啟熱替換功能。
- 在module中也可進行些優化,例如在字尾為.js檔案的處理中新增:
include: [resolve('src'), resolve('test')]
這樣loader載入器就只會匹配src/與/test目錄下的檔案,至於node_modules目錄下的檔案則跳過,假如沒加這一限制條件的話,node_modules下那麼多的js檔案,想想都覺得恐怖,並且別人釋出出來的包檔案一般都是經過babel轉成ES5標準的。
- 新增alias,如:
alias: {
'@': resolve('src')
}
這樣當webpack遇到import('@xxx')的時候就會直接在src/目錄下去尋找,能節省不少的目錄查詢時間
進階篇
多頁面優化
當我們的專案是多個頁面的時候,我們需要用到HtmlWebpackPlugin外掛,
for(let i = 0; i< html.length; i++) {
plugins.push(
new HtmlWebpackPlugin({
filename:fileName,
template: path.join('./src/html/', fileName),
inject: true,
minify: {
removeComments: true,
collapseWhitespace: false,
removeAttributeQuotes: true
},
chunksSortMode: 'dependency',
chunks: ['manifest', 'vendor', cur]
}))
)
}
複製程式碼
有多少個頁面就push多少個HtmlWebpackPlugin進去,至於頁面的獲取我們可以通過walk-sync來做到,通過獲取目錄下的入口檔案來判斷有多少個頁面存在。
我在優化過程中遇到個坑,當webpack從2.x升級為3.x的時候,
compilation.getStats().toJson()
這個函式的執行時間會大大加長,我看到其實在issue裡頭有人提出來了,不過作者並沒有給合併到master中去。還有點就是:當頁面是多頁面的時候每一次小的改動都會把所有的html檔案重新生成一次,針對這兩個優化我在Githubfork了下html-webpack-plugin,併發布了html-webpack-plugin-multihtml。我們的專案一共是有49個頁面之前rebuild是花費5-7s ,優化後保持在1s左右。
提取公共程式碼CommonsChunkPlugin
有些類庫如utils, bootstrap之類的可能被多個頁面共享,最好是可以合併成一個js,而非每個js單獨去引用。這樣能夠節省一些空間。這時我們可以用到CommonsChunkPlugin,我們指定好生成檔案的名字,以及想抽取哪些入口js檔案的公共程式碼,webpack就會自動幫我們合併好。
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
chunks: Object.keys(entrys),
minChunks: function (module, count) {
return (module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0 && count > 8)
}
}),
複製程式碼
這個是針對多頁面優化的,CommonsChunkPlugin會自己計算當一個類庫被引用的次數超過8次,就把它打包至vendor中,這樣就不必全打包至一個index.js裡頭
externals提取常用庫
externals 配置選項提供了「從輸出的 bundle 中排除依賴」的方法。相反,所建立的 bundle 依賴於那些存在於使用者環境(consumer's environment)中的依賴。
externals主要是防止將某些import的包打包到bundle中,而是在執行時(runtime)再去從外部獲取這些擴充套件依賴
配置也挺簡單的接下來貼下程式碼:
index.html中引入
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
複製程式碼
webpack.config.js中配置
externals: {
jquery: 'jQuery'
}
複製程式碼
這樣就能在程式碼中通過import引用了:
import $ from 'jquery';
複製程式碼
uglifyPlugin多執行緒壓縮程式碼
在webpack的預設情況下,都是單執行緒跑的,有個叫webpack-uglify-parallel的外掛,它能夠充分呼叫計算機的資源,利用計算機的多核特性進行程式碼壓縮。
使用方法也挺簡單的,
把之前webpack.prod.conf.js中的
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: true
},
comments: false
}),
複製程式碼
替換為
var os = require('os');
var UglifyJsParallelPlugin = require('webpack-uglify-parallel');
module.exports = {
/// ... rest of config
plugins: [
new UglifyJsParallelPlugin({
workers: os.cpus().length, // usually having as many workers as cpu cores gives good results
// other uglify options
})
]
}
複製程式碼
即可 GitHub地址:webpack-uglify-parallel
Happypack
happypack 是 webpack 的一個外掛,目的是通過多程式模型,來加速程式碼構建。目前我們專案中已經配置並且上線了,效果還可以,從最初的40s減少到30s的編譯時間。
配置按照GitHub上的來,也不難
var HappyPack = require('happypack');
var happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
// 省略其餘配置
module: {
loaders: [
{
test: /\.less$/,
loader: ExtractTextPlugin.extract('style',path.resolve(__dirname,'./node_modules', 'happypack/loader') + '?id=less'
)
}
]
},
plugins: [
new HappyPack({
id: 'less',
loaders: ['css!less'],
threadPool: happyThreadPool,
cache: true,
verbose: true
})
]
複製程式碼
我在優化我們專案的webpack遇到了兩個坑,一個就是上面提到的,webpack2升級3編譯時間增多,另一個就是devServer在低版本安卓機型上跑步起來。devServer這個使用"webpack-dev-server": "2.7.1"即可,因為2.9.x版本使用的是es6的寫法安卓4.1以下不支援,ie9以下也不支援。