Future Flags
未来标志
以下未来标志已稳定并可供采用。要了解有关未来标志的更多信息,请参阅 开发策略
更新至最新 v2.x
首先更新到 v2.x 的最新次要版本以获取最新的未来标志。
👉 更新至最新 v2
npm install @remix-run/{dev,react,node,etc.}@2
Vite 插件
背景
Remix 不再使用自己的封闭编译器(现在称为 “经典编译器”),而是使用 Vite。Vite 是一个功能强大、性能卓越且可扩展的 JavaScript 项目开发环境。查看 Vite 文档 了解有关性能、故障排除等的更多信息。
虽然这不是未来的标志,但新功能和一些功能标志仅在 Vite 插件中可用,并且 Classic Compiler 将在下一版本的 Remix 中删除。
👉 安装 Vite
npm install -D vite
更新您的代码
👉 在 Remix 应用程序的根目录中将 remix.config.js
替换为 vite.config.ts
import { vitePlugin as remix } from "@remix-run/dev";import { defineConfig } from "vite";
export default defineConfig({ plugins: [remix()],});
支持的 Remix 配置选项 的子集应该直接传递给插件:
export default defineConfig({ plugins: [ remix({ ignoredRouteFiles: ["**/*.css"], }), ],});
👉 删除 <LiveReload/>
,保留 <Scripts />
import { LiveReload, Outlet, Scripts,}
export default function App() { return ( <html> <head> </head> <body> <Outlet /> <LiveReload /> <Scripts /> </body> </html> )}
👉 更新 tsconfig.json
更新 tsconfig.json
中的 types
字段,并确保 skipLibCheck
、module
和 moduleResolution
均设置正确。
{ "compilerOptions": { "types": ["@remix-run/node", "vite/client"], "skipLibCheck": true, "module": "ESNext", "moduleResolution": "Bundler" }}
👉 更新 / 删除 remix.env.d.ts
删除 remix.env.d.ts
中的以下类型声明
/// <reference types="@remix-run/dev" /> /// <reference types="@remix-run/node" />
如果 remix.env.d.ts
现在为空,请将其删除
rm remix.env.d.ts
配置路径别名
Vite 默认不提供任何路径别名。如果你依赖此功能,例如将 ~
定义为 app
目录的别名,则可以安装 vite-tsconfig-paths 插件以自动解析 Vite 中 tsconfig.json
中的路径别名,以匹配 Remix 编译器的行为:
👉 安装 vite-tsconfig-paths
npm install -D vite-tsconfig-paths
👉 将 vite-tsconfig-paths
添加到你的 Vite 配置
import { vitePlugin as remix } from "@remix-run/dev";import { defineConfig } from "vite";import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({ plugins: [remix(), tsconfigPaths()],});
删除 @remix-run/css-bundle
Vite 内置了对 CSS 副作用导入、PostCSS 和 CSS 模块以及其他 CSS 捆绑功能的支持。Remix Vite 插件会自动将捆绑的 CSS 附加到相关路由。
使用 Vite 时,@remix-run/css-bundle
cssBundleHref
导出将始终为 undefined
。
👉 卸载 @remix-run/css-bundle
npm uninstall @remix-run/css-bundle
👉 删除对 cssBundleHref
的引用
import { cssBundleHref } from "@remix-run/css-bundle"; import type { LinksFunction } from "@remix-run/node"; // or cloudflare/deno
export const links: LinksFunction = () => [ ...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []), // ... ];
修复links
中引用的 CSS 导入
如果您 在 links
函数中引用 CSS,则需要更新相应的 CSS 导入以使用 Vite 的显式 ?url
导入语法。
👉 在 links
中使用的 CSS 导入中添加 ?url
import styles from "~/styles/dashboard.css";import styles from "~/styles/dashboard.css?url";
export const links = () => { return [ { rel: "stylesheet", href: styles } ];}
迁移 Tailwind CSS 或 Vanilla Extract
如果您使用的是 Tailwind CSS 或 Vanilla Extract,请参阅完整迁移指南。
从 Remix 应用服务器迁移
👉 更新你的 dev
、build
和 start
脚本
{ "scripts": { "dev": "remix vite:dev", "build": "remix vite:build", "start": "remix-serve ./build/server/index.js" }}
👉 在你的 Vite 配置中安装全局 Node polyfill
import { vitePlugin as remix } from "@remix-run/dev";import { installGlobals } from "@remix-run/node";import { defineConfig } from "vite";
installGlobals();
export default defineConfig({ plugins: [remix()],});
👉 配置你的 Vite 开发服务器端口(可选)
export default defineConfig({ server: { port: 3000, }, plugins: [remix()],});
迁移自定义服务器
如果您正在迁移客户服务器或 Cloudflare Functions,请参阅完整迁移指南。
迁移 MDX 路线
如果您正在使用 MDX,则应使用官方的 MDX Rollup 插件。请参阅 完整迁移指南 了解分步指南。
v3_fetcherPersist 复制代码
背景
fetcher 的生命周期现在基于它何时返回空闲状态,而不是何时卸载其所有者组件:查看 RFC 了解更多信息。
👉 启用标志
remix({ future: { v3_fetcherPersist: true, },});
更新您的代码
它不太可能影响您的应用。您可能需要检查 “useFetchers” 的使用情况,因为它们的持续时间可能会比以前更长。根据您正在做的事情,您可能会比以前渲染更长的内容。
v3_relativeSplatPath
背景
更改多段 splats 路径(如 dashboard/*
,而不是 *
)的相对路径匹配和链接。查看 CHANGELOG 了解更多信息。
👉 启用标志
remix({ future: { v3_relativeSplatPath: true, },});
更新您的代码
如果您的任何路线带有路径 + splat,如 “dashboard.$.tsx” 或 “route (“dashboard/*”)”,并且其下方有相对链接,如 “” 或 “”,则您需要更新您的代码。
👉 将路线一分为二
对于任何 splat 路线,将其拆分为布局路线和带有 splat 的子路线:
└── routes ├── _index.tsx ├── dashboard.tsx └── dashboard.$.tsx
// orroutes(defineRoutes) { return defineRoutes((route) => { route("/", "home/route.tsx", { index: true }); route("dashboard/*", "dashboard/route.tsx") route("dashboard", "dashboard/layout.tsx", () => { route("*", "dashboard/route.tsx"); }); });},
👉 更新相关链接
更新该路线树中具有相对链接的任何 <Link>
元素,以包含额外的 ..
相对段,从而继续链接到同一位置:
// dashboard.$.tsx or dashboard/route.tsxfunction Dashboard() { return ( <div> <h2>Dashboard</h2> <nav> <Link to="">Dashboard Home</Link> <Link to="team">Team</Link> <Link to="projects">Projects</Link> <Link to="../">Dashboard Home</Link> <Link to="../team">Team</Link> <Link to="../projects">Projects</Link> </nav> </div> );}
v3_throwAbortReason
背景
当服务器端请求被中止时,例如当用户在加载器完成之前离开页面时,Remix 将抛出 “request.signal.reason” 而不是诸如 “new Error (“query () call aborted…”)” 之类的错误。
👉 启用标志
remix({ future: { v3_throwAbortReason: true, },});
更新您的代码
您可能不需要调整任何代码,除非您在 “handleError” 内部有与前一个错误消息匹配的自定义逻辑以将其与其他错误区分开来。
v3_singleFetch
背景
使用此标志,Remix 会在您的应用内进行 SPA 导航时采用 “单一获取” 方法处理数据请求。更多详细信息请参阅 docs,但我们选择采用此方法的主要原因是简单性。使用单一获取,数据请求现在的行为与文档请求一样,开发人员不再需要考虑如何管理标头、缓存等两者之间的细微差别。对于更高级的用例,开发人员仍然可以选择细粒度的重新验证。
👉 启用标志(和类型)
import { vitePlugin as remix } from "@remix-run/dev";import { defineConfig } from "vite";import tsconfigPaths from "vite-tsconfig-paths";
declare module "@remix-run/node" { // or cloudflare, deno, etc. interface Future { v3_singleFetch: true; }}
export default defineConfig({ plugins: [ remix({ future: { v3_singleFetch: true, }, }), tsconfigPaths(), ],});
更新您的代码
在启用标志的情况下,您应该能够基本按原样使用您的代码,但以下更改应随着时间的推移而进行,并且需要在下一个主要版本之前进行。
👉 删除 json ()/defer () 以支持原始对象
Single Fetch 支持开箱即用的 JSON 对象和 Promises,因此您可以从 loader
/action
函数返回原始数据:
import { json } from "@remix-run/node";
export async function loader({}: LoaderFunctionArgs) { let tasks = await fetchTasks(); return json(tasks); return tasks;}
import { defer } from "@remix-run/node";
export async function loader({}: LoaderFunctionArgs) { let lazyStuff = fetchLazyStuff(); let tasks = await fetchTasks(); return defer({ tasks, lazyStuff }); return { tasks, lazyStuff };}
如果你使用 json
/defer
的第二个参数在响应中设置自定义状态或标头,则可以继续通过新的 data
API 执行操作:
import { json } from "@remix-run/node";import { data } from "@remix-run/node";
export async function loader({}: LoaderFunctionArgs) { let tasks = await fetchTasks(); return json(tasks, { return data(tasks, { headers: { "Cache-Control": "public, max-age=604800" } });}
👉 调整服务器上止延迟
如果你在 entry.server.tsx
文件中使用自定义的 ABORT_DELAY
,则应该将其更改为使用 Single Fetch 利用的新 streamTimeout
API:
const ABORT_DELAY = 5000;// Reject/cancel all pending promises after 5 secondsexport const streamTimeout = 5000;
// ...
function handleBrowserRequest(/* ... */) { return new Promise((resolve, reject) => { const { pipe, abort } = renderToPipeableStream( <RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />, { onShellReady() { /* ... */ }, onShellError(error: unknown) { /* ... */ }, onError(error: unknown) { /* ... */ }, } );
setTimeout(abort, ABORT_DELAY); // Automatically timeout the React renderer after 6 seconds, which ensures // React has enough time to flush down the rejected boundary contents setTimeout(abort, streamTimeout + 1000); });}
v3_lazyRouteDiscovery
背景
使用此标志,Remix 不再在初始加载时将完整路由清单发送到客户端。相反,Remix 仅在清单中发送服务器呈现的路由,然后在用户浏览应用程序时获取其余路由。更多详细信息请参阅 docs 和 blog post
👉 启用标志
remix({ future: { v3_lazyRouteDiscovery: true, },});
更新您的代码
您不需要对应用程序代码进行任何更改即可使用此功能。
如果您希望禁用某些链接上的紧急路由发现,您可能会发现新的 <Link discover>
API 有一些用处。
unstable_optimizeDeps
在开发过程中选择自动启用 依赖项优化。此标志将保持 “不稳定” 状态,直到 React Router v7 推出,因此在升级到 React Router v7 之前,您无需在 Remix v2 应用中采用此功能。