跳至主要内容
Deno 2 终于来了 🎉️
了解更多
Whole Website in a Single JavaScript File

一个完整的网站,只需一个 JavaScript 文件

此网站 是一个非常标准的演示网站;一个包含指向不同页面的链接的网站。除了整个网站都包含在一个 JavaScript 文件中,并在边缘,靠近用户的地方动态渲染之外,没什么特别的。

路由非常简单:我们使用 router 模块,该模块在内部使用 URLPattern 进行模式匹配。

/** @jsx h */
/// <reference no-default-lib="true"/>
/// <reference lib="dom" />
/// <reference lib="dom.asynciterable" />
/// <reference lib="deno.ns" />
import { serve } from "https://deno.land/[email protected]/http/server.ts";
import { router } from "https://crux.land/[email protected]";
import { h, ssr } from "https://crux.land/[email protected]";

const render = (component) => ssr(() => <App>{component}</App>);

serve(router(
  {
    "/": () => render(<Landing />),
    "/stats": () => render(<Stats />),
    "/bagels": () => render(<Bagels />),
  },
  () => render(<NotFound />),
));

我们有 3 个路径:/ 用于主页,/stats 用于一些统计信息,以及 /bagels 用于显示我们出售的各种百吉饼。我们还有一个回退处理程序(代码片段中的最后一个参数),它将在没有路径匹配时被调用,充当 404 页面。这些页面使用 标准库 中的 serve 函数提供服务。

对于 JSX 的渲染,我们使用 nanossr,它是一个微型服务器端渲染器,在内部使用 twind 进行样式化。这是通过使用 ssr 函数来实现的,该函数会传递一个回调函数,该回调函数应该返回 JSX。ssr 函数返回一个 Response。我们创建一个 render 函数以减少代码重复,只是为了整理代码。

但在所有这些之前,你可能注意到了一些奇怪的注释。让我们逐个看一下。

  • /** @jsx h */:此pragma 告诉 Deno 我们想要使用哪个函数来转译 JSX。
  • /// <reference no-default-lib="true"/>:Deno 默认情况下启用了各种 TypeScript 库;通过此注释,我们告诉它不要使用这些库,而是只使用我们手动指定的库。
  • /// <reference lib="dom" />/// <reference lib="dom.asynciterable" />/// <reference lib="deno.ns" />:这些库提供了各种类型。dom 库为我们提供了与 DOM 相关的各种类型,而 dom.asynciterable 定义了需要异步迭代器的函数,因为截至编写本文时,这些函数未包含在正常的 dom 库中。deno.ns 库为 Deno.* 命名空间下的所有函数和类提供了类型,例如 Deno.readFile。您可以阅读更多有关在 手册 中提供的各种库的信息。

让我们看看一些实际代码;在前面的代码片段中,您可能注意到我们将所有路由组件包装在一个 App 组件中。定义如下:

function App({ children }) {
  return (
    <div class="min-h-screen">
      <NavBar />
      {children}
    </div>
  );
}

它非常紧凑:它返回一个 div,在 div 中包含我们的 NavBar,这是我们页面顶部的菜单导航。我们正在服务器端进行模板化,使用与客户端相同的语言在不同页面之间共享组件。

托管在 Deno Deploy 上,这个小型网站能够实现 完美的页面速度评分。通过全球 29 个数据中心的加密 HTTP 从 anycast IP 地址提供服务,该网站完全托管,并且将在无限期内免费提供。

这里提到的所有内容都可以在 游乐场 上查看。