跳到主要内容
Deno 2.4 发布,带来 deno bundle、字节/文本导入、OTel 稳定版及更多功能
了解更多
Fresh lemon

Fresh 1.5:局部视图、客户端导航等

今天,我们很高兴地宣布 Fresh 1.5 版本发布,这是一个用于构建全栈 Web 应用程序的快速、Deno 原生框架。

此版本包含一种全新的客户端导航方法,我们称之为 Partials(局部更新)。使用 HTML 属性,您可以配置您的 Fresh 应用程序,以便在无需页面重新加载的情况下,使用服务器渲染的标记替换已加载页面中的 HTML。这种导航方式使您的应用程序感觉更加灵敏,并防止在页面切换时丢失客户端 Island 组件的状态。

除了 Partials,Fresh 1.5 还包含多项改进和错误修复,旨在支持复杂的 UI 开发模式。

准备好尝试了吗?您可以通过运行以下命令来启动一个新的 Fresh 项目:

deno run -Ar https://fresh.deno.dev

您也可以通过在项目文件夹中运行以下命令来更新现有项目:

deno run -Ar https://fresh.deno.dev/update .

以下是 1.5 版的新功能概览。请继续阅读以获取所有详细信息,以及 Fresh 下一迭代 的预期功能。

Fresh 1.5 一览

使用 Partials 进行客户端导航

传统上,客户端导航在 Web 开发中很难做到恰到好处。它通常需要大量的样板代码和新的数据加载策略。对于 Fresh,我们希望以一种不要求开发者改变他们构建网站和应用程序方式的方法来解决这个问题。

Fresh 1.5 发布了一个名为 Partials 的新概念,通过融合客户端和服务器端导航,使 Fresh 应用程序更具应用感。Partials 背后的思想是,您可以标记页面中在导航时会发生变化的区域,Fresh 将只更新这些区域。最棒的是:Island 状态保持不变。

请注意,在 Fresh 文档页面上,搜索栏 Island 在页面之间导航时不再闪烁。

为了实现这一点,我们只需要在代码中更改两件事:

  1. f-client-nav 属性添加到容器元素中,使该节点下的任何链接都选择客户端导航和局部更新
  2. 使用 <Partial name="content">...</Partial> 组件包装主内容区域

然后,瞧!我们的文档现在拥有完整的客户端导航功能!完整的更改可以在 此 PR 中查看。

- import { asset, Head } from "$fresh/runtime.ts";
+ import { asset, Head, Partial } from "$fresh/runtime.ts";

  // ...snip

  export default function DocsPage(props: PageProps<Data>) {
    return (
-     <div class="flex flex-col min-h-screen">
+     <div class="flex flex-col min-h-screen" f-client-nav>
-       <Content page={props.page} />
+       <Partial name="docs-main">
+         <Content page={props.page} />
+       </Partial>
      </div>
    )
  }

在幕后,Fresh 会获取新页面,并仅从 HTML 响应中提取相关内容。

精细的局部修改

我们可以通过使用 f-partial 属性选择更精细的局部修改,从而进一步优化此模式。

- <a href="/docs/routes">Routes</a>
+ <a href="/docs/routes" f-partial="/partials/docs/routes">Routes</a>

当链接被点击时,我们将如预期般导航到 /docs/routes,但会从 /partials/docs/routes 获取新内容。在我们的例子中,这可以是一个精简的 HTML 页面,它只返回主要内容,并绕过直接在服务器上渲染外部文档。

export default function DocRoute() {
  return (
    <Partial name="content">
      {/* Render only the markdown content here */}
    </Partial>
  );
}

在单个 HTTP 响应中应用多个 Partial

Fresh 中 Partials 的一个巧妙之处在于,一个响应可以返回任意数量的局部更新。这样,您可以在一个 HTTP 响应中更新页面上多个不相关的区域。例如,这在在线商店中非常有用。

export default function AddToCart() {
  return (
    <>
      <Partial name="cart-items" mode="append">
        {/* Render the new cart item here */}
      </Partial>
      <Partial name="total-price">
        <p>Total: {totalPrice}</p>
      </Partial>
    </>
  );
}

指定替换模式

您可能已经在前面的示例中注意到,我们在 <Partial> 组件上使用了新的 mode="append" 属性。默认模式是始终替换局部内容,但通过 mode 属性,您可以指定如何将内容集成到活动页面中。我们添加了三种不同的合并模式:

  • replace - 替换现有局部内容(默认)
  • prepend - 在现有内容之前插入新内容
  • append - 在现有内容之后插入新内容

就个人而言,我们发现 append 模式在您拥有显示日志消息或类似列表数据的 UI 时非常有用。前往我们的文档了解更多关于 Partials 的信息。

我们一直想简化的一件事是活跃链接的样式设置。到目前为止,我们看到的大多数代码库都会通过大量组件转发当前 URL,以便检查 <a> 元素的 href 属性是否应以显示它是当前页面的方式进行样式设置。

事实是 Fresh 已经知道当前的 URL 是什么,并且可以为您自动完成此操作。无需手动传递当前 URL。Fresh 1.5 将为链接添加以下两个属性:

  • data-current - 添加到路径完全匹配的链接
  • data-ancestor - 添加到部分匹配当前 URL 的链接

以下是这些如何使用 CSS 设置样式的示例:

/* Give links pointing to the current page a green color */
a[data-current] {
  color: green;
}

/* Color all ancestor links of the current page the color peachpuff */
a[data-ancestor] {
  color: peachpuff;
}

…以及使用 twind

// Current link
<a href="/foo" class="[data-current]:text-green-600">...</a>

// Ancestor link
<a href="/foo" class="[data-ancestor]:font-bold">...</a>

自定义构建目标

在内部,Fresh 将优化前端资产的生成传递给 esbuild,它有一个非常酷的“目标”功能,允许您指定要支持的最低浏览器版本。esbuild 会据此尝试将指定范围内不受支持的较新 JavaScript 构造转换为这些旧引擎支持的格式。由于每个项目都有不同的要求,因此在我们的配置中暴露此功能早就该做了。

// fresh.config.ts
export default defineConfig({
  build: {
    target: ["chrome99", "firefox99", "safari15"],
  },
});

前往 esbuild 文档 查看所有可能的目标值列表。

分析打包文件

Fresh 1.5 暴露了 esbuild 的 metafile.json 文件,该文件可用于分析和检查实际发送到浏览器的模块。此文件可以通过运行项目构建任务生成。

构建完成后,您可以在 https://esbuild.org.cn/analyze/ 上检查元文件,该工具由 esbuild 项目本身提供。

感谢 Tiago Gimenes 将此功能添加到 Fresh!

Bar chart of the modules included in the assets for the fresh website.

错误覆盖层

我们也花了一些时间改进了开发者体验。Fresh 1.5 现在将渲染一个适当的错误覆盖层,并尽力向您显示错误的来源。请放心,这仅在您运行 dev.ts 时可见。

The error overlay in browser shows you an excerpt of where it occured, the stack trace, as well as the error message.

终端中显示的错误也将向您显示错误发生位置的视觉指示。

The terminal prints an excerpt of the surrounding area of where the stack trace points to.

这虽然是一个小小的改进,但对于我直接在 Fresh 上工作而言,已经证明非常有用。

其他值得注意的功能

  • 内联脚本自动获得一个 nonce 值,这使得使用内容安全策略 (CSP) 标头更方便
  • Deno KV OAuth 插件已移至 Fresh 仓库,因为它是一个一流的支持插件——感谢 Asher GomezMichael Herzner 添加此功能!
  • 插件 API 接收了 buildStartbuildEnd 钩子,分别在构建时调用。我们认为这两个是实验性的,因为我们将在不久的将来开始在插件 API 中暴露更多内容,并且这些可能会发生变化。

展望未来?

随着对 Partials 的支持,我们离发布 View Transitions API 也很近了。我们也渴望让 Partials 变得更加出色!我们还在考虑插件 API 的新添加功能以及更多内容。

与过去的周期一样,您可以在 GitHub 上关注下一迭代计划