25

create-react-app 优雅定制指南

 4 years ago
source link: http://idayer.com/create-react-app-rewired-guide/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

create-react-app 是一款广泛使用的脚手架,默认它只能使用 eject 命令暴露出 webpack 配置,其实这样使用很不优雅,修改内容文件的话也不利于维护, react-app-rewired 正式解决这样问题的工具,今天我们就好好学习下它的用法。

1. 安装 react-app-rewired

create-react-app 2.x with Webpack 4

npm install react-app-rewired --save-dev

create-react-app 1.x or react-scripts-ts with Webpack 3

npm install [email protected] --save-dev

2. 根目录创建config-overrides.js

/* config-overrides.js */

module.exports = function override(config, env) {
  //do stuff with the webpack config...
  return config;
}

当然我们也可以把 config-overrides.js 放到其他位置,比如我们要指向 node_modules 中某个第三方库提供的配置文件,就可以添加下面配置到 package.json

"config-overrides-path": "node_modules/other-rewire"

3. 替换 react-scripts

打开 package.json :

/* 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 --env=jsdom",
+   "test": "react-app-rewired test --env=jsdom",
    "eject": "react-scripts eject"
}

4. 配置

定制 Webpack 配置

webpack 字段可以用来添加你的额外配置,当然这里面不包含 Webpack Dev Server

const { override, overrideDevServer, fixBabelImports, addLessLoader, addWebpackAlias, addWebpackModuleRule } = require('customize-cra');

const removeManifest = () => config => {
    config.plugins = config.plugins.filter(
        p => p.constructor.name !== "ManifestPlugin"
    );
    return config;
};

module.exports = {
    webpack: override(
        removeManifest(),
        fixBabelImports('import', {
            libraryName: 'antd',
            libraryDirectory: 'es',
            style: 'css',
        }),
        addLessLoader(),
        addWebpackModuleRule({
            test: require.resolve('snapsvg/dist/snap.svg.js'),
            use: 'imports-loader?this=>window,fix=>module.exports=0',
        },),
        addWebpackAlias({
            Snap: 'snapsvg/dist/snap.svg.js'
        }),
    ),
    devServer: overrideDevServer(
        ...
    )
}

定制 Jest 配置 - Testing

jest 配置

定制 Webpack Dev Server

通过 devServer 我们可以做一些开发环境的配置,比如设置 proxy 代理,调整 publicPath ,通过 disableHostCheck 禁用转发域名检查等。

CRA 2.0 开始,推荐搭配 customize-cra 使用,里面提供了一些常用的配置,可以方便我们直接使用。

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

const addProxy = () => (configFunction) => {
    configFunction.proxy = {
        '/v2ex/': {
            target: 'https://www.v2ex.com',
            changeOrigin: true,
            pathRewrite: { '^/v2ex': '/' },
        },
    };

    return configFunction;
}

module.exports = {
    webpack: override(
        ...
    ),
    devServer: overrideDevServer(
        addProxy()
    )
}

Paths - 路径变量

paths 里面是 create-react-app 里面的一些路径变量,包含打包目录、 dotenv 配置地址、 html 模板地址等。

module.exports = {
  dotenv: resolveApp('.env'),
  appPath: resolveApp('.'),
  appBuild: resolveApp('build'),
  appPublic: resolveApp('public'),
  appHtml: resolveApp('public/index.html'),
  appIndexJs: resolveModule(resolveApp, 'src/index'),
  appPackageJson: resolveApp('package.json'),
  appSrc: resolveApp('src'),
  appTsConfig: resolveApp('tsconfig.json'),
  appJsConfig: resolveApp('jsconfig.json'),
  yarnLockFile: resolveApp('yarn.lock'),
  testsSetup: resolveModule(resolveApp, 'src/setupTests'),
  proxySetup: resolveApp('src/setupProxy.js'),
  appNodeModules: resolveApp('node_modules'),
  publicUrl: getPublicUrl(resolveApp('package.json')),
  servedPath: getServedPath(resolveApp('package.json')),
  // These properties only exist before ejecting:
  ownPath: resolveOwn('.'),
  ownNodeModules: resolveOwn('node_modules'), // This is empty on npm 3
  appTypeDeclarations: resolveApp('src/react-app-env.d.ts'),
  ownTypeDeclarations: resolveOwn('lib/react-app.d.ts'),
};

比如我们要修改 appHtmlhtml 模板的默认位置,可以这样做:

const path = require('path');


module.exports = {
    paths: function (paths, env) {

        // 指向根目录的test.html
        paths.appHtml = path.resolve(__dirname, "test.html");

        return paths;
    },
}

5. 常用示例

添加多页面入口

首先安装 react-app-rewire-multiple-entry

npm install react-app-rewire-multiple-entry --save-dev

然后在 config-overrides.js 配置:

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

const multipleEntry = require('react-app-rewire-multiple-entry')([{
    entry: 'src/pages/options.tsx',
    template: 'public/options.html',
    outPath: '/options.html',
}]);

const addEntry = () => config => {

    multipleEntry.addMultiEntry(config);
    return config;
};

const addEntryProxy = () => (configFunction) => {
    multipleEntry.addEntryProxy(configFunction);
    return configFunction;
}

module.exports = {
    webpack: override(
        addEntry(),
    ),
    devServer: overrideDevServer(
        addEntryProxy(),
    )
}

禁用 ManifestPlugin

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


const removeManifest = () => config => {
    config.plugins = config.plugins.filter(
        p => p.constructor.name !== "ManifestPlugin"
    );
    return config;
};


module.exports = {
    webpack: override(
        removeManifest(),
    ),
}

antd 按需加载 && less-loader

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

module.exports = {
    webpack: override(
        fixBabelImports('import', {
            libraryName: 'antd',
            libraryDirectory: 'es',
            style: 'css',
        }),
        addLessLoader(),
    ),
}

最后,如果使用上有什么问题欢迎留言,我会尽我所能解答大家的问题。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK