Create React App(如下簡稱 CRA)是一個官方支持的建立 React 單頁應用的腳手架,它提供了一個零配置的現代構建設置,將一些複雜工具(好比 webpack, Babel)的配置封裝了起來,讓使用者不用關心這些工具的具體配置,從而下降了工具的使用難度。css
npx: npx 來自 npm 5.2+ 或更高版本html
npx create-react-app my-app
npm: npm init <initializer>
在 npm 6+ 中可用node
npm init react-app my-app
Yarn: yarn create
在 Yarn 0.25+ 中可用react
yarn create react-app my-app
在新建立的項目中,能夠運行一些內置命令:webpack
npm start
或 yarn start
git
在開發模式下運行應用程序, 默認在瀏覽器打開http://localhost:3000
。若是更改代碼,頁面將自動從新加載。github
npm test
或 yarn test
web
以交互模式運行測試程序。 默認狀況下,運行與上次提交後更改的文件相關的測試。npm
npm run build
或 yarn build
json
將生產環境的應用程序構建到 build
目錄。 它能將 React 正確地打包爲生產模式中並優化構建以得到最佳性能。構建將被壓縮,文件名中將包含哈希。
npm run eject
注意:這是單向操做。一旦 eject
,就不能回去了!
執行完這個命令後會將封裝在 CRA 中的配置所有反編譯到當前項目,這樣開發者徹底取得 webpack 文件的控制權,能夠自定義修改webpack打包配置。
建立後,項目文件結構以下所示:
my-app node_modules public favicon.ico index.html // 頁面模板 manifest.json src App.css App.js App.test.js index.css index.js // 項目入口 logo.svg reportWebVitals.js setupTests.js .gitignore package.json README.md yarn.lock
src
中的文件。 你須要將任何 JS 和 CSS 文件放在 src
中,不然 Webpack 將發現不了它們。public/index.html
中使用 public
中的文件。Create React App 分爲兩個包:
create-react-app
是一個全局命令行實用程序,可用於建立新項目。react-scripts
包含Create React App的腳本與配置當你運行 create-react-app
時,它始終使用最新版本的 react-scripts
建立項目,新建立的應用會得到全部新功能和改進。
CRA 將全部新特性委託給 react-scripts
, 只須要更新react-scripts
, 不須要更新 create-react-app
就能夠升級CRA 的特性。好比用老版本 CRA 建立了一個項目,這個項目不具有 PWA 功能,但只要項目升級了react-scripts
包的版本就能夠具有 PWA 的功能,項目自己的代碼不須要作任何修改。
Create React App已經封裝了webpack 配置,若是想對 webpack 配置作一些修改,這個時候應該怎麼辦呢?CRA提供瞭如下幾種方式來修改 webpack 的配置:
使用 CRA 建立完項目之後,在package.json
裏面提供了這樣一個命令:
{ ... "scripts": { "eject": "react-scripts eject" }, ... }
執行yarn eject
後會將封裝在 CRA 中的配置所有複製到當前項目。eject 後項目根目錄下會新增 config與scripts 文件夾,修改package.json與yarn.lock文件。
config jest env.js getHttpsConfig.js modules.js paths.js pnpTs.js webpack.config.js webpackDevServer.config.js scripts build.js start.js test.js
若是使用了eject
命令,雖然擴展了 webpack 配置,可是再也享受不到 CRA 升級帶來的好處了。由於react-scripts
已是以文件的形式存在於你的項目,而不是以包的形式,因此沒法對其升級。
react-scripts 是 CRA 的一個核心包,一些腳本和工具的默認配置都集成在裏面,使用 CRA 建立項目默認就是使用這個包。可是 CRA 還提供了另一種方式來建立 CRA 項目,用自定義 scripts 包的方式。
// 默認方式 $ create-react-app my-app // 自定義 scripts 包方式 $ create-react-app my-app --scripts-version 自定義包
自定義包
能夠是下面幾種形式:
react-scripts
包的版本號,好比0.8.2
,這種形式能夠用來安裝低版本的react-scripts
包。your-scripts
,裏面包含了修改過的 webpack 配置。/your/local/scripts.tgz
,一般是未發佈到 npm 倉庫的自定義 scripts 包,能夠用 npm pack
命令生成。這種方式相對於以前的eject
是一種更靈活地修改 webpack 配置的方式,並且能夠作到和 CRA 同樣,經過升級 scrips 包來升級項目特性。
自定義 scripts 包的結構能夠參照react-scripts
包的結構,只要修改對應的 webpack 配置文件,並安裝上所需的 webpack loader 或 plugin 包就能夠。
react-app-rewired 是 react 社區開源的一個修改 CRA 配置的工具,這種方式讓開發者既不用eject
項目也不用本身建立 scripts 包就能夠拓展webpack。
1.在 CRA 建立的項目中安裝react-app-rewired
npm install react-app-rewired --save-dev
2.在項目根目錄下建立config-overrides.js
文件(支持自定義文件路徑)
/* config-overrides.js */ module.exports = function override(config, env) { // 參數中的 config 就是默認的 webpack config // 對 config 進行任意修改 config.mode = 'development'; // 必定要把新的 config 返回 return config; }
config-overriders.js
導出的是一個函數,這個函數的簽名是 const override = (oldWebpackConfig, env) => newWebpackConfig
。
3.修改scripts
命令
/* package.json */ "scripts": { - "start": "react-scripts start", + "start": "react-app-rewired start", - "build": "react-scripts build", + "build": "react-app-rewired build", - "test": "react-scripts test", + "test": "react-app-rewired test", "eject": "react-scripts eject" }
設置自定義路徑 經過package.json 的config-overrides-path
設置自定義路徑:
/* package.json */ { ... "config-overrides-path": "src/app", // src/app/config-overrides.js ... }
默認狀況下,config-overrides.js
文件導出一個函數,用於自定義Webpack配置以在開發或生產模式下編譯React應用。 也能夠改成此文件導出一個對象,該對象最多包含三個字段,每一個字段都是一個函數。
module.exports = { // The Webpack config webpack: function(config, env) { // ...add your webpack config return config; }, // The Jest config jest: function(config) { // ...add your jest config customisation... return config; }, // create a webpack dev server devServer: function(configFunction) { return function(proxy, allowedHost) { const config = configFunction(proxy, allowedHost); const fs = require('fs'); config.https = { key: fs.readFileSync(process.env.REACT_HTTPS_KEY, 'utf8'), cert: fs.readFileSync(process.env.REACT_HTTPS_CERT, 'utf8'), ca: fs.readFileSync(process.env.REACT_HTTPS_CA, 'utf8'), passphrase: process.env.REACT_HTTPS_PASS }; return config; }; }, paths: function(paths, env) { // ...add your paths config return paths; }, }
編譯時,react-app-rewired 會先取到 create-react-app 生成的默認的 webpack config,而後調用 override(config)
方法,對 config 進行修改,獲得新的 webpack config。webpack 最終會使用這個新的 config 進行打包。
流程大體以下:
const overrides = require('../config-overrides'); const webpackConfigPath = paths.scriptVersion + "/config/webpack.config.prod"; // load original config const webpackConfig = require(webpackConfigPath); // override config in memory require.cache[require.resolve(webpackConfigPath)].exports = overrides.webpack(webpackConfig, process.env.NODE_ENV); // run original script require(paths.scriptVersion + '/scripts/build');
雖然react-app-rewired
的方式已經能夠很方便地修改 webpack 的配置了,但也能夠在自定義的 script 包中實現相似的功能。
以build.js
爲例,在獲取基本 webpack 配置對象和使用 webpack 對象之間加入如下代碼:
// override config const override = require(paths.configOverrides); const overrideFn = override || ((config, env) => config); const overrideConfig = overrideFn(config, process.env.NODE_ENV);
overrideConfig
就是修改後的 webpack 對象,最後修改調用了 webpack 對象的代碼,將原來的 webpack 對象替換成修改後的 webpack 對象。