首页   

【第3458期】React 团队宣布停止维护 Create React App

前端早读课  · 前端  · 2 天前

正文

前言

React 团队宣布停止维护 Create React App,并鼓励现有应用迁移到框架或构建工具。今日前端早读课文章由@Matt Carroll 和 Ricky Hanlon分享,公号:前端圈授权。

译文从这开始~~

今天,我们不再推荐使用 Create React App 来创建新应用,并建议现有的应用迁移到框架,或者迁移到像 Vite、Parcel 或 RSBuild 这样的构建工具。

我们还提供了文档,帮助那些不适合使用框架的项目,或者更倾向于从头构建框架的开发者。

2016 年,我们发布 Create React App 时,业界还没有一个清晰的构建 React 应用的方法。

要创建一个 React 应用,你必须安装一堆工具并自己将它们连接在一起,以支持 JSX、代码检查(linting)和热重载等基本功能。要正确完成这些工作非常棘手,因此社区为常见的配置创建了样板代码(boilerplates)。然而,样板代码很难更新,而且碎片化使得 React 难以发布新功能。

Create React App 通过将多个工具组合成一个推荐配置来解决这些问题。这使得应用能够轻松地升级到新的工具特性,并让 React 团队能够将重要的工具改进(如 Fast Refresh 支持、React Hooks 代码检查规则)推广给尽可能广泛的用户。

这种模式变得如此流行,以至于现在有一整类工具都采用这种方式工作。

停用 Create React App

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

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

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

图片

create-react-app 已被弃用。
您可以在 react.dev 上找到最新的 React 框架列表。
更多信息,请参阅:react.dev/link/cra
此错误消息每次安装只显示一次。

如何迁移到框架

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

对于现有应用,以下指南将帮助你迁移到纯客户端 SPA:

  • Next.js 的 Create React App 迁移指南

  • React Router 的框架采用指南

  • Expo Webpack 迁移到 Expo Router 的指南

Create React App 将继续以维护模式运行,我们已发布了与 React 19 兼容的新版本。

如何迁移到构建工具

如果你的应用有特殊限制,或者你更喜欢通过构建自己的框架来解决这些问题,或者你只是想从头开始学习 React 如何工作,你可以使用 Vite 或 Parcel 自定义 React 设置。

为了帮助用户上手 Vite 或 Parcel,我们发布了关于《构建框架》的新文档。继续阅读以了解更多关于 Create React App 的局限性以及为什么我们推荐使用框架。

  • 构建框架:https://react.dev/learn/building-a-react-framework

  • 局限性:https://react.dev/blog/2025/02/14/sunsetting-create-react-app#limitations-of-create-react-app

  • 为什么我们推荐使用框架:https://react.dev/blog/2025/02/14/sunsetting-create-react-app#why-we-recommend-frameworks

注意

你们是否推荐 Vite?

我们提供了几项基于 Vite 的推荐。

React Router v7 是一个基于 Vite 的框架,它允许你使用 Vite 的快速开发服务器和构建工具,同时提供路由和数据获取功能。正如我们推荐的其他框架一样,你可以使用 React Router v7 构建单页应用(SPA)。

我们还建议在将 React 添加到现有项目或构建框架时使用 Vite。

就像 Svelte 有 Sveltekit、Vue 有 Nuxt、Solid 有 SolidStart 一样,React 推荐在新项目中使用与 Vite 等构建工具集成的框架来开展新项目。

Create React App 的局限性

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

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

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

这使你能够立即开始使用 React 编码,具备 JSX、默认代码检查规则以及可在开发和生产环境中运行的打包工具等功能。然而,这种设置缺少构建真正的生产应用所需的工具。

大多数生产应用都需要解决诸如路由、数据获取和代码分割等问题。

路由(Routing)

Create React App 不包含特定的路由解决方案。如果你刚刚入口,一种选择是使用 useState 在状态中切换路由。但这样做意味着你无法分享应用中的链接 - 每个链接都会指向同一个页面 - 而且随着时间推移,应用的结构会变得越来越难以管理:

 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 Router 或 Tanstack Router 这样的路由库来解决路由问题的原因。使用路由库后,你可以为应用添加额外的路由,这不仅提供了有关应用结构的规范,并允许你开始分享路由链接。例如,使用 React Router 可以定义路由:

 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 的链接,应用将导航到仪表板页面。拥有路由库后,你可以添加其他功能,如嵌套路由、路由守卫和路由过渡,这些功能在没有路由库的情况下很难实现。
这里有一个权衡:路由库增加了应用的复杂性,但也提供了难以自行实现的功能。

数据获取(Data Fetching)

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

但这样做意味着数据会在组件渲染后才被获取,这可能会导致网络瀑布流(network waterfalls)。网络瀑布流是由于在应用渲染时而不是在代码下载的同时并行获取数据造成的:

 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>
)
}

在 useEffect 中获取数据意味着用户需要等待更长时间才能看到内容,即使数据本可以在更早的时候获取。为了解决这个问题,你可以使用像 React Query、SWR、Apollo 或 Relay 这样的数据获取库,它们提供了预获取数据的选项,以便在组件渲染之前就开始请求。

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

 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>
)
}

在初次加载时,路由器可以在路由渲染之前立即获取数据。当用户在应用中导航时,路由器能够同时获取数据和路由,实现并行获取。这减少了用户看到内容所需的时间,并能改善用户体验。
然而,这需要正确配置应用中的加载器,并在复杂性和性能之间做出权衡。

代码拆分(Code Splitting)

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

这意味着你的应用会被打包成一个单一的文件:

 - bundle.js    75kb

但为了达到理想的性能,你应该将代码 "拆分" 成多个文件,这样用户只需要下载他们需要的部分。通过只下载用户查看当前页面所需的代码,这减少了用户加载应用所需等待的时间。

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

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

 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')}
]);

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

更多问题...

这些只是 Create React App 局限性的几个例子。

一旦你集成了路由、数据获取和代码拆分,你现在还需要考虑待处理状态、导航中断、用户错误提示以及数据重新验证等问题。还有许多其他问题需要用户解决,例如:

  • 无障碍 (Accessibility)

  • 资源加载 (Asset loading)

  • 身份验证 (Authentication)

  • 缓存 (Caching)

  • 错误处理 (Error handling)

  • 数据变更 (Mutating data)

  • 导航 (Navigations)

  • 乐观更新 (Optimistic updates)

  • 渐进增强 (Progressive enhancement)

  • 服务端渲染 (Server-side rendering)

  • 静态站点生成 (Static site generation)

  • 流式传输 (Streaming)

所有这些协同工作以创建最佳的加载顺序。

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

我们为什么推荐框架

尽管你可以在像 Create React App、Vite 或 Parcel 这样的构建工具中自己解决所有这些问题,但要做好却很难。就像 Create React App 本身将多个构建工具集成在一起一样,你需要一个工具来集成所有这些功能,以提供最佳的用户体验。

这类集成构建工具、渲染、路由、数据获取和代码拆分的工具被称为 “框架”—— 或者如果您更喜欢将 React 本身称为框架,你可以称它们为 “元框架(metaframeworks)”。

框架对应用的结构提出了一些意见,以提供更好的用户体验,就像构建工具对工具链提出意见以简化工具使用一样。这就是我们开始推荐像 Next.js、React Router 和 Expo 这样的框架用于新项目的原因。

框架提供了与 Create React App 类似的入门体验,同时也为用户在真实生产应用中需要解决的问题提供了方案。

深入探讨

服务端渲染(Server rendering)是可选的

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

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

服务端渲染通常会向客户端发送更少的 JavaScript,并生成完整的 HTML,从而通过减少总阻塞时间 (TBD) 来加快首次内容绘制 (FCP),这也可以降低交互到下一次绘制 (INP)。这就是为什么 Chrome 团队鼓励开发者考虑静态或服务端渲染而非完全客户端渲染的方法,以实现最佳性能。

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

如果您愿意,框架提供了在任何页面上使用服务器渲染的选项,但不会强迫你使用服务器渲染。这允许你为应用中的每个页面选择正确的渲染策略。

关于 Server Components

我们推荐的框架还包括对 React Server Components 的支持。

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

Server Components 不需要服务器。它们可以在 CI 服务器上构建时运行,以创建静态站点生成 (SSG) 应用,或者在 Web 服务器上运行以创建服务端渲染 (SSR) 应用。

更多详情,请参阅《介绍零捆绑大小的 React Server Components》和相关文档。
https://react.dev/blog/2020/12/21/data-fetching-with-react-server-components

注意

服务端渲染不仅仅是为了 SEO

一个常见的误解是服务端渲染仅用于 SEO。

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

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

感谢 Dan Abramov 创建了 Create React App,以及 Joe Haddad、Ian Schmitz、Brody McKee 和许多其他人多年来维护 Create React App。感谢 Brooks Lybrand、Dan Abramov、Devon Govett、Eli White、Jack Herrington、Joe Savona、Lauren Tan、Lee Robinson、Mark Erikson、Ryan Florence、Sophie Alpert、Tanner Linsley 和 Theo Browne 审阅并提供有关本文的反馈。

关于本文
译者:@前端圈
译文:
https://mp.weixin.qq.com/s/PGuHycXvHpvFJ-qRUQtzJQ
作者:@Matt Carroll 和 Ricky Hanlon
原文:https://react.dev/blog/2025/02/14/sunsetting-create-react-app

这期前端早读课
对你有帮助,帮” 
 “一下,
期待下一期,帮”
 在看” 一下 。

© 2024 精读
删除内容请联系邮箱 2879853325@qq.com