Fresh 是 Deno 的全新全栈 Web 框架。默认情况下,使用 Fresh 构建的网页不会向客户端发送 JavaScript。该框架没有构建步骤,可以将部署时间缩短一个数量级。近日,Fresh 发布了第一个稳定版本。
Fresh 使用了一种不同的模型:默认情况下,开发者会将 0 KB 的 JS 发送给客户端。因为大多数渲染在服务器上完成,客户端只负责重新渲染交互性的小模块。这是一个开发者明确选择客户端渲染特定组件的模型。早在 2020 年,Jason Miller 在他的 Islands Architecture 博客文章中就描述了这个模型。
Fresh 核心是路由框架和模板引擎的组合,支持在服务器上按需渲染页面。除了在服务器中提供的即时 (JIT) 渲染之外,Fresh 还提供了一个接口,用于在客户端上无缝渲染某些组件,以实现最大的交互性。该框架使用 Preact 和 JSX(或 TSX)在服务器和客户端上进行渲染和模板化。客户端渲染在每个组件级别上是完全可选的,因此许多应用程序根本不会向客户端发送任何 JavaScript。
由于 Fresh 没有构建步骤,因此开发者编写的代码直接就是在服务器和客户端上运行的代码。将 TypeScript 或 JSX 转换为纯 JavaScript 的任何必要转换都是在需要时即时完成的。这允许通过即时部署实现非常快速的迭代循环。
Fresh 不仅仅是一个前端框架,而是一个用于编写网站的完全集成系统。开发者可以任意处理任何类型的请求、返回自定义响应、发出数据库请求等等。此路由返回纯文本 HTTP 响应而不是 HTML 页面,例如:
// routes/api/joke.ts
const JOKES = [/** jokes here */];
export const handler = (_req: Request): Response => {
const randomIndex = Math.floor(Math.random() * JOKES.length);
const body = JOKES[randomIndex];
return new Response(body);
};
这也可以用于为路由进行异步数据获取。下面是从磁盘上的文件加载博客文章的路由:
// routes/blog/[id].tsx
import { HandlerContext, PageProps } from "$fresh/server.ts";
export const handler = async (_req: Request, ctx: HandlerContext): Response => {
const body = await Deno.readTextFile(`./posts/${ctx.params.id}.md`);
return ctx.render({ body });
};
export default function BlogPostPage(props: PageProps) {
const { body } = props.data;
// ...
}
因为 Fresh 非常依赖动态服务器端渲染,所以速度必须快。Fresh 非常适合在 Deno Deploy、Netlify Edge Functions 或 Supabase Edge Functions 等边缘 runtime 场景运行。由于渲染过程在物理上非常靠近用户,从而可以最大限度地减少网络延迟。
Fresh 亮点特性
- 无构建步骤
- 零配置
- 边缘 JIT 渲染
- 轻量且快速(框架不需要客户端 JS)
- 单个组件支持可选的客户端 Hydration
- 由于采用渐进式增强和使用原生浏览器功能而具有很强的适应性
- 开箱即用的 TypeScript
- 文件系统路由采用 Next.js
Fresh 1.0 是一个稳定版本,支持在生产环境使用。通过 Deno,Fresh 项目可以手动部署到任何平台,但部署到像 Deno Deploy 这样的边缘运行时可获得最佳体验。