Skip to content

SSG 助手

¥SSG Helper

SSG Helper 从你的 Hono 应用生成静态站点。它将检索已注册路由的内容并将其保存为静态文件。

¥SSG Helper generates a static site from your Hono application. It will retrieve the contents of registered routes and save them as static files.

用法

¥Usage

手动

¥Manual

如果你有一个简单的 Hono 应用,如下所示:

¥If you have a simple Hono application like the following:

tsx
// index.tsx
const app = new Hono()

app.get('/', (c) => c.html('Hello, World!'))
app.use('/about', async (c, next) => {
  c.setRenderer((content, head) => {
    return c.html(
      <html>
        <head>
          <title>{head.title ?? ''}</title>
        </head>
        <body>
          <p>{content}</p>
        </body>
      </html>
    )
  })
  await next()
})
app.get('/about', (c) => {
  return c.render('Hello!', { title: 'Hono SSG Page' })
})

export default app

对于 Node.js,创建如下构建脚本:

¥For Node.js, create a build script like this:

ts
// build.ts
import app from './index'
import { toSSG } from 'hono/ssg'
import fs from 'fs/promises'

toSSG(app, fs)

通过执行脚本,文件将输出如下:

¥By executing the script, the files will be output as follows:

bash
ls ./static
about.html  index.html

Vite 插件

¥Vite Plugin

使用 @hono/vite-ssg Vite 插件,你可以轻松处理该过程。

¥Using the @hono/vite-ssg Vite Plugin, you can easily handle the process.

有关更多详细信息,请参见此处:

¥For more details, see here:

https://github.com/honojs/vite-plugins/tree/main/packages/ssg

toSSG

toSSG 是生成静态站点的主要函数,以应用和文件系统模块作为参数。它基于以下内容:

¥toSSG is the main function for generating static sites, taking an application and a filesystem module as arguments. It is based on the following:

输入

¥Input

toSSG 的参数在 ToSSGInterface 中指定。

¥The arguments for toSSG are specified in ToSSGInterface.

ts
export interface ToSSGInterface {
  (
    app: Hono,
    fsModule: FileSystemModule,
    options?: ToSSGOptions
  ): Promise<ToSSGResult>
}
  • app 指定已注册路由的 new Hono()

    ¥app specifies new Hono() with registered routes.

  • fs 指定以下对象,假设 node:fs/promise

    ¥fs specifies the following object, assuming node:fs/promise.

ts
export interface FileSystemModule {
  writeFile(path: string, data: string | Uint8Array): Promise<void>
  mkdir(
    path: string,
    options: { recursive: boolean }
  ): Promise<void | string>
}

使用 Deno 和 Bun 的适配器

¥Using adapters for Deno and Bun

如果要在 Deno 或 Bun 上使用 SSG,则每个文件系统都提供了一个 toSSG 函数。

¥If you want to use SSG on Deno or Bun, a toSSG function is provided for each file system.

对于 Deno:

¥For Deno:

ts
import { toSSG } from 'hono/deno'

toSSG(app) // The second argument is an option typed `ToSSGOptions`.

对于 Bun:

¥For Bun:

ts
import { toSSG } from 'hono/bun'

toSSG(app) // The second argument is an option typed `ToSSGOptions`.

选项

¥Options

选项在 ToSSGOptions 接口中指定。

¥Options are specified in the ToSSGOptions interface.

ts
export interface ToSSGOptions {
  dir?: string
  concurrency?: number
  beforeRequestHook?: BeforeRequestHook
  afterResponseHook?: AfterResponseHook
  afterGenerateHook?: AfterGenerateHook
  extensionMap?: Record<string, string>
}
  • dir 是静态文件的输出目标。默认值为 ./static

    ¥dir is the output destination for Static files. The default value is ./static.

  • concurrency 是同时生成的文件数。默认值为 2

    ¥concurrency is the concurrent number of files to be generated at the same time. The default value is 2.

  • extensionMap 是一个映射,其中包含 Content-Type 作为键和扩展字符串作为值。这用于确定输出文件的文件扩展名。

    ¥extensionMap is a map containing the Content-Type as a key and the string of the extension as a value. This is used to determine the file extension of the output file.

稍后将描述每个 Hook。

¥Each Hook will be described later.

输出

¥Output

toSSG 以以下 Result 类型返回结果。

¥toSSG returns the result in the following Result type.

ts
export interface ToSSGResult {
  success: boolean
  files: string[]
  error?: Error
}

Hook

你可以通过在选项中指定以下自定义钩子来自定义 toSSG 的流程。

¥You can customize the process of toSSG by specifying the following custom hooks in options.

ts
export type BeforeRequestHook = (req: Request) => Request | false
export type AfterResponseHook = (res: Response) => Response | false
export type AfterGenerateHook = (
  result: ToSSGResult
) => void | Promise<void>

BeforeRequestHook/AfterResponseHook

toSSG 针对应用中注册的所有路由,但如果你想要排除某些路由,则可以通过指定 Hook 来过滤它们。

¥toSSG targets all routes registered in app, but if there are routes you want to exclude, you can filter them by specifying a Hook.

例如,如果你只想输出 GET 请求,请在 beforeRequestHook 中过滤 req.method

¥For example, if you want to output only GET requests, filter req.method in beforeRequestHook.

ts
toSSG(app, fs, {
  beforeRequestHook: (req) => {
    if (req.method === 'GET') {
      return req
    }
    return false
  },
})

例如,如果你只想在 StatusCode 为 200 或 500 时输出,请在 afterResponseHook 中过滤 res.status

¥For example, if you want to output only when StatusCode is 200 or 500, filter res.status in afterResponseHook.

ts
toSSG(app, fs, {
  afterResponseHook: (res) => {
    if (res.status === 200 || res.status === 500) {
      return res
    }
    return false
  },
})

AfterGenerateHook

如果你想钩子 toSSG 的结果,请使用 afterGenerateHook

¥Use afterGenerateHook if you want to hook the result of toSSG.

ts
toSSG(app, fs, {
  afterGenerateHook: (result) => {
    if (result.files) {
      result.files.forEach((file) => console.log(file))
    }
  })
})

生成文件

¥Generate File

路由和文件名

¥Route and Filename

以下规则适用于注册的路由信息​​和生成的文件名。默认 ./static 的行为如下:

¥The following rules apply to the registered route information and the generated file name. The default ./static behaves as follows:

  • / -> ./static/index.html

  • /path -> ./static/path.html

  • /path/ -> ./static/path/index.html

文件扩展名

¥File Extension

文件扩展名取决于每个路由返回的 Content-Type。例如,来自 c.html 的响应保存为 .html

¥The file extension depends on the Content-Type returned by each route. For example, responses from c.html are saved as .html.

如果你想要自定义文件扩展名,请设置 extensionMap 选项。

¥If you want to customize the file extensions, set the extensionMap option.

ts
import { toSSG, defaultExtensionMap } from 'hono/ssg'

// Save `application/x-html` content with `.html`
toSSG(app, fs, {
  extensionMap: {
    'application/x-html': 'html',
    ...defaultExtensionMap,
  },
})

请注意,无论扩展名是什么,以斜杠结尾的路径都会保存为 index.ext。

¥Note that paths ending with a slash are saved as index.ext regardless of the extension.

ts
// save to ./static/html/index.html
app.get('/html/', (c) => c.html('html'))

// save to ./static/text/index.txt
app.get('/text/', (c) => c.text('text'))

中间件

¥Middleware

引入支持 SSG 的内置中间件。

¥Introducing built-in middleware that supports SSG.

ssgParams

你可以使用 Next.js 的 generateStaticParams 之类的 API。

¥You can use an API like generateStaticParams of Next.js.

示例:

¥Example:

ts
app.get(
  '/shops/:id',
  ssgParams(async () => {
    const shops = await getShops()
    return shops.map((shop) => ({ id: shop.id }))
  }),
  async (c) => {
    const shop = await getShop(c.req.param('id'))
    if (!shop) {
      return c.notFound()
    }
    return c.render(
      <div>
        <h1>{shop.name}</h1>
      </div>
    )
  }
)

disableSSG

具有 disableSSG 中间件集的路由被 toSSG 排除在静态文件生成之外。

¥Routes with the disableSSG middleware set are excluded from static file generation by toSSG.

ts
app.get('/api', disableSSG(), (c) => c.text('an-api'))

onlySSG

具有 onlySSG 中间件集的路由将在 toSSG 执行后被 c.notFound() 覆盖。

¥Routes with the onlySSG middleware set will be overridden by c.notFound() after toSSG execution.

ts
app.get('/static-page', onlySSG(), (c) => c.html(<h1>Welcome to my site</h1>))

Hono v4.7 中文网 - 粤ICP备13048890号