Introduction, Technical Explanation
このコンテンツはまだ日本語訳がありません。
简介、技术说明
Remix 建立在 React Router 之上,具有以下四个特点:
- 编译器
- 服务器端 HTTP 处理程序
- 服务器框架
- 浏览器框架
编译器
Remix 中的一切都从编译器开始:remix vite:build
。使用 Vite,这会创建一些东西:
- 服务器 HTTP 处理程序,通常位于
build/server/index.js
(可配置),包含所有路由和模块,以便能够在服务器上呈现并处理任何其他服务器端资源请求。 - 浏览器构建,通常位于
build/client/*
。这包括按路由自动进行代码拆分、指纹资产导入(如 CSS 和图像)等。在浏览器中运行应用程序所需的一切。 - 资产清单。客户端和服务器都使用此清单来了解整个依赖关系图。这对于在初始服务器渲染中预加载资源以及为客户端转换预取它们非常有用。这就是 Remix 能够消除当今 Web 应用程序中常见的渲染 + 获取瀑布的方式。
利用这些构建工件,应用程序可以部署到任何运行 JavaScript 的托管服务。
HTTP 处理程序和适配器
虽然 Remix 在服务器上运行,但它实际上并不是一个服务器。它只是一个提供给实际 JavaScript 服务器的处理程序。
它基于 Web Fetch API 而非 Node.js 构建。这使得 Remix 可以在任何 Node.js 服务器(如 Vercel、Netlify、Architect 等)以及非 Node.js 环境(如 Cloudflare Workers 和 Deno Deploy)中运行。
Remix 在 Express 应用中运行时如下所示:
Express(或 Node.js)是实际的服务器,Remix 只是该服务器上的处理程序。@remix-run/express
包称为适配器。Remix 处理程序与服务器无关。适配器通过在传入过程中将服务器的请求/响应 API 转换为 Fetch API,然后将来自 Remix 的 Fetch Response 适配到服务器的响应 API,使它们适用于特定服务器。以下是适配器执行的操作的伪代码:
真正的适配器的功能比这要多一些,但这就是它的要点。这不仅使您能够在任何地方部署 Remix,还允许您在现有的 JavaScript 服务器中逐步采用它,因为您可以在 Remix 之外拥有路由,而服务器在到达 Remix 之前会继续处理这些路由。
此外,如果 Remix 尚未提供适合您的服务器的适配器,您可以查看其中一个适配器的源代码并构建自己的适配器。
服务器框架
如果您熟悉 Rails 和 Laravel 等服务器端 MVC Web 框架,那么 Remix 就是视图和控制器,但模型则由您决定。JavaScript 生态系统中有许多出色的数据库、ORM、邮件程序等可以填补这一空白。Remix 还提供了有关 Fetch API 的帮助程序,用于 cookie 和会话管理。
Remix Route 模块不再区分视图和控制器,而是同时承担两项职责。
大多数服务器端框架都是以模型为中心
的。控制器管理单个模型的多个 URL。
Remix 专注于 UI。路由可以处理整个 URL 或 URL 的某个片段。当路由仅映射到某个片段时,嵌套的 URL 片段将成为 UI 中的嵌套布局。这样,每个布局(视图)都可以是自己的控制器,然后 Remix 将聚合数据和组件以构建完整的 UI。
通常情况下,Remix 路由模块可以在同一个文件中同时包含 UI 和与模型的交互,从而大大提高开发人员的人体工程学和工作效率。
路由模块有三个主要导出:loader
、action
和default
(组件)。
实际上,您可以将 Remix 用作服务器端框架,而无需使用任何浏览器 JavaScript。使用loader
进行数据加载的路由约定、使用action
和 HTML 表单进行突变以及在 URL 处呈现的组件可以为许多 Web 项目提供核心功能集。
通过这种方式,Remix 可以缩小规模。并非应用程序中的每个页面都需要浏览器中的大量 JavaScript,也并非每个用户交互都需要任何比浏览器默认行为更高级的功能。在 Remix 中,您可以先以简单的方式构建它,然后在不更改基本模型的情况下进行扩展。此外,应用程序的大部分功能在 JavaScript 加载到浏览器中之前就可以运行,这使得 Remix 应用程序在设计上能够适应不稳定的网络条件。
如果您不熟悉传统的后端 Web 框架,您可以将 Remix 路由视为 React 组件,这些组件已经是自己的 API 路由,并且已经知道如何在服务器上加载和提交数据给自己。
浏览器框架
一旦 Remix 将文档提供给浏览器,它就会使用浏览器构建的 JavaScript 模块填充
页面。这就是我们经常谈论的 Remix模拟浏览器
的地方。
当用户点击链接时,Remix 无需往返服务器获取整个文档和所有资产,而是只需获取下一页的数据并更新 UI。
此外,当用户提交 <Form>
来更新数据时,浏览器运行时不会执行正常的 HTML 文档请求,而是会获取服务器的数据并自动重新验证页面上的所有数据并使用 React 进行更新。
与发出完整文档请求相比,这具有许多性能优势:
- 资产无需重新下载(或从缓存中提取)
- 资产无需再次由浏览器解析
- 获取的数据比整个文档小得多(有时是数量级)
- 由于 Remix 增强了 HTML API(
<a>
和<form>
),您的应用往往在 JavaScript 加载到页面之前就可以运行
Remix 还内置了一些针对客户端导航的优化。它知道哪些布局会在两个 URL 之间保持不变,因此它只获取正在更改的布局的数据。完整的文档请求需要在服务器上获取所有数据,这会浪费后端资源并降低应用速度。
这种方法还具有用户体验 (UX) 方面的优势,例如不重置侧边栏导航的滚动位置,并允许您将焦点移动到比文档顶部更有意义的地方。
当用户即将点击链接时,Remix 还可以预取页面的所有资源。浏览器框架知道编译器的资产清单。它可以匹配链接的 URL,读取清单,然后预取下一页的所有数据、JavaScript 模块甚至 CSS 资源。这就是 Remix 应用即使在网络较慢的情况下也能感觉很快的原因。
然后,Remix 提供了客户端 API,因此您无需改变 HTML 和浏览器的基本模型即可创建丰富的用户体验。
采用我们之前的路由模块,这里有一些小的,但有用的用户体验改进,只能在浏览器中使用 JavaScript 来执行:
- 提交表单时禁用按钮
- 服务器端表单验证失败时聚焦输入
- 在错误消息中添加动画
此代码示例最有趣的地方在于它只是附加的。整个交互从根本上来说仍然是相同的,甚至在 JavaScript 加载之前也可以在基本层面上工作,唯一的区别是用户反馈将由浏览器(旋转图标等)而不是应用程序(useNavigation().state
)提供。
由于 Remix 深入到后端的控制器级别,因此它可以无缝地完成此操作。
尽管它没有像 Rails 和 Laravel 等服务器端框架那样深入堆栈,但它确实深入到堆栈的更深处,进入浏览器,从而实现从后端到前端的无缝转换。
例如,在后端繁重的 Web 框架中构建纯 HTML 表单和服务器端处理程序与在 Remix 中一样容易。但是,一旦您想要跨越到具有动画验证消息、焦点管理和待处理 UI 的体验,就需要对代码进行根本性的更改。通常,人们会构建一个 API 路由,然后引入一些客户端 JavaScript 来连接两者。使用 Remix,您只需在现有的服务器端视图
周围添加一些代码,而无需从根本上改变其工作方式。浏览器运行时接管服务器通信,以提供超越默认浏览器行为的增强用户体验。
我们借用了一个旧术语,将其称为 Remix 中的渐进增强。从简单的 HTML 表单开始(Remix 会缩小),然后在有时间和雄心壮志时扩大 UI。