逐步淘汰 Create React App

2025年2月14日,由 Matt CarrollRicky Hanlon 撰写

🌐 February 14, 2025 by Matt Carroll and Ricky Hanlon


今天,我们将弃用用于新应用的 Create React App,并鼓励现有应用迁移到 框架,或迁移到像 Vite、Parcel 或 RSBuild 这样的 构建工具

🌐 Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild.

我们也提供文档,说明在何种情况下框架不适合你的项目,你想要自己构建框架,或者你只是想通过从零开始构建 React 应用来学习 React 的工作原理。

🌐 We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch.


当我们在2016年发布 Create React App 时,没有明确的方法来构建一个新的 React 应用。

🌐 When we released Create React App in 2016, there was no clear way to build a new React app.

要创建一个 React 应用,你必须自己安装一堆工具并将它们连接在一起,以支持像 JSX、代码规范检查和热重载这样的基本功能。这在正确操作上非常棘手,所以社区 创建常用 模板来进行常见 配置。然而,模板难以更新,而且碎片化使得 React 很难发布新功能。

🌐 To create a React app, you had to install a bunch of tools and wire them up together yourself to support basic features like JSX, linting, and hot reloading. This was very tricky to do correctly, so the community created boilerplates for common setups. However, boilerplates were difficult to update and fragmentation made it difficult for React to release new features.

Create React App 通过将多个工具组合成一个推荐的配置解决了这些问题。这为应用提供了一种简单的方式来升级到新的工具功能,并允许 React 团队将非平凡的工具更改(如 Fast Refresh 支持、React Hooks lint 规则)部署给最广泛的用户群体。

🌐 Create React App solved these problems by combining several tools into a single recommended configuration. This allowed apps a simple way to upgrade to new tooling features, and allowed the React team to deploy non-trivial tooling changes (Fast Refresh support, React Hooks lint rules) to the broadest possible audience.

这个模型变得如此受欢迎,以至于今天有整整一类工具都是以这种方式运作的。

🌐 This model became so popular that there’s an entire category of tools working this way today.

弃用 Create React App

🌐 Deprecating Create React App

尽管 Create React App 使入门变得容易,但有几个限制使得构建高性能的生产应用变得困难。原则上,我们可以通过本质上将其发展为一个框架来解决这些问题。

🌐 Although Create React App makes it easy to get started, there are several limitations that make it difficult to build high performant production apps. In principle, we could solve these problems by essentially evolving it into a framework.

然而,由于 Create React App 目前没有活跃的维护者,并且已经有许多现有的框架可以解决这些问题,我们决定弃用 Create React App。

🌐 However, since Create React App currently has no active maintainers, and there are many existing frameworks that solve these problems already, we’ve decided to deprecate Create React App.

从今天开始,如果你安装新的应用,你将看到弃用警告:

🌐 Starting today, if you install a new app, you will see a deprecation warning:

Console
create-react-app is deprecated. You can find a list of up-to-date React frameworks on react.dev For more info see: react.dev/link/cra This error message will only be shown once per install.

我们还在 Create React App 的网站和 GitHub 仓库上添加了弃用通知。Create React App 将继续以维护模式运行,我们已经发布了一个新的 Create React App 版本,以支持 React 19。

🌐 We’ve also added a deprecation notice to the Create React App website and GitHub repo. Create React App will continue working in maintenance mode, and we’ve published a new version of Create React App to work with React 19.

如何迁移到一个框架

🌐 How to Migrate to a Framework

我们推荐使用框架创建新的 React 应用。我们推荐的所有框架都支持客户端渲染(CSR)和单页应用(SPA),并且可以部署到 CDN 或静态托管服务,而无需服务器。

🌐 We recommend creating new React apps with a framework. All the frameworks we recommend support client-side rendering (CSR) and single-page apps (SPA), and can be deployed to a CDN or static hosting service without a server.

对于现有应用,这些指南将帮助你迁移到仅客户端的单页应用(SPA):

🌐 For existing apps, these guides will help you migrate to a client-only SPA:

如何迁移到构建工具

🌐 How to Migrate to a Build Tool

如果你的应用有不寻常的限制,或者你更喜欢通过自己构建框架来解决这些问题,或者你只是想从零学习 React 的工作原理,你可以使用 Vite、Parcel 或 Rsbuild 自行构建自定义的 React 设置。

🌐 If your app has unusual constraints, or you prefer to solve these problems by building your own framework, or you just want to learn how react works from scratch, you can roll your own custom setup with React using Vite, Parcel or Rsbuild.

对于现有的应用,这些指南将帮助你迁移到构建工具:

🌐 For existing apps, these guides will help you migrate to a build tool:

为了帮助开始使用 Vite、Parcel 或 Rsbuild,我们新增了关于 从零开始构建 React 应用 的文档。

🌐 To help get started with Vite, Parcel or Rsbuild, we’ve added new docs for Building a React App from Scratch.

深入研究

我需要一个框架吗?

🌐 Do I need a framework?

大多数应用从框架中受益,但确实存在从零构建 React 应用的合理情况。一个好的经验法则是,如果你的应用需要路由,你可能会从使用框架中受益。

🌐 Most apps would benefit from a framework, but there are valid cases to build a React app from scratch. A good rule of thumb is if your app needs routing, you would probably benefit from a framework.

就像 Svelte 有 Sveltekit、Vue 有 Nuxt、Solid 有 SolidStart,React 推荐使用一个框架,它可以将路由完全集成到诸如数据获取和代码拆分等功能中,从而开箱即用。这样可以避免你需要自己编写复杂配置、本质上自己构建一个框架的麻烦。

🌐 Just like Svelte has Sveltekit, Vue has Nuxt, and Solid has SolidStart, React recommends using a framework that fully integrates routing into features like data-fetching and code-splitting out of the box. This avoids the pain of needing to write your own complex configurations and essentially build a framework yourself.

然而,你总是可以使用像 Vite、Parcel 或 Rsbuild 这样的构建工具从头开始构建 React 应用

🌐 However, you can always build a React app from scratch using a build tool like Vite, Parcel, or Rsbuild.

继续阅读以了解更多关于构建工具的局限性以及我们推荐框架的原因的信息。

🌐 Continue reading to learn more about the limitations of build tools and why we recommend frameworks.

构建工具的局限性

🌐 Limitations of Build Tools

Create React App 和类似的构建工具使开始构建 React 应用变得容易。运行 npx create-react-app my-app 后,你会得到一个配置齐全的 React 应用,其中包含开发服务器、代码检查和生产构建。

🌐 Create React App and build tools like it make it easy to get started building a React app. After running npx create-react-app my-app, you get a fully configured React app with a development server, linting, and a production build.

例如,如果你正在构建一个内部管理工具,你可以从一个登陆页面开始:

🌐 For example, if you’re building an internal admin tool, you can start with a landing page:

export default function App() {
return (
<div>
<h1>Welcome to the Admin Tool!</h1>
</div>
)
}

这使你能够立即开始在 React 中进行编码,使用诸如 JSX、默认 lint 规则以及可在开发和生产中运行的打包工具等功能。然而,这个设置缺少构建真实生产应用所需的工具。

🌐 This allows you to immediately start coding in React with features like JSX, default linting rules, and a bundler to run in both development and production. However, this setup is missing the tools you need to build a real production app.

大多数生产应用需要解决路由、数据获取和代码拆分等问题的解决方案。

🌐 Most production apps need solutions to problems like routing, data fetching, and code splitting.

路由

🌐 Routing

Create React App 不包含特定的路由解决方案。如果你刚刚开始,一个选项是使用 useState 在路由之间切换。但这样做意味着你不能共享应用的链接——每个链接都会指向同一个页面——而且随着时间的推移,构建应用的结构将变得困难:

🌐 Create React App does not include a specific routing solution. If you’re just getting started, one option is to use useState to switch between routes. But doing this means that you can’t share links to your app - every link would go to the same page - and structuring your app becomes difficult over time:

import {useState} from 'react';

import Home from './Home';
import Dashboard from './Dashboard';

export default function App() {
// ❌ Routing in state does not create URLs
const [route, setRoute] = useState('home');
return (
<div>
{route === 'home' && <Home />}
{route === 'dashboard' && <Dashboard />}
</div>
)
}

这就是为什么大多数使用 Create React App 的应用通过像 React RouterTanstack Router 这样的路由库来解决添加路由问题的原因。使用路由库,你可以向应用中添加额外的路由,它会对你的应用结构提供建议,并允许你开始共享路由的链接。例如,使用 React Router 你可以定义路由:

🌐 This is why most apps that use Create React App solve add routing with a routing library like React Router or Tanstack Router. With a routing library, you can add additional routes to the app, which provides opinions on the structure of your app, and allows you to start sharing links to routes. For example, with React Router you can define routes:

import {RouterProvider, createBrowserRouter} from 'react-router';

import Home from './Home';
import Dashboard from './Dashboard';

// ✅ Each route has it's own URL
const router = createBrowserRouter([
{path: '/', element: <Home />},
{path: '/dashboard', element: <Dashboard />}
]);

export default function App() {
return (
<RouterProvider value={router} />
)
}

通过此更改,你可以分享一个指向 /dashboard 的链接,应用将导航到仪表板页面。一旦你有了路由库,你可以添加额外的功能,如嵌套路由、路由守卫和路由过渡,而这些在没有路由库的情况下很难实现。

🌐 With this change, you can share a link to /dashboard and the app will navigate to the dashboard page . Once you have a routing library, you can add additional features like nested routes, route guards, and route transitions, which are difficult to implement without a routing library.

这里存在权衡:路由库为应用增加了复杂性,但它也增加了一些没有它很难实现的功能。

🌐 There’s a tradeoff being made here: the routing library adds complexity to the app, but it also adds features that are difficult to implement without it.

数据获取

🌐 Data Fetching

在 Create React App 中另一个常见问题是数据获取。Create React App 并不包含特定的数据获取解决方案。如果你只是刚开始,一个常见的选择是在 effect 中使用 fetch 来加载数据。

🌐 Another common problem in Create React App is data fetching. Create React App does not include a specific data fetching solution. If you’re just getting started, a common option is to use fetch in an effect to load data.

但这样做意味着数据是在组件渲染后获取的,这可能导致网络瀑布。网络瀑布是由于在应用渲染时获取数据而不是在代码下载时并行获取数据引起的:

🌐 But doing this means that the data is fetched after the component renders, which can cause network waterfalls. Network waterfalls are caused by fetching data when your app renders instead of in parallel while the code is downloading:

export default function Dashboard() {
const [data, setData] = useState(null);

// ❌ Fetching data in a component causes network waterfalls
useEffect(() => {
fetch('/api/data')
.then(response => response.json())
.then(data => setData(data));
}, []);

return (
<div>
{data.map(item => <div key={item.id}>{item.name}</div>)}
</div>
)
}

在 effect 中获取数据意味着用户需要等待更长时间才能看到内容,即使数据本可以更早获取。为了解决这个问题,你可以使用像 TanStack QuerySWRApolloRelay 这样的数据获取库,这些库提供预获取数据的选项,从而在组件渲染之前就开始发起请求。

🌐 Fetching in an effect means the user has to wait longer to see the content, even though the data could have been fetched earlier. To solve this, you can use a data fetching library like TanStack Query, SWR, Apollo, or Relay which provide options to prefetch data so the request is started before the component renders.

当与你的路由“加载器”模式集成以在路由级别指定数据依赖时,这些库的效果最佳,这可以让路由优化你的数据获取:

🌐 These libraries work best when integrated with your routing “loader” pattern to specify data dependencies at the route level, which allows the router to optimize your data fetches:

export async function loader() {
const response = await fetch(`/api/data`);
const data = await response.json();
return data;
}

// ✅ Fetching data in parallel while the code is downloading
export default function Dashboard({loaderData}) {
return (
<div>
{loaderData.map(item => <div key={item.id}>{item.name}</div>)}
</div>
)
}

在初次加载时,路由可以在路由渲染之前立即获取数据。当用户在应用中导航时,路由能够同时获取数据和路由,实现获取操作的并行化。这减少了在屏幕上看到内容所需的时间,并可以改善用户体验。

🌐 On initial load, the router can fetch the data immediately before the route is rendered. As the user navigates around the app, the router is able to fetch both the data and the route at the same time, parallelizing the fetches. This reduces the time it takes to see the content on the screen, and can improve the user experience.

然而,这需要在你的应用中正确配置加载器,并以复杂性换取性能。

🌐 However, this requires correctly configuring the loaders in your app and trades off complexity for performance.

代码分割

🌐 Code Splitting

在 Create React App 中另一个常见的问题是代码拆分。Create React App 并没有包含特定的代码拆分解决方案。如果你刚开始接触,你可能根本不会考虑代码拆分。

🌐 Another common problem in Create React App is code splitting. Create React App does not include a specific code splitting solution. If you’re just getting started, you might not consider code splitting at all.

这意味着你的应用作为一个单独的包发布:

🌐 This means your app is shipped as a single bundle:

- bundle.js 75kb

但为了理想的性能,你应该将代码“拆分”成独立的包,这样用户只需要下载他们需要的部分。这可以减少用户加载应用所需的等待时间,因为他们只下载查看当前页面所需的代码。

🌐 But for ideal performance, you should “split” your code into separate bundles so the user only needs to download what they need. This decreases the time the user needs to wait to load your app, by only downloading the code they need to see the page they are on.

- core.js 25kb
- home.js 25kb
- dashboard.js 25kb

一种进行代码拆分的方法是使用 React.lazy。然而,这意味着代码直到组件渲染时才会被获取,这可能会导致网络瀑布效应。一个更优化的解决方案是使用路由功能在代码下载时并行获取代码。例如,React Router 提供了一个 lazy 选项,用于指定路由应进行代码拆分并优化加载时机:

🌐 One way to do code-splitting is with React.lazy. However, this means that the code is not fetched until the component renders, which can cause network waterfalls. A more optimal solution is to use a router feature that fetches the code in parallel while the code is downloading. For example, React Router provides a lazy option to specify that a route should be code split and optimize when it is loaded:

import Home from './Home';
import Dashboard from './Dashboard';

// ✅ Routes are downloaded before rendering
const router = createBrowserRouter([
{path: '/', lazy: () => import('./Home')},
{path: '/dashboard', lazy: () => import('Dashboard')}
]);

优化的代码拆分很难做到完美,很容易出现错误,导致用户下载比所需更多的代码。当与路由和数据加载解决方案集成时,它的效果最佳,可以最大化缓存、并行化获取,并支持 “按交互导入” 模式。

🌐 Optimized code-splitting is tricky to get right, and it’s easy to make mistakes that can cause the user to download more code than they need. It works best when integrated with your router and data loading solutions to maximize caching, parallelize fetches, and support “import on interaction” patterns.

还有更多…

🌐 And more…

这些只是 Create React App 限制的一些例子。

🌐 These are just a few examples of the limitations of Create React App.

一旦你整合了路由、数据获取和代码分割,你现在还需要考虑待处理的状态、导航中断、向用户显示的错误信息以及数据的重新验证。有一些完整的用户需要解决的问题类别,如:

🌐 Once you’ve integrated routing, data-fetching, and code splitting, you now also need to consider pending states, navigation interruptions, error messages to the user, and revalidation of the data. There are entire categories of problems that users need to solve like:

  • 无障碍
  • 资源加载
  • 身份验证
  • 缓存
  • 错误处理
  • 数据变更
  • 导航
  • 乐观更新
  • 渐进增强
  • 服务器端渲染
  • 静态网站生成
  • 流媒体

所有这些协同作用以创建最优的加载顺序

🌐 All of these work together to create the most optimal loading sequence.

在 Create React App 中单独解决每个问题可能很困难,因为每个问题都与其他问题相互关联,并且可能需要用户不熟悉的问题字段的深厚专业知识。为了处理这些问题,用户最终会在 Create React App 的基础上构建自己定制的解决方案,而这正是 Create React App 最初试图解决的问题。

🌐 Solving each of these problems individually in Create React App can be difficult as each problem is interconnected with the others and can require deep expertise in problem areas users may not be familiar with. In order to solve these problems, users end up building their own bespoke solutions on top of Create React App, which was the problem Create React App originally tried to solve.

我们为何推荐框架

🌐 Why we Recommend Frameworks

虽然你可以自己在像 Create React App、Vite 或 Parcel 这样的构建工具中解决所有这些部分,但做得好是很难的。就像 Create React App 本身将几个构建工具集成在一起一样,你需要一个工具将所有这些功能整合在一起,以为用户提供最佳体验。

🌐 Although you could solve all these pieces yourself in a build tool like Create React App, Vite, or Parcel, it is hard to do well. Just like when Create React App itself integrated several build tools together, you need a tool to integrate all of these features together to provide the best experience to users.

这种将构建工具、渲染、路由、数据获取和代码拆分集成在一起的工具类别被称为“框架”——或者如果你更愿意称 React 本身为框架,你可以称它们为“元框架”。

🌐 This category of tools that integrates build tools, rendering, routing, data fetching, and code splitting are known as “frameworks” — or if you prefer to call React itself a framework, you might call them “metaframeworks”.

框架对应用结构的某些方面提出了一些观点,以提供更好的用户体验,就像构建工具提出一些观点以简化工具使用一样。这就是为什么我们开始推荐像 Next.jsReact RouterExpo 这样的框架用于新项目的原因。

🌐 Frameworks impose some opinions about structuring your app in order to provide a much better user experience, in the same way build tools impose some opinions to make tooling easier. This is why we started recommending frameworks like Next.js, React Router, and Expo for new projects.

框架提供与 Create React App 相同的入门体验,但也提供解决用户在实际生产应用中必须解决的问题的方案。

🌐 Frameworks provide the same getting started experience as Create React App, but also provide solutions to problems users need to solve anyway in real production apps.

深入研究

服务器渲染是可选的

🌐 Server rendering is optional

我们推荐的框架都提供创建客户端渲染(CSR)应用的选项。

🌐 The frameworks we recommend all provide the option to create a client-side rendered (CSR) app.

在某些情况下,CSR 是页面的正确选择,但很多时候并非如此。即使你的大部分应用是客户端渲染的,通常也有一些单独的页面可以受益于服务器渲染功能,例如 静态站点生成(SSG)服务端渲染(SSR),例如服务条款页面或文档页面。

🌐 In some cases, CSR is the right choice for a page, but many times it’s not. Even if most of your app is client-side, there are often individual pages that could benefit from server rendering features like static-site generation (SSG) or server-side rendering (SSR), for example a Terms of Service page, or documentation.

服务器渲染通常向客户端发送较少的 JavaScript,并生成完整的 HTML 文档,从而通过减少总阻塞时间(TBT)实现更快的首次内容绘制(FCP),这也可以降低下一次绘制的交互时间(INP)。这就是为什么 Chrome 团队建议开发者考虑使用静态或服务器端渲染,而不是完全客户端渲染,以获得最佳性能的原因。

🌐 Server rendering generally sends less JavaScript to the client, and a full HTML document which produces a faster First Contentful Paint (FCP) by reducing Total Blocking Time (TBD), which can also lower Interaction to Next Paint (INP). This is why the Chrome team has encouraged developers to consider static or server-side render over a full client-side approach to achieve the best possible performance.

使用服务器存在权衡,并且它并不总是每个页面的最佳选择。在服务器上生成页面会产生额外的成本,并且生成页面需要时间,这可能会增加首字节时间 (TTFB)。性能最佳的应用能够根据每种策略的权衡,为每个页面选择合适的渲染策略。

🌐 There are tradeoffs to using a server, and it is not always the best option for every page. Generating pages on the server incurs additional cost and takes time to generate which can increase Time to First Byte (TTFB). The best performing apps are able to pick the right rendering strategy on a per-page basis, based on the tradeoffs of each strategy.

框架提供了在任何页面上使用服务器的选项,如果你愿意,但并不强制你使用服务器。这让你可以为应用中的每个页面选择合适的渲染策略。

🌐 Frameworks provide the option to use a server on any page if you want to, but do not force you to use a server. This allows you to pick the right rendering strategy for each page in your app.

服务器组件怎么办

🌐 What About Server Components

我们推荐的框架也支持 React 服务器组件。

🌐 The frameworks we recommend also include support for React Server Components.

服务器组件通过将路由和数据获取移到服务器端来帮助解决这些问题,并允许根据你渲染的数据而不是仅根据渲染的路由对客户端组件进行代码拆分,从而减少发送的 JavaScript 数量,以实现最佳的加载顺序

🌐 Server Components help solve these problems by moving routing and data fetching to the server, and allowing code splitting to be done for client components based on the data you render, instead of just the route rendered, and reducing the amount of JavaScript shipped for the best possible loading sequence.

服务器组件不需要服务器。它们可以在 CI 服务器上的构建时运行,以创建一个静态生成(SSG)应用,也可以在 Web 服务器上运行时执行,用于服务器端渲染(SSR)应用。

🌐 Server Components do not require a server. They can be run at build time on your CI server to create a static-site generated app (SSG) app, at runtime on a web server for a server-side rendered (SSR) app.

请参阅 介绍零包大小的 React 服务器组件文档 以获取更多信息。

🌐 See Introducing zero-bundle size React Server Components and the docs for more info.

注意

服务器渲染不仅仅用于搜索引擎优化

🌐 Server Rendering is not just for SEO

一个常见的误解是服务器渲染仅用于搜索引擎优化

🌐 A common misunderstanding is that server rendering is only for SEO.

虽然服务器渲染可以提升 SEO,但它也通过减少用户在看到屏幕上的内容之前需要下载和解析的 JavaScript 数量来提高性能。

🌐 While server rendering can improve SEO, it also improves performance by reducing the amount of JavaScript the user needs to download and parse before they can see the content on the screen.

这就是为什么 Chrome 团队鼓励开发者考虑使用静态或服务器端渲染,而不是完全的客户端渲染,以实现最佳性能。

🌐 This is why the Chrome team has encouraged developers to consider static or server-side render over a full client-side approach to achieve the best possible performance.


感谢 Dan Abramov 创建 Create React App,也感谢 Joe HaddadIan SchmitzBrody McKee 以及 许多其他人 多年来维护 Create React App。感谢 Brooks LybrandDan AbramovDevon GovettEli WhiteJack HerringtonJoe SavonaLauren TanLee RobinsonMark EriksonRyan FlorenceSophie AlpertTanner LinsleyTheo Browne 审阅并提供对这篇文章的反馈。

🌐 Thank you to Dan Abramov for creating Create React App, and Joe Haddad, Ian Schmitz, Brody McKee, and many others for maintaining Create React App over the years. Thank you to Brooks Lybrand, Dan Abramov, Devon Govett, Eli White, Jack Herrington, Joe Savona, Lauren Tan, Lee Robinson, Mark Erikson, Ryan Florence, Sophie Alpert, Tanner Linsley, and Theo Browne for reviewing and providing feedback on this post.