跳到主要内容
Deno 2.4 发布,带来 deno bundle、字节/文本导入、稳定的 OTel 以及更多功能
了解更多
Deno dinosaur flying with a lemon balloon

Fresh 1.1 - 自动 JSX、插件、DevTools 等

Fresh 是 Deno 的一个全新全栈 Web 框架。默认情况下,使用 Fresh 构建的网页不会向客户端发送任何 JavaScript。该框架没有构建步骤,这使得开发体验和部署时间得到了数量级的提升。

今天我们发布了 Fresh 的下一个重要版本。1.1 版本带来了许多重要的改进,使 Fresh 更易于使用、更快、总体上更有用。本次发布的一些亮点包括

要创建一个新的 Fresh 项目,您可以运行

$ deno run -A -r https://fresh.deno.dev my-app

要将项目更新到最新版本的 Fresh,请在项目根目录运行更新脚本

$ deno run -A -r https://fresh.deno.dev/update .

除了更新 Fresh 及其依赖项外,此脚本还可以对您的代码库应用 codemod,以使其与 Fresh 项目的最新建议保持同步。另请参阅 《概念:更新》 文档页面。

自动 JSX

新项目现在默认配置为使用自动模式 JSX。这意味着您不再需要在所有文件顶部添加 /** @jsx h */ 编译指示和 import { h } from "preact";。这极大地改善了开发体验,并消除了新用户常见的错误来源。

- /** @jsx h */
- import { h } from "preact";

  export default function AboutPage() {
    return (
      <main>
        <h1>About</h1>
        <p>This is the about page.</p>
      </main>
    );
  }

现有项目可以通过 Fresh 更新脚本中的 codemod 更新为使用自动模式。或者,您可以通过在项目根目录的 deno.json 文件中添加以下行来手动启用它

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact"
  }
}

完成此操作后,您必须从 JSX/TSX 文件中移除所有 /** @jsx h */ 编译指示和 import { h } from "preact"; 导入。自动模式和非自动模式不能在同一项目中混合使用。

插件

插件是一种新的方式,可以在不修改 Fresh 核心的情况下扩展其功能。目前,插件只能用于协调渲染并将样式和脚本注入到渲染后的 HTML 中。这对于像 twind 这样的样式框架很有用。它还可以用于将 Google Analytics 脚本注入页面,或全局加载一个 Web 组件

插件通过 main.ts 文件中传递给 start 函数的选项包中的 plugins 属性定义。

这只是插件的首次迭代。未来版本将添加更多钩子,插件可以使用这些钩子来扩展 Fresh 的功能。未来,插件将能够为一个项目添加新的路由、中间件和 Islands。

插件文档可在 《概念:插件》 文档页面中找到。

截至目前,只有一个官方插件可用。随着插件系统功能的扩展,未来将添加更多插件。

官方 twind 插件

Twind 是一个小型 Tailwind-in-JS 实现,可以根据您 JSX 中使用的类即时生成 CSS。Fresh 的早期版本提供了一个选项,可以在项目初始化期间自动为您配置 Twind,但这导致了大量的样板代码。

借助新的插件系统,我们现在为 Twind 提供了一个 Fresh 官方插件。该插件会自动为您配置 Twind,以最大限度地减少项目中的样板代码。使用它非常简单,只需

  // main.ts
  import { start } from "$fresh/server.ts";
  import manifest from "./fresh.gen.ts";

+ import twindPlugin from "$fresh/plugins/twind.ts";
+ import twindConfig from "./twind.config.js";

  await start(manifest, {
+   plugins: [
+     twindPlugin(twindConfig),
+   ],
  });

借助这个新插件,在您的项目中使用 Twind 类变得更加简单。以前,您必须从 twind 模块导入 tw 函数,并将所有类名包装在其中。现在,您可以直接在 JSX 组件中指定类名,插件将处理其余部分。

  // pages/index.tsx
- import { tw } from "@twind";

  export default function IndexPage() {
    return (
-     <h1 class={tw`text-4xl font-bold`}>Hello, world!</h1>
+     <h1 class="text-4xl font-bold">Hello, world!</h1>
    );
  }

借助新插件,Twind 在客户端渲染期间也更可靠地工作,并且能够更好地解决服务器和客户端渲染样式表之间的冲突。

项目初始化脚本已更新为使用新的 Twind 插件,现在还会生成所有必需的文件,以便能够使用 Twind VSCode 扩展

更新脚本可用于通过 codemod 将您的项目更新为使用新的 Twind 插件。

支持 Preact Signals

新的 Fresh 项目现在自动配置为使用新的 Preact Signals。Signals 是 Preact 的一种新型响应式状态管理原语。它们旨在比 hooks 和 context 更快,同时也更符合人体工程学。

下面是使用 signals 而不是 hooks 的基本“计数器”组件示例。

import { useSignal } from "@preact/signals";
import { Button } from "../components/Button.tsx";

interface CounterProps {
  start: number;
}

export default function Counter(props: CounterProps) {
  const count = useSignal(props.start);
  return (
    <div>
      <p>{count}</p>
      <button onClick={() => count.value--}>-1</button>
      <button onClick={() => count.value++}>+1</button>
    </div>
  );
}

Signals 还提供了一种在 Fresh 项目中跨多个 island 管理共享状态的绝佳方式。查看 Fresh with Signals 演示以了解其工作原理。

对于现有项目,更新脚本将自动将 @preact/signals 依赖项添加到您的导入映射中。您也可以手动将依赖项添加到导入映射中——只需确保同时将 preact-render-to-string 更新到 >=5.2.3。

支持 Preact DevTools

您现在可以使用适用于 ChromeFirefoxEdge 的 Preact DevTools 扩展来检查 Fresh 项目的组件树。

这是调试您的 islands 问题并了解 Preact 如何渲染组件的绝佳方式。

要使用此功能,无需额外配置。只需更新到最新版本的 Fresh 并为您的浏览器安装 Preact DevTools 扩展即可。

此功能仅在开发期间可用。在生产环境中,Preact DevTools 集成不可用。这样做是为了减少发送给客户端的 JavaScript 数量。

感谢 Marvin Hagemeister 贡献此功能,并 改进了对基于 island 的 hydration 的 Preact DevTools 支持

明确渲染 404 页面

现在可以从路由处理程序中明确渲染 404 页面。如果您想根据数据库查询结果渲染 404 页面,或者在路由处理程序中进行更复杂的路由,这会很有用。

要渲染 404 页面,只需从您的路由处理程序中调用 ctx.renderNotFound(),而不是调用 ctx.render() 或返回自定义 Response 对象。就像使用 ctx.render() 一样,您可以在将返回的 Response 对象发送到客户端之前对其进行修改。

// routes/index.ts

export const handler: Handlers = {
  GET(req, ctx) {
    const url = new URL(req.url);
    const id = url.searchParams.get("id");
    if (!id) return ctx.renderNotFound(); // return a 404 page if no id is provided
    return ctx.render({ id });
  },
};

// ... page component here ...

感谢 Steven Yung 贡献此功能。

堆叠式中间件

现在可以为单个中间件路由设置多个中间件函数。如果您有多个不同的中间件函数都应该应用于给定的匹配器,这会很有用。这通过从中间件文件导出一个数组而不是单个函数来实现。

这是一个中间件模块示例,其中包含两个中间件函数:一个用于日志记录,另一个用于向响应添加计时头。

// routes/_middleware.ts

export const handler = [
  timing,
  logging,
];

async function timing(
  _req: Request,
  ctx: MiddlewareHandlerContext,
): Promise<Response> {
  const start = performance.now();
  const res = await ctx.next();
  const end = performance.now();
  const dur = (end - start).toFixed(1);
  res.headers.set("Server-Timing", `handler;dur=${dur}`);
  return res;
}

async function logging(
  req: Request,
  ctx: MiddlewareHandlerContext,
): Promise<Response> {
  const res = await ctx.next();
  console.log(`${req.method} ${req.url} ${res.status}`);
  return res;
}

感谢 @ahuigo 贡献此功能。

实验性 Deno.serve 支持

Deno v1.25 为 Deno 添加了一个新的高性能 HTTP 服务器。您可以在 Deno 1.25 发布说明中了解更多信息。它仅在 Deno v1.25 及更高版本中使用 --unstable 标志运行时可用。

Fresh 的此版本增加了对使用新的 Deno.serve API 的实验性支持,以替代现有的 std/http 服务器。Deno.serve 尚未稳定,因此不应在生产环境中使用。Deno.serve 在 Deno Deploy 上也不可用,因为它仍处于实验阶段。

要启用新服务器,您必须在 main.ts 文件中传递给 start() 方法的选项包中指定 experimentalDenoServe: true

展示与“Made with Fresh”徽章

Fresh 官网现在有一个 展示区,您可以在其中找到使用 Fresh 的项目列表。如果您有使用 Fresh 的项目,请 将其添加到列表中

除了展示区之外,我们现在还提供一个“Made with Fresh”徽章,您可以将其添加到您的网站或项目 README 中。该徽章也提供深色版本。

Made with Fresh

Made with Fresh(dark)

按照以下说明将徽章添加到您的项目: https://github.com/denoland/fresh#badges