Vite
维特
Vite 是一个功能强大、性能卓越且可扩展的 JavaScript 项目开发环境。为了改进和扩展 Remix 的捆绑功能,我们现在支持 Vite 作为替代编译器。未来,Vite 将成为 Remix 的默认编译器。
经典 Remix 编译器与 Remix Vite
现有的 Remix 编译器可通过remix build
和remix dev
CLI 命令访问并通过remix.config.js
进行配置,现在被称为经典 Remix 编译器
。
Remix Vite 插件和 remix vite:build
和 remix vite:dev
CLI 命令统称为Remix Vite
。
除非另有说明,否则今后的文档将假定使用 Remix Vite。
入门
我们有几个不同的基于 Vite 的模板可供您入门。
这些模板包括一个 vite.config.ts
文件,用于配置 Remix Vite 插件。
配置
Remix Vite 插件通过项目根目录中的 vite.config.ts
文件进行配置。有关更多信息,请参阅我们的 Vite 配置文档。
Cloudflare
要开始使用 Cloudflare,您可以使用 cloudflare
模板:
有两种方法可以在本地运行 Cloudflare 应用程序:
虽然 Vite 提供了更好的开发体验,但 Wrangler 通过在 Cloudflare 的 workerd
运行时 而不是 Node 中运行服务器代码,提供了更接近 Cloudflare 环境的模拟。
Cloudflare 代理
为了在 Vite 中模拟 Cloudflare 环境,Wrangler 提供了 [Node 代理到本地 workerd
绑定] wrangler-getplatformproxy。
Remix 的 Cloudflare Proxy 插件为您设置了以下代理:
然后,代理可以在loader
或action
函数中的context.cloudflare
中使用:
查看 Cloudflare 的 getPlatformProxy
文档 以获取有关每个代理的更多信息。
绑定
要配置 Cloudflare 资源的绑定:
- 对于使用 Vite 或 Wrangler 进行本地开发,请使用 wrangler.toml
- 对于部署,请使用 Cloudflare 仪表板
每当您更改wrangler.toml
文件时,您都需要运行wrangler types
来重新生成绑定。
然后,您可以通过 context.cloudflare.env
访问您的绑定。
例如,将 KV 命名空间 绑定为 MY_KV
:
增强加载上下文
如果您想向加载上下文添加其他属性,
您应该从共享模块中导出 getLoadContext
函数,以便 Vite、Wrangler 和 Cloudflare Pages 中的加载上下文都以相同的方式增强:
getLoadContext
传递给 Cloudflare Proxy 插件和 functions/[[path]].ts
中的请求处理程序,否则您将获得不一致的加载上下文增强,具体取决于您运行应用程序的方式。
首先,将 getLoadContext
传递给 Vite 配置中的 Cloudflare Proxy 插件,以在运行 Vite 时增强加载上下文:
接下来,将 getLoadContext
传递给 functions/[[path]].ts
文件中的请求处理程序,以在运行 Wrangler 或部署到 Cloudflare Pages 时增强加载上下文:
拆分客户端和服务器代码
Vite 处理客户端和服务器代码混合使用的方式与 Classic Remix 编译器不同。有关更多信息,请参阅我们关于 [拆分客户端和服务器代码] [拆分客户端和服务器代码] 的文档。
新的构建输出路径
Vite 管理public
目录的方式与现有的 Remix 编译器有显著差异。Vite 将文件从public
目录复制到客户端构建目录,而 Remix 编译器则保持public
目录不变,并使用子目录(public/build
)作为客户端构建目录。
为了使默认的 Remix 项目结构与 Vite 的工作方式保持一致,构建输出路径已更改。现在有一个默认为build
的单个buildDirectory
选项,取代了单独的assetsBuildDirectory
和serverBuildDirectory
选项。这意味着,默认情况下,服务器现在编译为build/server
,客户端现在编译为build/client
。
这也意味着以下配置默认值已被更改:
- publicPath 已被 Vite 的
base
选项 取代,默认为"/"
而不是"/build/"
。 - serverBuildPath 已被
serverBuildFile
取代,默认为"index.js"
。此文件将写入您配置的buildDirectory
中的服务器目录。
Remix 转向 Vite 的原因之一是,这样您在采用 Remix 时需要学习的内容就会减少。 这意味着,对于您想要使用的任何其他捆绑功能,您应该参考 Vite 文档 和 Vite 插件社区,而不是 Remix 文档。
Vite 有许多现有 Remix 编译器未内置的 功能 和 插件。 使用任何此类功能都将导致现有 Remix 编译器无法编译您的应用,因此,只有您打算从现在开始专门使用 Vite 时才使用它们。
迁移
设置 Vite
👉 安装 Vite 作为开发依赖项
Remix 现在只是一个 Vite 插件,所以您需要将它连接到 Vite。
👉 在 Remix 应用程序的根目录中将 remix.config.js
替换为 vite.config.ts
[支持的 Remix 配置选项] vite-config 的子集应直接传递给插件:
HMR 和 HDR
Vite 为 HMR 等开发功能提供了强大的客户端运行时,
从而淘汰了 <LiveReload />
组件。在开发中使用 Remix Vite 插件时,
<Scripts />
组件将自动包含 Vite 的客户端运行时和其他仅供开发使用的脚本。
👉 删除 <LiveReload/>
,保留 <Scripts />
TypeScript 集成
Vite 处理各种不同文件类型的导入,有时方式与现有的 Remix 编译器不同,因此让我们从vite/client
引用 Vite 的类型,而不是从@remix-run/dev
引用过时的类型。
由于 vite/client
提供的模块类型与 @remix-run/dev
隐式包含的模块类型不兼容,因此您还需要在 TypeScript 配置中启用 skipLibCheck
标志。一旦 Vite 插件成为默认编译器,Remix 将来将不再需要此标志。
👉 更新 tsconfig.json
更新tsconfig.json
中的types
字段,并确保skipLibCheck
、module
和moduleResolution
均设置正确。
👉 更新/删除 remix.env.d.ts
删除 remix.env.d.ts
中的以下类型声明
如果 remix.env.d.ts
现在为空,请将其删除
从 Remix 应用服务器迁移
如果您在开发中使用remix-serve
(或不带-c
标志的remix dev
),则需要切换到新的最小开发服务器。
它内置于 Remix Vite 插件中,并将在您运行remix vite:dev
时接管。
Remix Vite 插件不会安装任何 全局 Node polyfill,因此如果您依赖 remix-serve
来提供它们,则需要自行安装。最简单的方法是在 Vite 配置顶部调用 installGlobals
。
Vite 开发服务器的默认端口与remix-serve
不同,因此如果您想维护相同的端口,则需要通过 Vite 的server.port
选项进行配置。
您还需要更新到新的构建输出路径,即服务器的build/server
和客户端资产的build/client
。
👉 更新你的 dev
、build
和 start
脚本
👉 在你的 Vite 配置中安装全局 Node polyfill
👉 配置你的 Vite 开发服务器端口(可选)
迁移自定义服务器
如果您在开发中使用自定义服务器,则需要编辑自定义服务器以使用 Vite 的 connect
中间件。
这会在开发过程中将资产请求和初始渲染请求委托给 Vite,让您即使使用自定义服务器也能从 Vite 出色的 DX 中受益。
然后,您可以在开发过程中加载名为virtual:remix / server-build
的虚拟模块来创建基于 Vite 的请求处理程序。
您还需要更新服务器代码以引用新的构建输出路径,即服务器构建的build/server
和客户端资产的build/client
。
例如,如果您使用 Express,可以按如下方式操作。
👉 更新你的 server.mjs
文件
👉 更新你的 build
、dev
和 start
脚本
如果您愿意,您也可以使用 TypeScript 编写自定义服务器。
然后,您可以使用 tsx
或 tsm
等工具来运行自定义服务器:
请记住,如果您这样做,初始服务器启动时速度可能会明显减慢。
迁移 Cloudflare 函数
<文档警告>
Remix Vite 插件仅正式支持 Cloudflare Pages,它专为全栈应用程序而设计,与 Cloudflare Workers Sites 不同。如果您当前正在使用 Cloudflare Workers Sites,请参阅 Cloudflare Pages 迁移指南。
👉 在 remix
插件之前添加 cloudflareDevProxyVitePlugin
,以正确覆盖 vite dev 服务器的中间件!
您的 Cloudflare 应用可能正在设置 [Remix Config server
字段] remix-config-server 以生成一个 catch-all Cloudflare 函数。
使用 Vite,这种间接操作不再必要。
相反,您可以直接为 Cloudflare 编写一个 catch-all 路由,就像您为 Express 或任何其他自定义服务器编写路由一样。
👉 为 Remix 创建一个万能路由
👉 通过 context.cloudflare.env
而不是 context.env
访问绑定和环境变量
虽然您在开发过程中主要使用 Vite,但您也可以使用 Wrangler 来预览和部署您的应用程序。
要了解更多信息,请参阅本文档的 Cloudflare 部分。
👉 更新你的 package.json
脚本
迁移引用以构建输出路径
使用现有 Remix 编译器的默认选项时,服务器被编译为 build
,客户端被编译为 public/build
。由于 Vite 通常使用其 public
目录的方式与现有 Remix 编译器不同,这些输出路径已发生更改。
👉 更新参考资料以构建输出路径
- 服务器现在默认编译到
build/server
中。 - 客户端现在默认编译到
build/client
中。
例如,要从 Blues Stack 更新 Dockerfile:
配置路径别名
Remix 编译器利用tsconfig.json
中的paths
选项来解析路径别名。这在 Remix 社区中很常见,用于将~
定义为app
目录的别名。
Vite 默认不提供任何路径别名。如果你依赖此功能,可以安装 vite-tsconfig-paths 插件,以自动解析 Vite 中 tsconfig.json
中的路径别名,以匹配 Remix 编译器的行为:
👉 安装 vite-tsconfig-paths
👉 将 vite-tsconfig-paths
添加到你的 Vite 配置
删除 @remix-run/css-bundle
Vite 内置了对 CSS 副作用导入、PostCSS 和 CSS 模块以及其他 CSS 捆绑功能的支持。Remix Vite 插件会自动将捆绑的 CSS 附加到相关路由。
使用 Vite 时,@remix-run/css-bundle
cssBundleHref
导出将始终为 undefined
。
👉 卸载 @remix-run/css-bundle
👉 删除对 cssBundleHref
的引用
如果路由的链接
功能仅用于连接cssBundleHref
,则可以将其完全删除。
修复 links
中引用的 CSS 导入
如果您 [在 links
函数中引用 CSS] regular-css,则需要更新相应的 CSS 导入以使用 [Vite 的显式 ?url
导入语法。] vite-url-imports
👉 在 links
中使用的 CSS 导入中添加 ?url
.css?url
导入需要 Vite v5.1 或更新版本
通过 PostCSS 启用 Tailwind
如果您的项目正在使用 Tailwind CSS,您首先需要确保您有一个 PostCSS 配置文件,它将被 Vite 自动获取。
这是因为当启用 Remix 的 tailwind
选项时,Remix 编译器不需要 PostCSS 配置文件。
👉 如果缺少,请添加 PostCSS 配置,包括 tailwindcss
插件
如果您的项目已经有 PostCSS 配置文件,则需要添加 tailwindcss
插件(如果尚不存在)。
这是因为当 Remix 的 tailwind
配置选项 启用时,Remix 编译器会自动包含此插件。
👉 如果缺少 tailwindcss
插件,请将其添加到你的 PostCSS 配置中
👉 迁移 Tailwind CSS 导入
如果您 [在 links
函数中引用 Tailwind CSS 文件] regular-css,则需要 [迁移 Tailwind CSS 导入语句。] fix-up-css-imports-referenced-in-links
添加 Vanilla Extract 插件
如果您使用 Vanilla Extract,则需要设置 Vite 插件。
👉 安装官方 Vite 的 Vanilla Extract 插件
👉 将 Vanilla Extract 插件添加到你的 Vite 配置
添加 MDX 插件
如果你使用 MDX,由于 Vite 的插件 API 是 Rollup 插件 API 的扩展,因此你应该使用官方的 MDX Rollup 插件:
👉 安装 MDX Rollup 插件
<文档信息>
Remix 插件需要处理 JavaScript 或 TypeScript 文件,因此必须先从其他语言(如 MDX)进行任何转译。 在这种情况下,这意味着将 MDX 插件放在 Remix 插件之前。
👉 将 MDX Rollup 插件添加到你的 Vite 配置
添加 MDX 前置内容支持
Remix 编译器允许您定义 MDX 中的 frontmatter。如果您使用此功能,则可以使用 remark-mdx-frontmatter 在 Vite 中实现此目的。
👉 安装所需的 Remark frontmatter 插件
👉 将 Remark frontmatter 插件传递给 MDX Rollup 插件
在 Remix 编译器中,frontmatter 导出名为attributes
。这与 frontmatter 插件的默认导出名称frontmatter
不同。虽然可以配置 frontmatter 导出名称,但我们建议更新您的应用代码以使用默认导出名称。
👉 将 MDX 文件中的 MDX attributes
导出重命名为 frontmatter
👉 将 MDX attributes
导出重命名为 frontmatter
以供消费者使用
定义 MDX 文件的类型
👉 将 *.mdx
文件的类型添加到 env.d.ts
将 MDX 前置内容映射到路由导出
Remix 编译器允许您在 frontmatter 中定义 headers
、meta
和 handle
路由导出。这个 Remix 特有的功能显然不受 remark-mdx-frontmatter
插件支持。如果您使用此功能,则应手动将 frontmatter 映射到路由导出:
👉 将前言映射到 MDX 路由的路由出口
请注意,由于您明确映射了 MDX 路由导出,因此您现在可以自由使用您喜欢的任何前置结构。
更新 MDX 文件名用法
Remix 编译器还提供了从所有 MDX 文件中导出filename
的功能。这主要是为了能够链接到 MDX 路由集合。如果您使用此功能,您可以在 Vite 中通过 glob imports 实现此功能,它为您提供了一个将文件名映射到模块的便捷数据结构。这使得维护 MDX 文件列表变得更加容易,因为您不再需要手动导入每个文件。
例如,要导入posts
目录中的所有 MDX 文件:
这相当于手写:
如果愿意,您还可以立即导入所有 MDX 文件:
调试
您可以使用 [NODE_OPTIONS
环境变量] node-options 来启动调试会话:
然后,您可以从浏览器中附加调试器。
例如,在 Chrome 中,您可以打开chrome://inspect
或单击开发工具中的 NodeJS 图标来附加调试器。
vite-插件-检查
vite-plugin-inspect
向您展示每个 Vite 插件如何转换您的代码以及每个插件需要多长时间。
表现
Remix 包含一个用于性能分析的 --profile
标志。
当使用--profile
运行时,将生成一个.cpuprofile
文件,可以共享或上传到speedscope.app进行分析。
您还可以在开发服务器运行时按p + enter
来在开发中进行分析,以启动新的分析会话或停止当前会话。
如果您需要分析开发服务器启动,您还可以使用--profile
标志在启动时初始化分析会话:
请记住,您可以随时查看 Vite 性能文档 获取更多提示!
捆绑分析
要可视化和分析你的包,你可以使用 rollup-plugin-visualizer 插件:
然后,当你运行 remix vite:build
时,它会在每个包中生成一个 stats.html
文件:
在浏览器中打开stats.html
来分析您的捆绑包。
故障排除
查看 [调试][调试] 和 [性能][性能] 部分,了解常规故障排除技巧。 此外,查看 github 上 remix vite 插件的已知问题,看看是否有其他人遇到类似问题。
高温热释光
如果您期待热更新但却得到整个页面重新加载, 请查看我们的关于热模块替换的讨论,以了解有关 React Fast Refresh 的局限性以及常见问题的解决方法的更多信息。
ESM/CJS
Vite 同时支持 ESM 和 CJS 依赖项,但有时您仍可能会遇到 ESM / CJS 互操作问题。 通常,这是因为依赖项未正确配置为支持 ESM。 我们不会责怪他们,正确支持 ESM 和 CJS 真的很棘手。
有关修复示例错误的演练,请查看🎥 如何修复 Remix 中的 CJS/ESM 错误。
要诊断您的某个依赖项是否配置错误,请检查 publint 或 类型是否错误。
此外,您可以使用 vite-plugin-cjs-interop 插件 解决外部 CJS 依赖项的默认
导出问题。
最后,您还可以明确配置要将哪些依赖项捆绑到使用 Vite 的 ssr.noExternal
选项 捆绑的服务器中,以使用 Remix Vite 插件模拟 Remix 编译器的 serverDependenciesToBundle
。
开发过程中浏览器中的服务器代码错误
如果您在开发过程中在浏览器控制台中看到指向服务器代码的错误,则可能需要明确隔离仅限服务器的代码。 例如,如果您看到类似以下内容:
然后,您需要追踪哪个模块正在引入除服务器专用全局变量(如process
)之外的依赖项,并在 单独的 .server
模块或使用 vite-env-only
中隔离代码。
由于 Vite 使用 Rollup 在生产环境中对您的代码进行树形调整,因此这些错误只会在开发过程中发生。
与其他基于 Vite 的工具一起使用插件(例如 Vitest、Storybook)
Remix Vite 插件仅适用于应用程序的开发服务器和生产版本。 虽然还有其他基于 Vite 的工具(例如 Vitest 和 Storybook)使用 Vite 配置文件,但 Remix Vite 插件并非设计用于这些工具。 我们目前建议在与其他基于 Vite 的工具一起使用时排除该插件。
对于 Vitest:
对于故事书:
或者,您可以为每个工具使用单独的 Vite 配置文件。 例如,要使用专门针对 Remix 的 Vite 配置:
当不提供 Remix Vite 插件时,你的设置可能还需要提供 Vite Plugin React。例如,当使用 Vitest 时:
文档重新安装时样式在开发中消失
当使用 React 渲染整个文档(如 Remix 所做的那样)时,您可能会在将元素动态注入head
元素时遇到问题。如果重新安装文档,现有的head
元素将被删除并替换为一个全新的元素,从而删除 Vite 在开发过程中注入的所有style
元素。
这是一个已知的 React 问题,已在其 canary 发布渠道 中修复。如果您了解所涉及的风险,您可以将您的应用固定到特定的 React 版本,然后使用 package overrides 确保这是整个项目中使用的唯一 React 版本。例如:
值得强调的是,Vite 注入的样式问题仅发生在开发阶段。生产版本不会出现此问题,因为会生成静态 CSS 文件。
在 Remix 中,当 [根路由的默认组件导出] route-component 与其 [ErrorBoundary] error-boundary 和/或 [HydrateFallback] hydrate-fallback 导出之间交替渲染时,可能会出现此问题,因为这会导致安装新的文档级组件。
由于 Hydration 错误,React 会从头开始重新渲染整个页面,因此也可能发生这种情况。Hydration 错误可能是由您的应用代码引起的,也可能是由操纵文档的浏览器扩展引起的。
这与 Vite 息息相关,因为在开发过程中,Vite 会将 CSS 导入转换为 JS 文件,并将其样式注入到文档中,这会产生副作用。Vite 这样做是为了支持静态 CSS 文件的延迟加载和 HMR。
例如,假设您的应用具有以下 CSS 文件:
在开发过程中,此 CSS 文件在导入时将作为副作用转换为以下 JavaScript 代码:
这种转换不适用于生产代码,这就是为什么这个样式问题只影响开发。
Wrangler 开发中的错误
使用 Cloudflare Pages 时,您可能会遇到来自 wrangler pages dev
的以下错误:
这是 [Wrangler 的已知问题] cloudflare-request-clone-errors。
致谢
Vite 是一个了不起的项目,我们非常感谢 Vite 团队所做的工作。 特别感谢 Vite 团队的 Matias Capeletto、Arnaud Barré 和 Bjorn Lu 的指导。
Remix 社区很快就探索了 Vite 支持,我们感谢他们的贡献:
最后,我们受到了其他框架实现 Vite 支持的启发: