首页
/ Create React App 4.x 版本演进全解析:从 4.0.0 大版本到 4.0.3 维护版的变更、迁移指南与源码验证

Create React App 4.x 版本演进全解析:从 4.0.0 大版本到 4.0.3 维护版的变更、迁移指南与源码验证

2026-09-03 16:55:19作者:苗圣禹Peter

本文以 create-react-app 仓库中的 CHANGELOG-4.x.md 为主体,完整梳理 4.x 系列四个版本(4.0.0、4.0.1、4.0.2、4.0.3)的全部变更条目、破坏性变更与迁移命令,并结合仓库内 react-scripts 的实际源码(如 config/env.jsconfig/webpack.config.jsscripts/utils/createJestConfig.js)逐项验证这些变更的落地方式。读完本篇,你既能掌握每个版本的完整升级路径与官方迁移命令,也能理解 Fast Refresh、新 JSX Transform、dotenv 加载顺序修正、Jest resetMocks 等核心特性在源码中的真实实现。

4.x 系列版本总览

CHANGELOG 覆盖 4.x 系列的四个版本,发布时间线与定位如下:

版本 发布日期 定位
4.0.3 2021-02-22 维护版:小 bug 修复与依赖更新
4.0.2 2021-02-03 维护版:小 bug 修复与文档更新
4.0.1 2020-11-23 维护版:小 bug 修复与文档更新
4.0.0 2020-10-23 大版本:Fast Refresh、React 17 支持等多项新特性

每个版本都附带统一的迁移方式:对于任何尚未 eject 的项目,只需精确锁定 react-scripts 版本即可升级。例如从 4.0.2 升到 4.0.3:

npm install --save --save-exact react-scripts@4.0.3

yarn add --exact react-scripts@4.0.3

同理,从 4.0.1 升到 4.0.2、从 4.0.0 升到 4.0.1、从 3.4.x 升到 4.0.0,命令形式一致(版本号相应替换)。CHANGELOG 中 4.0.0 的迁移部分还特别强调:升级后如果遇到错误,可能需要删除 node_modules 文件夹并用 yarn(或 npm install)重装依赖。对于曾经 eject 过的项目,官方建议的解法是:找到 eject 时的提交(以及后续修改配置的提交)将其回退、先升级,之后再视需要重新 eject;同时也有可能当初 eject 所依赖的功能现在已开箱即用。

4.0.0:Fast Refresh 与 React 17 支持的大版本

核心亮点

CHANGELOG 列出了 4.0.0 的八大亮点,逐项都有对应的源码落点:

  • Fast Refresh(PR #8582):实验性 React 快速刷新,开发模式下组件编辑后秒级热替换且不丢失状态;
  • React 17 支持与新 JSX Transform(PR #9645):不再强制 import React from 'react'
  • TypeScript 4 支持(PR #9734):配合 TS 4.1 使用新的 JSX 编译设置;
  • ESLint 7(PR #8978),并新增 Jest 与 React Testing Library 规则(PR #8963);
  • Jest 26(PR #8955);
  • PWA/Workbox 改进:切换到 Workbox InjectManifest 插件(PR #9205),PWA 模板移入独立仓库以便独立发布;
  • Web Vitals 支持(PR #9116)。

Fast Refresh 在源码中的实现

config/webpack.config.js 中,开发环境通过 @pmmmwh/react-refresh-webpack-plugin 启用刷新:

isEnvDevelopment &&
  shouldUseReactRefresh &&
  new ReactRefreshWebpackPlugin({
    overlay: false,
  }),

其中 shouldUseReactRefresh = env.raw.FAST_REFRESH(同文件第 115 行),而 FAST_REFRESH 的默认逻辑在 config/env.js 中定义:

FAST_REFRESH: process.env.FAST_REFRESH !== 'false',

也就是说 默认开启,设置 FAST_REFRESH=false 即可关闭。该变量会注入到客户端,供 webpackHotDevClient.js 判断是否启用 React Refresh 运行时。4.0.1 中修复的 "FAST_REFRESH=false 时页面不刷新" 问题,修的正是这条链路。另外 scripts/start.js 会在 React 版本低于 16.10 时打印 Fast Refresh 兼容性警告(对应 4.0.0 变更中的 #9350)。

新 JSX Transform 的检测机制

webpack 侧对 JSX runtime 的判定采用“能力探测”而非简单版本判断,见 config/webpack.config.js

const hasJsxRuntime = (() => {
  try {
    if (semver.lt(require('react/package.json').version, '16.14.0')) {
      return false;
    }
    require.resolve('react/jsx-runtime');
    return true;
  } catch (e) {
    return false;
  }
})();

hasJsxRuntime 为真时,Babel 的 @babel/preset-react 使用 runtime: 'automatic'(webpack 配置第 428 行),同时 ESLint 侧会关闭 react/react-in-jsx-scope 规则(第 785-788 行)。Jest 的 Babel 转换同样做了相同检测,见 config/jest/babelTransform.js。TypeScript 项目在 verifyTypeScriptSetup.js 中则要求 hasJsxRuntime && semver.gte(ts.version, '4.1.0-beta') 时才写入新的 jsx 编译选项(scripts/utils/verifyTypeScriptSetup.js),这与 CHANGELOG 中 "Use new JSX setting with TypeScript 4.1.0"(#9734)一一对应。新模板 cra-template 也相应移除了未使用的 React import(#9853),见 cra-template/template/src/App.js

破坏性变更(Breaking Changes)

CHANGELOG 将 4.0.0 的破坏性变更归纳为六类,逐条说明如下:

1. ESLint 升级到 7 并移除 EXTEND_ESLINT 标志

升级到 ESLint 7,新增了大量规则,包括 Jest 与 React Testing Library 规则及 import/no-anonymous-default-export 规则;eslint-plugin-hooks 升级到 4.0.0。从源码结构看,4.x 的 webpack 配置使用的是 eslint-webpack-plugin(替代了已废弃的 eslint-loader,见 config/webpack.config.js),并且不再需要用户设置 EXTEND_ESLINT=true 就能自定义 ESLint 配置——该环境变量在 4.x 源码中已无处理逻辑,与 CHANGELOG 的 "removed the EXTEND_ESLINT flag"(#9587)一致。当前 webpack 中的 ESLint 插件配置要点(webpack.config.js):

  • extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx']——注意 mjs/cjs 测试支持相关的扩展名处理;
  • failOnError: !(isEnvDevelopment && emitErrorsAsWarnings)——开发环境可把错误降级为警告;
  • 缓存文件位置:node_modules/.cache/.eslintcache。这个 "把 ESLint 缓存文件移入 node_modules" 的变更(#9977,4.0.2)在源码中直接体现为 cacheLocation: path.resolve(paths.appNodeModules, '.cache/.eslintcache'),好处是缓存随 node_modules 一起被忽略和清理,不会污染项目目录。

2. Jest 升级到 26,默认 resetMocks: true

scripts/utils/createJestConfig.js 中,默认配置直接写死了 resetMocks: true。这意味着每次测试运行前 mock 会被重置,依赖 mock 调用累积的用例需要显式处理。同时该文件列出了 package.json 中允许覆盖的 Jest 键(supportedKeys,第 74-93 行),包括 resetMockstestMatchtransform 等——4.0.2 的文档 PR #9473 "add missing override options for Jest config" 补的正是这份清单的文档化。如果覆盖了不支持的键(比如 setupFilesAfterEnv),Jest 启动时会打印明确指引:把初始化代码放进 src/setupTests.js

3. Service Worker 切换到 Workbox InjectManifest

webpack 生产配置中的 PWA 生成逻辑见 config/webpack.config.js

isEnvProduction &&
  fs.existsSync(swSrc) &&
  new WorkboxWebpackPlugin.InjectManifest({
    swSrc,
    dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
    exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
    // Bump up the default maximum size (2mb) that's precached,
    // to make lazy-loading failure scenarios less likely.
    maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
  }),

即:只有项目存在 src/service-worker.js 时才注入 service worker,采用 InjectManifest 策略(你自己维护 SW 源码,Workbox 负责预缓存清单注入);默认 2MB 的预缓存大小上限被提高到 5MB——这正是 4.0.1 中 "Increase Workbox's maximumFileSizeToCacheInBytes"(#10048,by jeffposnick)的落地结果,目的是降低懒加载资源偶发加载失败的概率。PWA 模板也随之迁移到独立的 cra-template/pwa 仓库,可独立发布。

4. 移除 --typescript 标志与 NODE_PATH 环境变量支持

创建新应用时不再支持 --typescript 标志,改用 --template typescript。在 packages/create-react-app/createReactApp.js 中,命令行帮助只保留了 --template <path-to-template> 选项,其取值可以是 npm 包名(如 cra-template-typescript)、file: 本地路径或 .tgz/.tar.gz 包地址;createApp 内通过 getTemplateInstallPackage 决定安装哪个模板包。同样,设置基础路径的旧 NODE_PATH 环境变量方式被移除,替代方案是在 jsconfig.json(或 tsconfig.json)中配置 baseUrl——仓库中的 test/fixtures/jsconfigtest/fixtures/typescript 测试夹具即演示了这种绝对路径导入方式。

5. 修正 dotenv 文件加载顺序

4.0.0 将 .env 系列文件的加载顺序调整为符合 dotenv 规范(PR #9037)。当前源码 config/env.js 的实现顺序为:

const dotenvFiles = [
  `${paths.dotenv}.${NODE_ENV}.local`,
  // Don't include `.env.local` for `test` environment
  NODE_ENV !== 'test' && `${paths.dotenv}.local`,
  `${paths.dotenv}.${NODE_ENV}`,
  paths.dotenv,
].filter(Boolean);

.env.[NODE_ENV].local > .env.local(test 环境除外)> .env.[NODE_ENV] > .env。由于 dotenv 不会覆盖已存在的环境变量,排在前面的文件优先级更高。同时该文件还处理了 NODE_PATH 的相对路径解析(仅接受相对路径,防止误导入 Node 核心模块),并通过 REACT_APP_ 前缀过滤出注入客户端的变量(第 69 行)。

6. 停止支持 Node 8

Node 8 已于 2019 年底到达生命周期终点,4.x 不再支持。从源码结构看,4.x 中各包(如 babel-preset-react-appreact-scripts)的依赖声明已按更高 Node 基线调整(#8948),文档中也移除了 Node 8 的引用(#10214,4.0.2 文档变更)。

4.0.0 其他值得注意的变更

  • 新增功能(节选自 CHANGELOG 明细):
    • AVIF 图片支持(#9611);
    • 允许在 package.json 中覆盖 Jest 的 testMatch(#9114);
    • 恢复 --stats 输出 webpack 统计(#8790);
    • 模板支持 devDependencies(#8838)——模板的 package.json 中的 devDependencies 会被合并进新创建项目的 devDependencies,这正是 createReactApp.js 中模板依赖处理逻辑支撑的能力;
    • 检测到 create-react-app 版本过旧时退出提示(#9359)。
  • Bug 修复(节选):新 JSX Transform 相关问题修复(#9788)、ESLint 配置改为从 appPath 解析(#9683)、测试运行器支持 .cjs/.mjs(#8768,与 createJestConfig.jstransform 正则包含 cjs|mjs 一致)、refreshOverlayInterop 模块作用域错误修复(#9805)。
  • 增强(节选):开发环境 scss source map(#8638)、React 低于 16.10 时的 Fast Refresh 警告(#9350)、模板测试更新与 web-vitals 性能上报(#9116,模板中的 reportWebVitals.js 即该能力的落地)、Yarn 2 --use-pnp 修复(#8460)。
  • 底层工具(节选):Jest 26 升级(#8955)、eslint-loader 替换为 eslint-webpack-plugin(#9751)、依赖大版本升级(#8950)。

4.0.0 是 4.x 系列改动最大的版本,CHANGELOG 记录了 63 位贡献者。对于 3.4.x 用户,除了执行上述迁移命令外,务必对照本文"破坏性变更"一节检查 ESLint 自定义规则、Jest mock 用法、service worker 源码(需自行提供 src/service-worker.js 以启用 InjectManifest 流程)以及 Node 版本。

4.0.1:聚焦稳定性与维护体验的补丁版

4.0.1(2020-11-23)是维护版,包含小 bug 修复与文档更新,主要变更:

  • Bug 修复
    • noFallthroughCasesInSwitch/jsx object is not extensible 问题修复(#9921);
    • react-jsx 报错修复(#9869);
    • eject 之后 React is not defined 编译错误修复(#9885);
    • 重新编译缓慢问题修复(#9911);
    • FAST_REFRESH=false 时页面不刷新的问题修复(#9884)——如前所述,该开关经由 config/env.jswebpackHotDevClient.js 传递,是排查"关闭 Fast Refresh 后 HMR 失效"类问题的关键链路。
  • 增强:调高 Workbox 的 maximumFileSizeToCacheInBytes(#10048),源码中现为 5MB(见上文 webpack 配置摘录)。
  • 文档:在"需要 jsdom 的库"列表中补充 React Testing Library(#10052)。
  • 内部:用 prompts 替换 inquirer(#10083,影响 create-react-appreact-scripts 的交互输入实现)、模板图片优化(#9516)。

迁移方式:

npm install --save --save-exact react-scripts@4.0.1
# 或
yarn add --exact react-scripts@4.0.1

4.0.2:BUILD_PATH 高级配置变量登场

4.0.2(2021-02-03)同样为维护版,但它带来了一个实用的新配置项:

新特性:BUILD_PATH 环境变量

PR #8986 增加了 BUILD_PATH 高级配置变量,允许覆盖默认的 build 输出目录。在 config/paths.js 中实现极为简洁:

const buildPath = process.env.BUILD_PATH || 'build';

即构建产物默认输出到 build/,设置 BUILD_PATH=dist 等即可改为其他目录,无需 eject。这与 advanced-configuration 文档中"不 eject 就能调整构建路径"的场景直接对应(参见 docusaurus/docs/advanced-configuration.md)。

其他变更(4.0.2)

  • Bug 修复
    • eslint-webpack-plugin 增加退出开关(#10170)——对应源码中的 DISABLE_ESLINT_PLUGIN 环境变量:config/webpack.config.jsconst disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === 'true';,仅当显式设置为字符串 'true' 时整个 ESLint 插件从 plugins 数组中剔除(第 766 行)。设置方式如 DISABLE_ESLINT_PLUGIN=true npm run build
    • 补齐 react 缺失的 peer 依赖并更新 react-refresh-webpack-plugin(#9872);
    • react-scripts 增加 TypeScript 4.x 作为 peerDependency(#9964)。
  • 增强:ESLint 缓存文件移入 node_modules(#9977,见前文 cacheLocation 源码)、改进开发环境 vendor chunk 命名(#9569)。
  • 文档:补充 Jest 配置可覆盖选项说明(#9473)、更新 public 目录文档(#10314)、移除 Node 8 相关表述(#10214)。
  • 内部:用 immer 处理 appTsConfig 不可变性(#10027,实现见 packages/react-dev-utils/immer.js)、恢复部分集成测试(#10091)。
  • 底层工具:升级 sass-loader(#9988)、更新 postcss 系列后又回滚(#10003、#10216)、升级 @svgr/webpack 修复构建错误(#10213)、formatWebpackMessages 移除 chalk 依赖(#10198)、TypeScript 模板版本提升(#10141)。

迁移方式:

npm install --save --save-exact react-scripts@4.0.2
# 或
yarn add --exact react-scripts@4.0.2

4.0.3:4.x 系列的收尾维护版

4.0.3(2021-02-22)是 4.x 系列 CHANGELOG 记录的最后一个版本,包含少量修复:

  • Bug 修复:升级 eslint-webpack-plugin 以修复 opt-out 标志(DISABLE_ESLINT_PLUGIN)失效的问题(#10590)——这恰好呼应 4.0.2 引入的退出开关:开关语义为"仅当等于字符串 true 时生效",4.0.3 通过升级插件保证了该判断在插件侧行为正确;
  • 内部react-dev-utils 升级 immer 至 8.0.1 以修复安全漏洞(#10412,immer 的封装入口为 packages/react-dev-utils/immer.js);create-react-app 更新测试用例使其与描述一致(#10384,对应 tests/getTemplateInstallPackage.test.js)。

迁移方式:

npm install --save --save-exact react-scripts@4.0.3
# 或
yarn add --exact react-scripts@4.0.3

升级实践要点总结

  1. 统一迁移命令:4.x 系列所有版本升级都遵循"未 eject 则精确升级 react-scripts"的原则:npm install --save --save-exact react-scripts@<版本>yarn add --exact react-scripts@<版本>;3.x 升 4.0.0 时如遇依赖问题,删 node_modules 重装是官方认可的兜底手段。

  2. 3.4.x 升 4.0.0 的检查清单

    • ESLint:确认自定义规则与 ESLint 7 兼容;不再需要 EXTEND_ESLINT;新增 Jest/testing-library/import 规则可能产生新告警;
    • Jest:resetMocks: true 成为默认,mock 相关用例需复查;可在 package.jsonjest 字段覆盖 supportedKeys 列出的选项;
    • PWA:需按 InjectManifest 模式提供 src/service-worker.js;预缓存上限 5MB;
    • 创建新项目:用 --template typescript 代替 --typescript;基础路径用 jsconfig.jsonbaseUrl 代替 NODE_PATH 环境变量;
    • 运行环境:Node 8 不再受支持。
  3. 常用环境变量速查(均已在 4.x 源码中验证):

    • FAST_REFRESH=false:关闭 Fast Refresh(env.js);
    • DISABLE_ESLINT_PLUGIN=true:跳过构建时 ESLint 检查(webpack.config.js);
    • BUILD_PATH=dist:自定义构建输出目录(paths.js);
    • .env 加载优先级:.env.[NODE_ENV].local > .env.local(test 除外)> .env.[NODE_ENV] > .envenv.js)。
  4. 历史版本溯源:4.x 之前的版本请查阅 CHANGELOG-3.x.md(CHANGELOG 文末亦如此指引),更早的还可看 CHANGELOG-2.x.mdCHANGELOG-1.x.mdCHANGELOG-0.x.md

适用前提与限制说明

  • 本文所有版本号、变更条目、迁移命令均直接取自仓库根目录的 CHANGELOG-4.x.md;源码验证基于当前仓库快照(4.x 末期的 packages/ 代码),若你在 4.x 之外的版本上操作,行为可能不同。
  • 变更条目中的 PR 编号、贡献者名单为 CHANGELOG 原文记录;本文未逐一验证每个 PR 细节,仅对文中重点特性(Fast Refresh、JSX runtime、dotenv 顺序、Jest resetMocks、Workbox InjectManifest、ESLint 插件与缓存、BUILD_PATH)给出了源码级佐证路径。
  • 部分能力(如 Fast Refresh)在 4.0.0 时标注为"实验性",实际使用中建议以当时版本 README 与官方文档为准。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
983
503
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384