Create React App:不使用eject,自定義webpack配置

前言:譯者一直使用react,可是前段時間由於facebook的協議問題,公司開始禁止使用react來開發前端項目。(更新到react16的MIT協議也不行)因而,筆者決定將react替換爲preact,這樣就須要在webpack配置中設置alias,可是又不但願使用create-react-app中不可逆的eject。因而找到了這篇教程,簡單翻譯後結合本身的須要進行了修改。分享給有須要的人。css

Create React App提供了一套很是不錯的配置,可以上手即用,而且提供了「eject」功能,讓你可以本身接管全部的配置項。前端

可是,若是當你僅僅是想微調一下Webpack的配置呢?而並非接管全部的配置項。你可能想要增長SASS或者SCSS的支持,或者使用本身定義的.eslintrc文件。(譯者的使用場景是在webpack中增長alias)node

讓咱們開始講解如何操做。react

警告!
首先你要注意: 若是你並不瞭解Webpack的運行機制,或是不喜歡在工程里加入的hacky代碼(少許的),我建議你不要使用這種方式,這是一種高級的技巧。webpack

當Create React App變化時,特別是它使用的react-scripts包變化時,頗有可能致使咱們的代碼須要一些修復。若是官方修改了webpack的結構,或者導出方式,咱們的代碼將出現問題,這時就須要你本身去了解如何修復它們。因此,再強調一次,若是你以爲這種方式有問題,請不要這麼作!(譯者以爲原做者有點誇張了)git

破解Create React App
好了,有了這個可怕的免責聲明,讓咱們來看看如何破解Create React App,若是你想直接去看示例項目的代碼,也是能夠的。在開始以前,確保使用的是最新的react-scripts,做者在編寫的時候是1.0.11。(譯者使用的是1.4.1)github

Create React App的基礎被封裝在「react-scripts」包中,能夠在package.json中的「dependencies」的列表裏瞭解到。web

咱們將使用rewire來建立猴子補丁(運行時動態替換),使得咱們在執行以前對Webpack配置進行定製。npm

下面這個文件是這個項目中最重要的部分。我建議在您的CRA項目中創建一個名爲「scripts」的目錄,並將這些代碼放入scripts/customized-config.js文件中。你能夠任意命名,不過(稍後咱們將用到這個文件名)。json

scripts/customized-config.js

/*
  本模塊運行react-scripts裏的腳本 (Create React App)
  能夠自定義webpack配置,經過在項目根目錄建立"config-overrides.dev.js" 、 "config-overrides.prod.js" 文件.

  A config-overrides file should export a single function that takes a
  config and modifies it as necessary.

  module.exports = function(webpackConfig) {
    webpackConfig.module.rules[0].use[0].options.useEslintrc = true;
  };
*/
var rewire = require('rewire');
var proxyquire = require('proxyquire');

switch(process.argv[2]) {
  // The "start" script is run during development mode
  case 'start':
    rewireModule('react-scripts/scripts/start.js', loadCustomizer('../config-overrides.dev'));
    break;
  // The "build" script is run to produce a production bundle
  case 'build':
    rewireModule('react-scripts/scripts/build.js', loadCustomizer('../config-overrides.prod'));
    break;
  // The "test" script runs all the tests with Jest
  case 'test':
    // Load customizations from the config-overrides.testing file.
    // That file should export a single function that takes a config and returns a config
    let customizer = loadCustomizer('../config-overrides.testing');
    proxyquire('react-scripts/scripts/test.js', {
      // When test.js asks for '../utils/createJestConfig' it will get this instead:
      '../utils/createJestConfig': (...args) => {
        // Use the existing createJestConfig function to create a config, then pass
        // it through the customizer
        var createJestConfig = require('react-scripts/utils/createJestConfig');
        return customizer(createJestConfig(...args));
      }
    });
    break;
  default:
    console.log('customized-config only supports "start", "build", and "test" options.');
    process.exit(-1);
}

// Attempt to load the given module and return null if it fails.
function loadCustomizer(module) {
  try {
    return require(module);
  } catch(e) {
    if(e.code !== "MODULE_NOT_FOUND") {
      throw e;
    }
  }

  // If the module doesn't exist, return a
  // noop that simply returns the config it's given.
  return config => config;
}

function rewireModule(modulePath, customizer) {
  // Load the module with `rewire`, which allows modifying the
  // script's internal variables.
  let defaults = rewire(modulePath);

  // Reach into the module, grab its global 'config' variable,
  // and pass it through the customizer function.
  // The customizer should *mutate* the config object, because
  // react-scripts imports the config as a `const` and we can't
  // modify that reference.
  let config = defaults.__get__('config');
  customizer(config);
}

爲了跑通代碼,你須要安裝一些額外的依賴包:

npm install --save rewire proxyquire

你能夠經過註釋來了解它是如何工做的。最有趣的部分是位於底部的rewireModule方法,它使用rewire庫來查看另外一個文件,並獲取定義在那裏的配置變量的引用。

一旦你完成了這個操做,就能夠爲開發,生產,測試環境編寫用來覆蓋的配置文件。這一部分徹底取決於你——不管你對CRA的Webpack配置作了什麼改動,你均可以直接去作。

這些文件應該直接在CRA文件夾的根目錄下,全部3個文件都是可選的。若是您想要從新配置它們的位置,只需改變上面「loadCustomizer」調用的路徑。只是不要把它們放在「src」中就能夠。

下面是一些開發環境替換配置的例子:

config-overrides.dev.js

const path = require('path');

module.exports = function(config) {
  // 使用你本身的 ESLint 
  let eslintLoader = config.module.rules[0];
  eslintLoader.use[0].options.useEslintrc = true;

  // Add the SASS loader second-to-last
  // (last one must remain as the "file-loader")
  let loaderList = config.module.rules[1].oneOf;
  loaderList.splice(loaderList.length - 1, 0, {
    test: /\.scss$/,
    use: ["style-loader", "css-loader", "sass-loader"]
  });
}

還須要建立一個config-overrides.prod.js文件具備相同的內容。開發過程當中使用的是dev文件(例如npm start),在構建期間使用prod文件(例如,npm run build)。

爲了讓剛剛的配置生效,你須要安裝SASS loader, 和它的依賴node-sass:

npm install --save sass-loader node-sass

最後,要讓這些新代碼生效,你須要更改package.json,調用這些新的腳本,而不是默認的react-scripts的腳本。要作到這一點,能夠用如下方法替換「start」、「build」和「test」。

package.json

"scripts": {
  "start": "node scripts/customized-config start",
  "build": "node scripts/customized-config build",
  "test": "node scripts/customized-config test --env=jsdom",
}

示例項目
一個CRA生成的項目,在github上,點擊這裏.

譯者補充:
1.原文沒有講到默認的配置文件位置,是在node_modules\react-scripts\config\目錄下的
webpack.config開頭的文件,例如:webpack.config.dev.js
2.替換react爲preact只須要在config-overrides.dev.js文件中加入:

/*
  * 替換react爲preact
  * */
  let alias = config.resolve.alias
  alias["react"] = "preact-compat"
  alias["react-dom"] = "preact-compat"

相關資料:
preact替換react:https://preactjs.com/guide/sw...

相關文章
相關標籤/搜索