Fresh 1.1 - 自动 JSX、插件、DevTools 等
Fresh 是 Deno 的一个全新全栈 Web 框架。默认情况下,使用 Fresh 构建的网页不会向客户端发送任何 JavaScript。该框架没有构建步骤,这使得开发体验和部署时间得到了数量级的提升。
今天我们发布了 Fresh 的下一个重要版本。1.1 版本带来了许多重要的改进,使 Fresh 更易于使用、更快、总体上更有用。本次发布的一些亮点包括
- 自动 JSX
- 插件
- 支持 Preact Signals
- 支持 Preact DevTools
- 明确渲染 404 页面
- 堆叠式中间件
- 实验性
Deno.serve
支持 - 展示与“Made with 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
您现在可以使用适用于 Chrome、Firefox 和 Edge 的 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 中。该徽章也提供深色版本。
按照以下说明将徽章添加到您的项目: https://github.com/denoland/fresh#badges