-
安装
create-react-app
脚手架:npm install -g create-react-app
-
创建项目:
create-react-app cra-modify
也可以不执行步骤1,直接运行
npx create-react-app cra-modify
创建项目,链接:npx的用法如果创建项目时,拉取依赖包特别慢,可以设置
npm
镜像源为国内的淘宝,命令:npm config set registry https://registry.npm.taobao.org
-
创建成功后,进入
cra-modify
:cd cra-modify
-
运行
npm start
启动项目,打开如下页面,说明安装正常。
reject
项目在package.json
里面提供了这样一个命令:
{
...
"scripts": {
...
"eject": "react-scripts eject"
},
...
}
执行完命令npm run eject
后会将create react app
中的配置暴露到当前项目,这样就可以随意的修改 webpack
文件了。目录结构如下所示:
.
├── config
│ ├── env.js
│ ├── getHttpsConfig.js
│ ├── jest
│ ├── modules.js
│ ├── paths.js
│ ├── pnpTs.js
│ ├── webpack.config.js
│ └── webpackDevServer.config.js
├── package.json
├── package-lock.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── README.md
├── scripts
│ ├── build.js
│ ├── start.js
│ └── test.js
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── serviceWorker.js
└── setupTests.js
CRA
是通过react-scripts
包来升级 CRA 特性的。比如用老版本 CRA
创建了一个项目,这个项目不具备 PWA
功能,但只要项目升级了react-scripts
包的版本就可以具备 PWA
的功能,项目本身的代码不需要做任何修改。
但如果我们使用了eject
命令,就再也享受不到 CRA
升级带来的好处了,因为react-scripts
已经是以文件的形式存在于你的项目,而不是以包的形式,所以无法对其升级。
替换 react-scripts 包
react-scripts 是 CRA 的一个核心包,一些脚本和工具的默认配置都集成在里面,使用 CRA
创建项目默认就是使用这个包,但是 CRA
还提供了另外一种方式来创建 CRA
项目,即使用自定义 scripts
包的方式。
# 默认方式
$ create-react-app foo
# 自定义 scripts 包方式
$ create-react-app foo --scripts-version 自定义包
自定义包
可以是下面几种形式:
react-scripts
包的版本号,比如0.8.2
,这种形式可以用来安装低版本的react-scripts
包。- 一个已经发布到
npm
仓库上的包的名字,比如your-scripts
,里面包含了修改过的webpack
配置。 - 一个
tgz
格式的压缩文件,比如/your/local/scripts.tgz
,通常是未发布到npm
仓库的自定义scripts
包,可以用npm pack
命令生成。
这种方式相对于eject
是一种更灵活地修改 webpack
配置的方式,而且可以做到和 CRA
一样,通过升级 scrips
包来升级项目特性。
自定义 scripts
包的结构可以参照react-scripts
包的结构,只要修改对应的 webpack
配置文件,并安装上所需的 webpack loader
或 plugin
包就可以了。
使用 react-app-rewired
虽然有这两种方式可以扩展 webpack
配置,但是很多开发者还是觉得太麻烦,有没有一种方式可以既不用eject
项目又不用创建自己的 scripts
包呢?答案是肯定的,react-app-rewired 是 react
社区开源的一个修改 CRA
配置的工具。
在 CRA
创建的项目中安装了react-app-rewired
后,可以通过创建一个config-overrides.js
文件来对 webpack
配置进行扩展。
/* config-overrides.js */
module.exports = function override(config, env) {
//do stuff with the webpack config...
return config;
}
override
方法的第一个参数config
就是 webpack
的配置,在这个方法里面,我们可以对 config
进行扩展,比如安装其他 loader
或者 plugins
,最后再将这个 config
对象返回回去。最后再修改package.json
中的脚本命令,修改内容请见这里。
//修改package.json
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
},
新的 react-app-rewired@2.x 版本的关系,你还需要安装 customize-cra 。
config-overrides.js
代码示例:
const { override, fixBabelImports, addDecoratorsLegacy } = require("customize-cra");
module.exports = override(
// babel-plugin-import 是一一个用用于按需加载组件代码和样式的 babel 插件
fixBabelImports("import", {
libraryName: "antd", // antd 按需加载
libraryDirectory: "es",
style: "css",
}),
addDecoratorsLegacy(), // 配置装饰器
);
scripts
包 + override
组合
虽然react-app-rewired
的方式已经可以很方便地修改 webpack
的配置了,但其实我们也可以在自定义的 script
包中实现类似的功能。
在react-app-rewired
的源码中可以看到它核心的包也叫 react-app-rewired
,里面重新覆盖了react-scripts
中的几个脚本文件,包括build.js
、start.js
和test.js
。
具体过程是怎样的呢?以build.js
为例:
- 先获取
webpack
的基本配置,然后再调用config-overrides.js
(就是在根目录中新增的那个文件)中的override
方法,将原先的webpack
对象作为参数传入, - 再取得经过修改后的
webpack
配置对象 - 最后再调用
react-scripts
中的build.js
脚本,传入修改后的webpack
对象来执行命令,
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');
知道了原理之后,我们也可以修改自定义 scripts
包的脚本文件,还是以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
对象。
总结
CRA
是一个非常棒的 React
脚手架工具,但你如果不满足于它的 webpack
默认配置,你可以通过上述几种方式来扩展自己项目的 webpack
配置,这几种方式各有优缺点,可以结合具体的使用场景来选择合适自己的方式。
参考
https://juejin.im/post/5a5d5b815188257327399962