跳到主要内容
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 */:这个编译指示告诉 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 上,能够实现 完美的页面速度评分。该站点通过加密的 HTTP 从全球 29 个数据中心的任播 IP 地址提供服务,完全托管,并将无限期地免费提供。

此处提及的所有内容都可以在playground上查看。