通過不斷的調整和測試,關於 react 的 webpack 配置終於新鮮出爐。本次的重點主要集中在開發環境上,生產環境則是使用 webpack 的 production 默認模式。css
本次配置主要有:node
eslint+prettier;react
optimization.splitChunks;webpack
happypack;es6
DllReferencePlugin & DllPlugin;web
...npm
講真,對於初次接觸 webpack 的同窗,怕的可能不是 webpack 的配置,而是長長的 package.json。依賴那麼多,你怎麼就知道須要哪些依賴呢。不開玩笑,我還真知道。 webpack 的依賴主要是一些 loader 和 plugins。咱們知道單頁面引用被打包後,原有的結構基本上不復存在了。而以前引用的圖片或字體資源還按照以前的路徑查找,確定是找不到的。那麼咱們就須要轉換工具(順便轉換資源)—— url-loader
|file-loader
。 大多數人寫樣式時,喜歡使用 css、less、sass。這時也會有對應的工具 style-loader
, css-loader
, less-loader
。 想要使用 JavaScript 新特性或處理兼容性,就用 babel-loader
。以上這些基本上能夠應付一些簡單的項目。可實際上呢?json
我信你個鬼,你這個糟老頭壞的很!瀏覽器
看文檔啊,看官方介紹啊。本次也是經過看 babel 文檔,和一些依賴文檔來配置 webpack 的,全程無壓力,並且很正宗。因此,文檔很重要。緩存
若是時團隊合做,代碼規範是很重要的。能夠經過 eslint+prettier 規範。這兩個工具各有側重點,不過官網也提供了二者結合的方案。詳細介紹見官網。我我的不習慣建立太多的配置文件,因此都放在了 package.json 文件中。
// webpack.common.js
{
enforce: "pre",
test: /\.m?jsx?$/,
exclude: /node_modules/,
loader: "eslint-loader",
options: {
fix: true,
cache: true,
formatter: require("eslint-friendly-formatter"),
}
},
複製代碼
"eslintConfig": {
"parser": "babel-eslint",
"env": {
"browser": true,
"es6": true,
"node": true
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"extends": [
"plugin:prettier/recommended"
]
},
"prettier": {
"singleQuote": true,
"semi": true
},
複製代碼
開發環境沒什麼好說的了,簡單易配置,官網很詳細。
// webpack.dev.js
plugins: {
//...
new webpack.HotModuleReplacementPlugin()
},
devtool: "eval-source-map",
devServer: {
contentBase: path.resolve(__dirname, '..', 'dist'),
port: APP_CONFIG.port,
hot: true,
open: true
}
// index.js
// 入口處要配置這些,別忘了。
// 由於有冒泡的機制,因此在頂端加一個就好。
if (module.hot) {
module.hot.accept('./views/login/index.js', () => {
render(App) // 渲染應用
})
}
複製代碼
這個配置是用來分割包的。在性能優化上,請求數和請求包的大小也是很重要的優化點。請求數量和請求數據大小要控制在合理的範圍內。 不過一般狀況下,咱們會將包分割爲內容不變的部分和內容變化的部分。這不單單是爲了將大的包分割成更小的包,也是爲了可以充分利用緩存機制。
// webpack.common.js
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
verdor: {
test: /[\\/]node_modules[\\/]/,
name: 'verdors',
chunks: 'all',
priority: -10,
},
common: {
name: 'common',
chunks: 'all',
minChunks: 2,
priority: -20,
}
}
}
複製代碼
轉換文件算是打包過程當中比較耗時的事情,經過 happypack 能夠將這件事分攤給多個 node 進程,這樣就會大大縮短了打包時間(同理,能夠考慮使用 thread-loader
)。不過進程之間的通訊是要開銷的,這是一個優化方向,要不要採用,還須要酌情考慮。
// loader
{
test: /\.m?jsx?$/,
exclude: /node_modules/,
use: 'happypack/loader?id=js',
}
// plugins
new HappyPack({
id: 'js',
threadPool: happyThreadPool,
loaders: [{
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [['@babel/preset-env', {
"useBuiltIns": "usage",
"corejs": 3
}], "@babel/preset-react"],
plugins: ['@babel/transform-runtime',
"@babel/plugin-proposal-class-properties", [
"import",
{
"libraryName": "antd",
"style": true
}
]
]
}
}]
})
複製代碼
不喜歡單獨的 babel 文件,因此 babel 的配置都在這裏了。其實,關於 babel 要配置的內容仍是挺多的。不過不要怕,babel 的官方文檔有詳細說明。
以前也提到過,一般咱們會使用 optimization.splitChunks
來處理第三方庫,將其分割成不變的部分。但是,每次打包的時候都須要重複這一步驟。 這時候咱們就想啊,不變的部分打包一次不就能夠了麼,以後就只打包那些常常變化的部分,這樣不就能提升效率了麼?是的, DllReferencePlugin & DllPlugin
基本上要作的就是這麼一回事。因此,咱們會針對這兩部分作不一樣的配置。
// webpack.dll.js
new webpack.DllPlugin({
context: process.cwd(),
path: path.join(__dirname, '..', 'dist', 'dll', '[name]-manifest.json'),
name: '[name]_[hash]'
})
// webpack.common.js
new webpack.DllReferencePlugin({
context: process.cwd(),
manifest: require(path.resolve(__dirname, '..', 'dist', 'dll', "vendor-manifest.json"))
}),
複製代碼
multi-spa-webpack-cli
已經發布到 npm,只要在 node 環境下安裝便可。一路按 Enter,所有源碼都在裏面!!!
npm install multi-spa-webpack-cli -g
複製代碼
使用步驟以下:
# 1. 初始化項目
multi-spa-webpack-cli init spa-project
# 2. 進入文件目錄
cd spa-project
# 3. 安裝依賴
npm install
# 4. 打包不變的部分
npm run build:dll
# 5. 啓動項目(手動打開瀏覽器:localhost:8090)
npm start
複製代碼
webpack 系列: