相关版本
该版本直接fork官方的GitHub仓库,版本号为 v3.2.1。
详细的源代码注释,请查看GitHub仓库
目录结构
├─bin
│ └─react-scripts.js # 命令入口文件
├─config
│ └─jest # jest配置文件夹
│ ├─env.js # 环境变量配置
│ ├─modules.js # 返回对应的JS或TS配置
│ ├─paths.js # 项目主要的入口文件配置项
│ ├─pnpTs.js # pnp相关配置项
│ ├─webpack.config.js # webpack的配置
│ └─webpackDevServer.config.js # webpack开发服务器的配置内容
├─fixtures # 暂不清楚用途
├─lib # TS定义
├─scripts # 对应的启动脚本
│ ├─build.js # run build的脚本
│ ├─eject.js # run eject的脚本
│ ├─init.js # create-react-app后的执行脚本
│ ├─start.js # run start的脚本
│ └─utils # 工具函数封装
├─template # 普通的js模板文件夹
│ ├─public
│ └─src
└─template-typescript # typescript版的模板文件夹
流程分析
该源代码采用lerna工具管理依赖,主要的源码均位于packages目录下。在react-scripts目录下的package.json中,bin字段内容如下:
"bin": {
"react-scripts": "./bin/react-scripts.js"
},
因此我们运行该react-scripts命令时,实际是执行该目录下的./bin/react-scripts.js。
bin/react-scripts.js
该文件在执行时,会读取命令行参数。主要源码如下:
const args = process.argv.slice(2);
在日常开发过程中,执行命令的主要格式是:yarn run start, 最终在命令行被转为换:node react-scripts路径 start。因此要读取有效的命令行参数,也应该是从第三个参数开始。
在读取到的参数中,查找出有效的命令build/eject/start/test对应的序号,如果没有查找到则取第一个参数作为默认值,但最终也会直接输出警告信息后退出程序。
查找到有效命令后,执行**../scripts**目录下对应的脚本文件,并传入除有效参数外的剩余参数。
scripts/init.js
该文件主要是在执行完create-react-app命令后,将项目模板文件复制到新建的项目目录。传入的参数列表如下:
{
appPath, // 项目根目录
appName, // 项目名称
verbose, // 是否打印日志
originalDirectory, // 命令执行目录
template // create-react-app命令中传入的额外参数:指定的模板文件路径
}
scripts/start.js
对应的执行命令为:yarn run start。主要作用:启动开发服务器,执行流程如下:
- 设置环境变量:BABEL_ENV、NODE_ENV=“development”;
- 加载自定义的环境变量配置;
- 必要的入口文件检测:作为入口的index.html和js;
- 读取ip和port;
- 检测是否配置browserslist。如果最终都没有browserlist则直接退出;
- 查找可用端口:先确认默认端口是否可用,不可用则确认是否自动查找可用端口,不查找则直接退出,查找则返回一个可用端口;
- 配置createCompiler的options并执行,返回一个compiler;
- 载入代理配置,并配置代理服务prepareProxy;
- 创建开发服务配置,具体的配置代码放在webpackDevServer.config.js;
- 运行WebpackDevServer,传入compiler和proxyConfig,返回一个devServer
- 启动devServer服务,如果在交互模式下清理控制台,再打开浏览器
scripts/build.js
对应的执行命令为:yarn run build。主要作用:源代码构建,执行流程如下:
- 设置环境变量:BABEL_ENV、NODE_ENV=“production”;
- 加载自定义的环境变量配置;
- 必要的入口文件检测:作为入口的index.html和js;
- 生成webpack配置;
- 检测是否配置browserslist;
- 检测是否配置browserslist。如果最终都没有browserlist则直接退出
- 在构建前,检测出所有文件大小的map
- 清空构建的输出目录
- 复制待构建目录的public目录到构建目录:静态文件夹名——paths.appPublic
- 开始webpack构建
- 构建完成后,输出相关的构建信息:警告/警告/错误、文件大小信息、后续操作的提示
scripts/eject.js
对应的执行命令为:yarn run eject。主要作用:暴露webpack配置到项目目录中,让用户可以自行修改构建配置,执行流程如下:
- 确认是否需要继续当前操作——暴露webpack等配置信息?是——继续,否——退出
- 如果有git源代码管理工具?否——继续;是——是否有未保存的记录?是——退出,否继续
- 读取react-scripts待复制的文件夹及其下的文件,分别确认所有内容在项目根目录下是否存在,有一个存在则直接退出。检测的文件夹:['config', 'config/jest', 'scripts']
- 生成相关的jest配置:jestConfig
- 在项目目录下,创建待复制的文件夹
- 相关文件复制:相关文件复制:在文件复制文件时,删除文件内容@remove-on-eject-begin...@remove-on-eject-end
- package.json配置修改并保存:
devDependencies、dependencies中删除react-scripts dependencies依赖添加:react-scripts的dependencies中,除了也属于optionalDependencies的所有依赖,全部添加到项目依赖中 dependencies依赖是所有字段全部按依赖名称重新排列一次 scripts字段:用react-scripts的bin字段的key去匹配项目package.json的scripts中所有的value,将匹配到的结果全部替换为node scripts/[key].js scripts字段:删除eject项 添加其他字段:jest、babel、eslintConfig
- 如果类型声明的入口路径appTypeDeclarations:读取并替换react-scripts types后保存
- 移除node_modules/.bin/react-scripts命令
- 重新安装依赖
- 如果有git则直接提交git记录