跳到主要内容
Deno 2.4 发布,带来了 deno bundle、字节/文本导入、OTel 稳定版等功能
了解更多
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/std@0.140.0/http/server.ts";
import { router } from "https://crux.land/router@0.0.11";
import { h, ssr } from "https://crux.land/nanossr@0.0.4";

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,其中包含我们的NavBar,它是页面顶部的菜单导航。我们正在进行服务器端模板化,使用与客户端相同的方式在不同页面之间共享组件。

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

这里提到的所有内容都可以在实验场中查看。