背景
使用 CRA 脚手架创建的项目,如果想要修改编译配置,通常可能会选择 npm run eject
弹出配置后魔改。但是,eject 是不可逆操作,弹出配置后,你将无法跟随官方的脚步去升级项目的 react-script 版本。
如果想要无 eject 重写 CRA 配置,目前成熟的是下面这几种方式
- 通过 CRA 官方支持的
--scripts-version
参数,创建项目时使用自己重写过的 react-scripts 包 - 使用 react-app-rewired + customize-cra 组合覆盖配置
- 使用 craco 覆盖配置
第二种方式相对第三种略复杂一些,我自己很有体会并且我们注意到最新的AntDesign4 官方也开始推荐 craco 了,那我们还等什么还不快行动起来,今天主要在这里详细讨论一下 craco 的使用,也方便大家给出更好的建议。
配置步骤
- 首先,使用
create-react-app
创建一个项目,这里我们命名为my-project
npx create-react-app my-project
- 进入项目目录,安装基本依赖
yarn add antd @craco/craco craco-less @babel/plugin-proposal-decorators babel-plugin-import -D
3、修改 package.json
中的 scripts
{
"scripts":{
"start": "set PORT=5000 && craco start FAST_REFRESH=true",
"build": "set GENERATE_SOURCEMAP=false && craco build",
"analyzer": "env NODE_ENV=production BUILD_ANALYZER=true yarn start",
"test": "craco test"
}
}
4、项目根目录创建 craco.config.js
文件
/* craco.config.js */
module.exports = {
...
}
上面用到了几个环境变量: PORT
启动端口 GENERATE_SOURCEMAP
打包时是否生成 sourceMap
BUILD_ANALYZER
文件方式输出编译分析
基础的配置到此完成了,接下来是处理各种配置的覆盖,完整的 craco.config.js 配置文件结构,可以在 craco 官方的文档中详细查询:Configuration Overview 。
扩展 babel 配置
虽然可以在 configure 中定义 babel 配置,但 craco 也提供了快捷的方式单独去书写,添加
@babel/preset-env
配置示例如下:
/* craco.config.js */
module.exports = {
babel: {
presets: [
[
'@babel/preset-env',
{
modules: false, // 对ES6的模块文件不做转化,以便使用tree shaking、sideEffects等
useBuiltIns: 'entry', // browserslist环境不支持的所有垫片都导入
// https://babeljs.io/docs/en/babel-preset-env#usebuiltins
// https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md
corejs: {
version: 3, // 使用core-js@3
proposals: true,
},
},
],
],
plugins: [
// 配置 babel-plugin-import
['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }, 'antd'],
// 配置解析器
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": true }],
["babel-plugin-styled-components", { "displayName": true }]
],
loaderOptions: {},
loaderOptions: (babelLoaderOptions, { env, paths }) => { return babelLoaderOptions; }
},
}
检测模块编译情况
new WebpackBar({ profile: true }),
new CircularDependencyPlugin({
exclude: /node_modules/,
include: /src/,
failOnError: true,
allowAsyncCycles: false,
cwd: process.cwd()
})