還在run eject 修改create-react-app中的配置?

NDOER發表於2019-12-30

前奏曲

眾所周知, create-react-app(以下稱為CRA)是 FaceBook 開源的 建立 React 現代Web應用程式應用的腳手架,讓我們可以快速和專注專案的開發而不用過多的去關心工具和服務的配置,在一些場景中還是需要另外的加入或者修改 CRA 中的配置,在 CRA 的官方文件中指出可以通過執行npm run eject 來暴露出配置檔案來進行修改,但是這種方式是不可逆的,同時會有一些隱藏的問題。

eject做了什麼

當你執行 npm run eject會將潛藏的一系列配置檔案和一些依賴項都“彈出”到專案中,然後就可以由你自己完全控制,但是這個過程是不可逆的。

來看看 npm run eject後專案發生了什麼變化,以下的示例使用 npx create-react-app進行建立。

eject之前的目錄結構:

螢幕快照 2019-12-30 上午9.10.44.png

eject之後的目錄結構:

image.png


通過Git版本管理追蹤到的檔名高亮顯示可以看出eject後產生變化,而開啟package.json可以看到專案的依賴項(dependencies)和npm script發生了變化以及新增了 jest的配置。

eject副作用

雖然Eject後可以根據自己的需要新增配置項做一些更高階的配置,但是由於這個操作是不可逆的,所以也會帶來一些問題:

無法迎接未來

如果後續的create-react-app更新了並新增了很多不錯的功能,你想應用到你的專案中,可以通過更新 create-react-app版本來實現,而不是去更新webpack的配置,但是如果已經對專案進行了 eject操作,那麼你無法很好的“迎接”未來。

程式碼潔癖

create-react-app其中的一個目的就是可以讓你專注與專案的開發,這對於一些有程式碼潔癖或者喜歡保持應用程式儘可能乾淨的人是友好的,他不用去關心其他的配置與服務,看不到其他從來不用關心的程式碼,然而在 eject之後,package.json就寫入了很多依賴項,還有其他的指令碼和配置檔案,差不多有10多個新檔案,每個檔案包含了50-200行程式碼,這對於這類人在維護依賴項的時候會辣眼睛。

回到根本

eject修改配置後,你會將其複製貼上到其他的專案中,因為在大多數情況下,專案的配置(比如webpack與babel)都是相同的。如果你由多個類似的專案,那麼你必須得自己去維護多份配置和指令碼,告辭!

eject前請三思

在你 eject之前請多思考和對你的問題或者疑問進行調查。

Eject後自己新增補充的功能是CRA缺少的嗎?

CRA 缺少所需要的功能,需要自己去新增,這其實是大部分人進行 eject 的原因。但是在 eject之前,請你花點時間思考一下或者搜尋一下來確保自己需要新增的功能不會變成額外的工作或者重複別人之前已經做過的工作。

CRA的 issues 中已經記錄了很多的問題,很有可能已經有人解決了你的問題,去在討論區裡探索一下,你有可能會發現解決方案或者替代的方法,如果沒有關於你問題的相關討論,你可以考慮提出 issues ,而且經過深思的 issues 是值得被讚賞的。

Eject給你帶來多少價值?


eject修改配置檔案之前,你可以問問自己,如果進行這個更改可以增加多少價值?增加價值是否超過了管理構建過程中所引入的認知負擔?

在執行eject後,你得對更新那些你可能沒有完全瞭解的程式碼負責,因為 eject後將新增數千行復雜的程式碼進行構建和測試,你需要學習這些程式碼來正確的更新、測試和構建。如果構建不通過,CRA 也將無法支援你的自定義配置,如果你有一個開發團隊,你是否相信他們還需要充分了解他們對構建過程所做的更改來保證其穩定性。

需要對CRA進行很大更改?


如果你的工作流是很特殊的,需要特殊的工具或者服務,但是在你 eject之前,請思考讓你的用例比你想象中的更加重用,fork react-script允許你進行更改,還可以在其他類似的專案上進行重用,而不是 eject瞭然後自己去維護。這種方式相對於直接進行 eject是一種更靈活和維護性更強的一種修改方式,可以和CRA一樣進行升級script包來應用特性。

允許其他人使用併為你的構建過程做出貢獻,這可以提高專案的穩定性和完善性。Fork 也是CRA團隊所建議的,這篇文件提供了指南來引導你如何將 create-react-app定製化為自己的利器。

想學習CRA內部構建過程的原理?


這是極好的!如果你想學習內部的工作原理,那麼請盡情的進行 eject!不過了解CRA的工作原理是一項不簡單的任務,如果你感到困惑或者迷茫,請不要灰心,多在社群、google、stackoverflow上進行探索,你不會辜負你所付出的!

替代方案

react-app-rewired + customize-cra

文件連線:

在專案中使用過 ant design的應該知道,可以使用react-app-rewiredcustomize-cra這兩個工具庫來進行自定義配置。

image.png

對於 create-react-app1.x需要使用 react-app-rewired@1.62,而因為各自版本升級的原因,在到 react-app-rewired@2.x版本的時候只保留了核心的功能,在這個commit你可以看到移除了 rewire helper 的功能函式。因此你需要藉助customize-cra來自定義 CRA v2+以上的配置。

常見用法

首先安裝依賴:

yarn add react-app-rewired customize-cra
複製程式碼

antd 配置:

修改npm script:

"start": "PROT=3002 react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
複製程式碼

專案根目錄建立 config-override.js並寫入配置:

// confit-override.js
// 按需載入元件程式碼和樣式
// addLessLoader 來幫助載入 less 樣式,幫助自定義主題
// 使用外掛讓 Day.js 替換 momentjs 減小打包大小,
const { override, fixBabelImports,addWebpackPlugin, addLessLoader } = require('customize-cra');
const AntdDayjsWebpackPlugin = require('antd-dayjs-webpack-plugin');
const path = require('path');

module.exports = override(
    fixBabelImports('import', {
        libraryName: 'antd',
        libraryDirectory: 'es',
        style: true,
    }),
   addLessLoader({
      javascriptEnabled: true,
      modifyVars: { '@primary-color': '#1DA57A' },
    }),
    addWebpackPlugin(new AntdDayjsWebpackPlugin())
);
複製程式碼

新增alias別名

在平時專案開發中,經常性會遇見引用元件或者工具函式時會出現這樣的情況:

import header from '../../../../components/header';
複製程式碼

而alias別名的設定,會讓這更為方便的引用。

// config-override.js
const { addWebpackAlias} = require('customize-cra');
const resolve = dir => path.join(__dirname, '.', dir);

module.exports = override(
  ...
	addWebpackAlias({
    ['src']: resolve('./src')
  }),
  ...
)
複製程式碼

如果是TS專案,注意需要在 tsconfig.json 中進一步設定,如果直接在 tsconfig.json 檔案中直接設定 paths 屬性,當重新run 的時候,屬性又會被刪除。

CRA issue 中的解決方式:
github.com/facebook/cr…

// tsconfig.json
{
 	...
	"extends": "./paths.json",
  ...
}
複製程式碼
// paths.json

{
    "compilerOptions": {
      "baseUrl": "src",
      "paths": {
        "src/*": ["*"]
      }
    }
  }
複製程式碼

API代理

const { 
  override, 
  overrideDevServer,
} = require('customize-cra');

const devServerConfig = () => config => {
  return {
      ...config,
      port: 3000,
      proxy: {
        '/app/v1': {
          target: 'http://localhost:3005',
          changeOrigin: true,
          ws: false,
          pathRewrite: {
            '^/app/v1': '/app/v1',
          },
          secure: false,
        },
      },
  }
}

module.exports = {
 	...
  devServer: overrideDevServer(
    devServerConfig()
  ),
  ...
}
複製程式碼

關閉sourceMap

//config-override.js
const { 
  override, 
} = require('customize-cra');

const rewiredMap = () => config => {
    config.devtool = config.mode === 'development' ? 'cheap-module-source-map' : false;
    return config;
};

module.exports = override(
    rewiredMap()
);
複製程式碼

其他更多用法可參見文件,傳送門

@craco/craco

首先安裝依賴:

yarn add @craco/craco 
複製程式碼

同樣修改 npm scripts:

"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test",
}

複製程式碼

常見用法

修改alias別名

根目錄建立craco.config.js 並寫入配置

//craco.config.js
const path = require('path');
const resolve = dir => path.join(__dirname, '.', dir);

module.exports = {
 ...
 webpack: {
 	alias: {
  	 'src': resolve('src')
  }
 }
 ...
}
複製程式碼

antd配置

安裝 craco-antd外掛

yarn add craco-antd 
複製程式碼

新增配置

const CracoAntDesignPlugin = require("craco-antd");

module.exports = {
   	...
    plugins: [{ plugin: CracoAntDesignPlugin }],
    ...
}
複製程式碼

其他更多用法可參見文件,傳送門

最後

現在我們知道有哪些方式來修改CRA建立的專案中的預設配置,不管是 npm run eject或者是通過 fork一份 react-script來正對專案來高度定製化,在或者是用一些替代的方法都是可以達到目的的,不過從對比上來看,使用 craco或者 react-app-rewired+ customize-cra是可以滿足絕大多數需求的,不過各自帶來的效應不管是負面還是正面的,既然去使用來就得去面對。

記得在你進行 eject之前,請三思!多思考思考!你的專案和現有團隊的專案中需要修改CRA中預設配置的需求到底是怎麼樣的!選擇合適的,才是最好的!

人生也是,多思考,多看看自己內心深處到底需要的是什麼。

相關文章