擴展 Create React App 的 Webpack 配置

 

 

Create React App(以下簡稱 CRA)是創建 React 應用的一個腳手架,它與其他腳手架不同的一個地方就是將一些複雜工具(比如 webpack)的配置封裝了起來,讓使用者不用關心這些工具的具體配置,從而降低了工具的使用難度。

但是對於一些熟悉 webpack 的開發者來說,他們可能想對 webpack 配置做一些修改,這個時候應該怎麼辦呢?

其實我們可以通過以下幾種方式來修改 webpack 的配置:

  • 項目 eject
  • 替換 react-scripts 包
  • 使用 react-app-rewired
  • scripts 包 + override 組合

下面對這幾種方式分別進行介紹。

項目 eject

使用 CRA 創建完項目以後,項目在package.json裏面提供了這樣一個命令:

1
2
3
4
5
6
7

 
  1. {

  2. ...

  3. "scripts": {

  4. "eject": "react-scripts eject"

  5. },

  6. ...

  7. }

  8.  

執行完這個命令——yarn run eject後會將封裝在 CRA 中的配置全部反編譯到當前項目,這樣用戶就可以完全取得 webpack 文件的控制權,想怎麼修改就怎麼修改了。

1
2
3
4
5
6
7
8
9
10
11

 
  1. # eject 後項目根目錄下會出現 config 文件夾,裏面就包含了 webpack 配置

  2. config

  3. ├── env.js

  4. ├── jest

  5. │   ├── cssTransform.js

  6. │   └── fileTransform.js

  7. ├── paths.js

  8. ├── polyfills.js

  9. ├── webpack.config.dev.js // 開發環境配置

  10. ├── webpack.config.prod.js // 生產環境配置

  11. └── webpackDevServer.config.js

  12.  

CRA 與其他腳手架不同的另一個地方,就是可以通過升級其中的react-scripts包來升級 CRA 的特性。比如用老版本 CRA 創建了一個項目,這個項目不具備 PWA 功能,但只要項目升級了react-scripts包的版本就可以具備 PWA 的功能,項目本身的代碼不需要做任何修改。

但如果我們使用了eject命令,就再也享受不到 CRA 升級帶來的好處了,因爲react-scripts已經是以文件的形式存在於你的項目,而不是以包的形式,所以無法對其升級。

替換 react-scripts 包

react-scripts 是 CRA 的一個核心包,一些腳本和工具的默認配置都集成在裏面,使用 CRA 創建項目默認就是使用這個包,但是 CRA 還提供了另外一種方式來創建 CRA 項目,即使用自定義 scripts 包的方式。

1
2
3
4
5

 
  1. # 默認方式

  2. $ create-react-app foo

  3.  
  4. # 自定義 scripts 包方式

  5. $ create-react-app foo --scripts-version 自定義包

  6.  

自定義包可以是下面幾種形式:

  • react-scripts包的版本號,比如0.8.2,這種形式可以用來安裝低版本的react-scripts包。
  • 一個已經發布到 npm 倉庫上的包的名字,比如your-scripts,裏面包含了修改過的 webpack 配置。
  • 一個 tgz 格式的壓縮文件,比如/your/local/scripts.tgz,通常是未發佈到 npm 倉庫的自定義 scripts 包,可以用 npm pack 命令生成。

這種方式相對於之前的eject是一種更靈活地修改 webpack 配置的方式,而且可以做到和 CRA 一樣,通過升級 scrips 包來升級項目特性。

自定義 scripts 包的結構可以參照react-scripts包的結構,只要修改對應的 webpack 配置文件,並安裝上所需的 webpack loader 或 plugin 包就可以了。

使用 react-app-rewired

雖然有這兩種方式可以擴展 webpack 配置,但是很多開發者還是覺得太麻煩,有沒有一種方式可以既不用eject項目又不用創建自己的 scripts 包呢?答案是肯定的,react-app-rewired 是 react 社區開源的一個修改 CRA 配置的工具。

在 CRA 創建的項目中安裝了react-app-rewired後,可以通過創建一個config-overrides.js文件來對 webpack 配置進行擴展。

1
2
3
4
5
6

 
  1. /* config-overrides.js */

  2.  
  3. module.exports = function override(config, env) {

  4. //do stuff with the webpack config...

  5. return config;

  6. }

  7.  

override方法的第一個參數config就是 webpack 的配置,在這個方法裏面,我們可以對 config 進行擴展,比如安裝其他 loader 或者 plugins,最後再將這個 config 對象返回回去。

最後再修改package.json中的腳本命令,修改內容請見這裏

scripts 包 + override 組合

雖然react-app-rewired的方式已經可以很方便地修改 webpack 的配置了,但其實我們也可以在自定義的 script 包中實現類似的功能。

react-app-rewired的源碼中可以看到它核心的包也叫 react-app-rewired,裏面重新覆蓋了react-scripts中的幾個腳本文件,包括build.jsstart.jstest.js

具體過程是怎樣的呢?以build.js爲例:

  • 先獲取 webpack 的基本配置,然後再調用config-overrides.js(就是在根目錄中新增的那個文件)中的override方法,將原先的 webpack 對象作爲參數傳入,
  • 再取得經過修改後的 webpack 配置對象
  • 最後再調用react-scripts中的build.js腳本,傳入修改後的 webpack 對象來執行命令,

具體源碼如下:

1
2
3
4
5
6
7
8
9
10

 
  1. const overrides = require('../config-overrides');

  2. const webpackConfigPath = paths.scriptVersion + "/config/webpack.config.prod";

  3.  
  4. // load original config

  5. const webpackConfig = require(webpackConfigPath);

  6. // override config in memory

  7. require.cache[require.resolve(webpackConfigPath)].exports =

  8. overrides.webpack(webpackConfig, process.env.NODE_ENV);

  9. // run original script

  10. require(paths.scriptVersion + '/scripts/build');

  11.  

知道了原理之後,我們也可以修改自定義 scripts 包的腳本文件,還是以build.js爲例,在獲取基本 webpack 配置對象和使用 webpack 對象之間加入以下代碼:

1
2
3
4

 
  1. // override config

  2. const override = require(paths.configOverrides);

  3. const overrideFn = override || ((config, env) => config);

  4. const overrideConfig = overrideFn(config, process.env.NODE_ENV);

  5.  

overrideConfig就是修改後的 webpack 對象,最後修改調用了 webpack 對象的代碼,將原來的 webpack 對象替換成修改後的 webpack 對象。

總結

CRA 是一個非常棒的 React 腳手架工具,但你如果不滿足於它的 webpack 默認配置,你可以通過上述幾種方式來擴展自己項目的 webpack 配置,這幾種方式各有優缺點,可以結合具體的使用場景來選擇合適自己的方式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章