关于eject需要知道的

整理:使用create-react-app构建的项目在yarn run eject后的一些问题。

eject之前

create-react-app脚手架把关于webpack配置和其它脚本封装到了一个叫做react-scriptspackage里。默认情况下所有的配置是不可见的,但是可以通过react-app-rewired在不eject的条件下修改某些webpack配置。这样的方式在绝大多数情况下是可行的,但是如果我们想更精确的控制,比如修改默认的css打包方式、使用less、组件库按需加载等,即使也能够做,但或多或少会用到hack的方式。

在运行yarn run eject后,所有关于webpack配置将会暴露出来,在根目录会生成configscripts两个目录,并且react-script将不复存在,所有react-script的依赖都将注入到项目中。

eject是单项操作,一旦完成,就没办法还原,这就意味着复杂的webpack管理将交由我们自己管理。

eject进行时

  1. 步骤1 运行yarn run eject,稍等片刻,观察到生成新增了configscripts两个目录,并且package.json文件被修改。

  2. 打开package.json文件,由于我们已经不使用react-scripts了,所以这里需要修改start build test等命令。使用scripts目录中对应的脚本即可,例如:

    1
    2
    3
    4
    5
    6
    "scripts": {
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scriprs/test.js"
    ...
    }
  3. 运行yarn start,不出意外的话,项目正常运行,如果提示can’t find module xxx,删除node_modulesyarn.lock(如果有的话),重新运行yarn install安装依赖即可。

eject后出现了问题

如果是eject后运行项目报错,重新安装依赖后仍然报错,那么就要考虑是依赖版本的问题了。就比如笔者的这个项目,使用老版本的react-react-app生成,并且在中期升级了react-scriptsreact等,且使用了特定版本的eslint规则。在根据报错提示进行修复后,运行项目仍然报错且无任何报错提示。

我们需要弄清楚到底是什么依赖有问题,这个过程是复杂且繁琐的,并且可能由于依赖前后版本已经发生了巨大的变化,即使找到存在问题的依赖也可能不能仅通过升级该依赖的版本解决问题。

所以一个备选方案是把项目整体迁移到新版本的create-react-app上,这里有两个做法:使用create-react-app新生成一个项目,我们把源码和依赖都迁移到新项目中,在新的项目中进行eject;使用create-react-app生成一个空的项目并eject,使用新的configscripts替换当前项目的脚本和配置,并且比较packahe.json,更新依赖的版本,重新安装依赖,大功告成。

在实际的情况下,受制于项目版本控制、团队协作、迁移成本等,第一种方式,基本不可用。

解决完问题,接下来我们需要将写在config-overrides.js中的自定义配置进行迁移。

自定义配置

在进行自定义配置之前,如果项目因eslint规则,无法运行成功,可以尝试在config/webpack.config.js中找到eslint-loader并且注释掉这个配置,此时在开发模式下,eslint并不会对源码进行规则校验。

less支持

因为create-react-app脚手架并不支持less,我们需要手动添加对less的支持。首先安装less-loader,并在webpack.config.js中的module.rules下添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const lessRegex = /\.less$/;
module: {
rules: [
...
{
test: lessRegex,
use: getStyleLoaders(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap,
},
'less-loader'
),
}
]
}

注意到这里使用到了一个封装好的函数getStyleLoaders,其针对不同的css预处理器,生成适用的loader,源码非常简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
isEnvDevelopment && require.resolve('style-loader'),
isEnvProduction && {
loader: MiniCssExtractPlugin.loader,
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
},
{
loader: require.resolve('css-loader'),
options: cssOptions,
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
}),
postcssNormalize(),
],
sourceMap: isEnvProduction && shouldUseSourceMap,
},
},
].filter(Boolean);
if (preProcessor) {
loaders.push({
loader: require.resolve(preProcessor),
options: {
sourceMap: isEnvProduction && shouldUseSourceMap,
},
});
}
return loaders;
};

我们知道如果使用了css预处理器,在设置loader的时候,可能需要多个loaders,例如:

  • less-loader: 把less编译成css
  • css-loader: 解决css使用importrequire引入的问题
  • style-loader: 通过style标签把css注入到DOM中。
  • 生产环境下可能还需要生成单独的css文件,css压缩等。

getStyleLoaders就是生成这些loaders的一个公共方法。

组件库按需加载

在开发过程中,如果使用到了组件库且该组件库支持按需加载(例如antd),那么我们可以根据相关的教程配置即可。

比如在当前项目中使用到了xx-ui这个组件库,该组件库支持babel-plugin-import按需加载,在安装好依赖后,我们只需要在package.jsonbabel下配置plugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"babel": {
"presets": [
"react-app"
],
"plugins": [
[
"import",
{
"libraryName": "@wind/xx-ui",
"libraryDirectory": "es",
"style": true
}
],
]
}

这和传统的.babelrc中进行plugin配置无区别,但总算不用再维护额外的一个文件了。

其它

比如我们在构建时需要对代码进行拆分,我们可以在webpack.config.jsoptimization中使用splitChunks进行自定义、分离runtimeChunk等

比如我们构建时不想使用默认的static/js/[name].[contenthash:8].chunk.js作为chunks的文件名,直接修改即可。注意,在代码分割时,相应的css也会被分割,如果想修改css的配置可以直接找到MiniCssExtractPlugin进行修改即可。

最后

经过上面所有的步骤,项目已经能够完全正常运行,和eject之前一样。接下来我们可以详细阅读webpack.config.js,进行更进一步的定制,也可以删除某些项目中不需要的配置,减轻webpack.config.js的复杂性。

如果项目是老项目的话,为了项目能够在eject后不会因为eslint报错而无法正常运行,可以注释掉eslint-loader来避免每次构建时候的预检,但此时对代码风格的约束只限于编辑器本身eslint的支持,对代码质量和团队代码风格可能造成一定的影响。

更好的方式是使用一个适合这个项目的eslint规则,如eslint-config-airbnb-base,并且对这个第三方规则进行定制,直至这个规则适合这个项目。

完。

分享到 评论