HonoX - Hono based meta framework
HonoX
HonoX 是一个简单快速的元框架,用于创建全栈网站或 Web API(前身为 Sonik)。它站在巨人的肩膀上,基于 Hono、Vite 和 UI 库构建而成。
注意:HonoX 目前处于“alpha 阶段”。根据 零版本语义化版本控制,同一主版本内可能会引入破坏性变更。
特性
- 基于文件的路由 - 你可以像使用 Next.js 一样创建大型应用。
- 快速 SSR - 借助 Hono,渲染速度极快。
- BYOR(自带渲染器) - 你可以使用自己的渲染器,而不仅限于使用 hono/jsx 的渲染器。
- 孤岛 hydration - 如果需要交互功能,创建一个孤岛即可。只有该孤岛的 JavaScript 会被 hydration。
- 中间件 - 它的工作方式与 Hono 一致,因此你可以使用大量 Hono 的中间件。
安装
你可以从 npm 安装 honox 包。
npm install hono honox
入门模板
如果您要开始一个新的 HonoX 项目,请使用 hono-create 命令。运行以下命令并选择 x-basic(使用箭头键查找该选项)。
npm create hono@latest
快速入门 - 基础篇
让我们使用 hono/jsx 作为渲染器创建一个基础的 HonoX 应用。此应用不包含客户端 JavaScript,通过服务器端渲染 JSX。
项目结构
以下是 HonoX 应用的典型项目结构。
.
├── app
│ ├── global.d.ts // global type definitions
│ ├── routes
│ │ ├── _404.tsx // not found page
│ │ ├── _error.tsx // error page
│ │ ├── _renderer.tsx // renderer definition
│ │ ├── merch
│ │ │ └── [...slug].tsx // matches `/merch/:category`, `/merch/:category/:item`, `/merch/:category/:item/:variant`
│ │ ├── about
│ │ │ └── [name].tsx // matches `/about/:name`
│ │ ├── blog
│ │ │ ├── index.tsx // matches /blog
│ │ │ └── (content)
│ │ │ ├── _renderer.tsx // renderer definition for routes inside this directory
│ │ │ └── [name].tsx // matches `/blog/:name`
│ │ └── index.tsx // matches `/`
│ └── server.ts // server entry file
├── package.json
├── tsconfig.json
└── vite.config.ts
vite.config.ts
开发所需的最低 Vite 配置如下:
import { defineConfig } from 'vite'
import honox from 'honox/vite'
export default defineConfig({
plugins: [honox()],
})
服务器入口文件
需要一个服务器入口文件。该文件应放置在 app/server.ts。在开发或构建阶段,Vite 会首先调用此文件。
在入口文件中,只需使用 createApp() 函数初始化你的应用。app 将是 Hono 的实例,因此你可以使用 Hono 的中间件以及 hono/dev 中的 showRoutes() 方法。
// app/server.ts
import { createApp } from 'honox/server'
import { showRoutes } from 'hono/dev'
const app = createApp()
showRoutes(app)
export default app
路由
定义路由有三种方式。
1. createRoute()
每个路由应返回一个 Handler | MiddlewareHandler 数组。createRoute() 是一个用于返回该数组的辅助函数。你可以使用 default export 编写 GET 请求的路由。
// app/routes/index.tsx
// `createRoute()` helps you create handlers
import { createRoute } from 'honox/factory'
export default createRoute((c) => {
return c.render(
<div>
<h1>Hello!</h1>
</div>
)
})
你还可以通过 export POST、PUT 和 DELETE 来处理除 GET 之外的其他方法。
// app/routes/index.tsx
import { createRoute } from 'honox/factory'
import { getCookie, setCookie } from 'hono/cookie'
export const POST = createRoute(async (c) => {
const { name } = await c.req.parseBody<{ name: string }>()
setCookie(c, 'name', name)
return c.redirect('/')
})
export default createRoute((c) => {
const name = getCookie(c, 'name') ?? 'no name'
return c.render(
<div>
<h1>Hello, {name}!</h1>
<form method='POST'>
<input type='text' name='name' placeholder='name' />
<input type='submit' />
</form>
</div>
)
})
2. 使用 Hono 实例
您可以通过导出 Hono 对象的实例来创建 API 端点。
// app/routes/about/index.ts
import { Hono } from 'hono'
const app = new Hono()
// matches `/about/:name`
app.get('/:name', (c) => {
const name = c.req.param('name')
return c.json({
'your name is': name,
})
})
export default app
3. 直接返回 JSX
或者更简单地说,你可以直接返回 JSX。
// app/routes/index.tsx
export default function Home(_c: Context) {
return <h1>Welcome!</h1>
}
渲染器
通过在 _renderer.tsx 中编写渲染器(即执行 c.setRender() 的中间件)来定义渲染器。
在编写 _renderer.tsx 之前,请在 global.d.ts 中编写渲染器类型定义。
// app/global.d.ts
import type {} from 'hono'
type Head = {
title?: string
}
declare module 'hono' {
interface ContextRenderer {
(content: string | Promise<string>, head?: Head): Response | Promise<Response>
}
}
JSX Renderer 中间件允许你按以下方式创建渲染器:
// app/routes/_renderer.tsx
import { jsxRenderer } from 'hono/jsx-renderer'
export default jsxRenderer(({ children, title }) => {
return (
<html lang='en'>
<head>
<meta charset='UTF-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
{title ? <title>{title}</title> : <></>}
</head>
<body>{children}</body>
</html>
)
})
_renderer.tsx 会应用于每个目录下,而 app/routes/posts/_renderer.tsx 会应用于 app/routes/posts/* 中。
404 页面
你可以在 _404.tsx 中编写自定义的 404 页面。
// app/routes/_404.tsx
import { NotFoundHandler } from 'hono'
const handler: NotFoundHandler = (c) => {
return c.render(<h1>Sorry, Not Found...</h1>)
}
export default handler
错误页面
您可以在 _error.tsx 中编写自定义错误页面。
// app/routes/_error.tsx
import { ErrorHandler } from 'hono'
const handler: ErrorHandler = (e, c) => {
return c.render(<h1>Error! {e.message}</h1>)
}
export default handler
开始使用 - 带客户端
让我们创建一个包含客户端的应用程序。这里,我们将使用 hono/jsx/dom。
项目结构
以下是包含客户端的最小应用程序的项目结构:
.
├── app
│ ├── client.ts // client entry file
│ ├── global.d.ts
│ ├── islands
│ │ └── counter.tsx // island component
│ ├── routes
│ │ ├── _renderer.tsx
│ │ └── index.tsx
│ └── server.ts
├── package.json
├── tsconfig.json
└── vite.config.ts
渲染器
这是一个 _renderer.tsx 文件,它将为客户端加载 /app/client.ts 入口文件。它会根据 import.meta.env.PROD 变量加载生产环境的 JavaScript 文件。如果页面上存在 islands,则会渲染 <HasIslands /> 内部的内容。
// app/routes/_renderer.tsx
import { jsxRenderer } from 'hono/jsx-renderer'
import { HasIslands } from 'honox/server'
export default jsxRenderer(({ children }) => {
return (
<html lang='en'>
<head>
<meta charset='UTF-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
{import.meta.env.PROD ? (
<HasIslands>
<script type='module' src='/static/client.js'></script>
</HasIslands>
) : (
<script type='module' src='/app/client.ts'></script>
)}
</head>
<body>{children}</body>
</html>
)
})
如果您的 dist/.vite/manifest.json 中有清单文件,可以使用 <Script /> 轻松编写。
// app/routes/_renderer.tsx
import { jsxRenderer } from 'hono/jsx-renderer'
import { Script } from 'honox/server'
export default jsxRenderer(({ children }) => {
return (
<html lang='en'>
<head>
<meta charset='UTF-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<Script src='/app/client.ts' />
)
})
注意:由于使用 <HasIslands /> 可能会对构建性能产生轻微影响,建议你不要在开发环境中使用它,而只在构建时使用。<Script /> 在开发过程中不会导致性能下降,因此最好使用它。
nonce 属性
如果你想为 <Script /> 或 <script /> 元素添加 nonce 属性,可以使用 安全头中间件。
定义中间件:
// app/routes/_middleware.ts
import { createRoute } from 'honox/factory'
import { secureHeaders, NONCE } from 'hono/secure-headers'
export default createRoute(
secureHeaders({
contentSecurityPolicy: {
scriptSrc: [NONCE],
},
})
)
你可以通过 c.get('secureHeadersNonce') 获取 nonce 值:
// app/routes/_renderer.tsx
import { jsxRenderer } from 'hono/jsx-renderer'
import { Script } from 'honox/server'
export default jsxRenderer(({ children }, c) => {
return (
<html lang='en'>
<head>
<Script src='/app/client.ts' async nonce={c.get('secureHeadersNonce')} />
)
})
客户端入口文件
客户端入口文件应位于 app/client.ts。只需编写 createClient() 即可。
// app/client.ts
import { createClient } from 'honox/client'
createClient()
交互功能
如果您想为页面添加交互功能,请创建 Island 组件。Island 组件应满足以下要求:
- 放置在
app/islands目录下,或使用$前缀命名,例如$componentName.tsx。 - 应以
default导出,或使用采用驼峰式命名(不含下划线且不全为大写)的适当组件名称导出。
例如,您可以编写如下计数器之类的交互组件:
// app/islands/counter.tsx
import { useState } from 'hono/jsx'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
)
}
当你在路由文件中加载组件时,它会以服务器端渲染的方式呈现,同时 JavaScript 也会发送到客户端。
// app/routes/index.tsx
import { createRoute } from 'honox/factory'
import Counter from '../islands/counter'
export default createRoute((c) => {
return c.render(
<div>
<h1>Hello</h1>
<Counter />
</div>
)
})
注意:你无法在 Island 组件中访问 Context 对象。因此,你应该从 Island 外部的组件传递值。
import { useRequestContext } from 'hono/jsx-renderer'
import Counter from '../islands/counter.tsx'
export default function Component() {
const c = useRequestContext()
return <Counter init={parseInt(c.req.query('count') ?? '0', 10)} />
}
BYOR - 自带渲染器
您可以使用 React、Preact、Solid 或其他 UI 库来引入自己的渲染器。
注意:对于您引入的渲染器,我们可能不提供支持。
React 示例
您可以通过 @hono/react-renderer 定义渲染器。请先安装相关模块。
npm i @hono/react-renderer react react-dom hono
npm i -D @types/react @types/react-dom
在 global.d.ts 中定义渲染器将接收的 Props。
// global.d.ts
import '@hono/react-renderer'
declare module '@hono/react-renderer' {
interface Props {
title?: string
}
}
以下是 app/routes/_renderer.tsx 的示例。
// app/routes/_renderer.tsx
import { reactRenderer } from '@hono/react-renderer'
export default reactRenderer(({ children, title }) => {
return (
<html lang='en'>
<head>
<meta charSet='UTF-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
{import.meta.env.PROD ? (
<script type='module' src='/static/client.js'></script>
) : (
<script type='module' src='/app/client.ts'></script>
)}
{title ? <title>{title}</title> : ''}
</head>
<body>{children}</body>
</html>
)
})
app/client.ts 文件将如下所示。
// app/client.ts
import { createClient } from 'honox/client'
createClient({
hydrate: async (elem, root) => {
const { hydrateRoot } = await import('react-dom/client')
hydrateRoot(root, elem)
},
createElement: async (type: any, props: any) => {
const { createElement } = await import('react')
return createElement(type, props)
},
})
在 vite.config.ts 中配置 react。
// vite.config.ts
import build from '@hono/vite-build/cloudflare-workers'
import honox from 'honox/vite'
import { defineConfig } from 'vite'
export default defineConfig(({ mode }) => {
if (mode === 'client') {
return {
build: {
rollupOptions: {
input: ['./app/client.ts'],
output: {
entryFileNames: 'static/client.js',
chunkFileNames: 'static/assets/[name]-[hash].js',
assetFileNames: 'static/assets/[name].[ext]',
},
},
emptyOutDir: false,
},
}
} else {
return {
ssr: {
external: ['react', 'react-dom'],
},
plugins: [honox(), build()],
}
}
})
调整 tsconfig.json 中的 jsx 工厂函数选项。
// tsconfig.json
{
"compilerOptions": {
...
"jsxImportSource": "react"
...
}
}
使用 React 与 <Script />
如果您在 dist/.vite/manifest.json 中导出清单文件,就可以轻松使用 <Script /> 编写一些代码。
// app/routes/_renderer.tsx
import { reactRenderer } from '@hono/react-renderer'
import { Script } from 'honox/server'
export default reactRenderer(({ children, title }) => {
return (
<html lang='en'>
<head>
<meta charSet='UTF-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<Script src='/app/client.ts' async />
)
})
在 vite.config.ts 中配置 react。
// vite.config.ts
import build from '@hono/vite-build/cloudflare-workers'
import honox from 'honox/vite'
import { defineConfig } from 'vite'
export default defineConfig(({ mode }) => {
if (mode === 'client') {
return {
build: {
rollupOptions: {
input: ['./app/client.ts'],
},
manifest: true,
emptyOutDir: false,
},
}
} else {
return {
ssr: {
external: ['react', 'react-dom'],
},
plugins: [honox(), build()],
}
}
})
指南
嵌套布局
如果您正在使用 JSX Renderer 中间件,可以通过 <Layout /> 来嵌套布局。
// app/routes/posts/_renderer.tsx
import { jsxRenderer } from 'hono/jsx-renderer'
export default jsxRenderer(({ children, Layout }) => {
return (
<Layout>
<nav>Posts Menu</nav>
<div>{children}</div>
</Layout>
)
})
在嵌套布局中传递额外 Props
传递给嵌套渲染器的 Props 不会自动传播到父级渲染器。为确保父级布局接收到必要的 Props,您需要从嵌套的 <Layout /> 组件中显式传递它们。以下是实现方法:
让我们从路由处理器开始:
// app/routes/nested/index.tsx
export default createRoute((c) => {
return c.render(<div>Content</div>, { title: 'Dashboard' })
})
现在,让我们来看看我们的嵌套渲染器:
// app/routes/nested/_renderer.tsx
export default jsxRenderer(({ children, Layout, title }) => {
return (
<Layout title={title}>
{/* Pass the title prop to the parent renderer */}
<main>{children}</main>
</Layout>
)
})
在这种设置中,发送到嵌套渲染器的 <Layout /> 的所有 props 都会被父渲染器消费:
// app/routes/_renderer.tsx
export default jsxRenderer(({ children, title }) => {
return (
<html lang='en'>
<head>
<title>{title}</title> {/* Use the title prop here */}
</head>
<body>
{children} {/* Insert the Layout's children here */}
</body>
</html>
)
})
使用中间件
你可以在每个根文件中使用 Hono 的中间件,语法与 Hono 相同。例如,要使用 Zod Validator 验证值,请按以下步骤操作:
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
const schema = z.object({
name: z.string().max(10),
})
export const POST = createRoute(zValidator('form', schema), async (c) => {
const { name } = c.req.valid('form')
setCookie(c, 'name', name)
return c.redirect('/')
})
或者,你可以在目录中使用 _middleware.(ts|tsx) 文件,使该中间件应用于当前路由及其所有子路由。中间件将按照其在数组中的列出顺序运行。
// /app/routes/_middleware.ts
import { createRoute } from 'honox/factory'
import { logger } from 'hono/logger'
import { secureHeaders } from 'hono/secure-headers'
export default createRoute(logger(), secureHeaders(), ...<more-middleware>)
尾部斜杠
默认情况下,如果根文件是 index.tsx 或 index.mdx 等索引文件,尾部斜杠会被移除。
不过,如果你按以下方式将 trailingSlash 选项设置为 true,则不会移除尾部斜杠。
import { createApp } from 'honox/server'
const app = createApp({
trailingSlash: true,
})
如下所示:
trailingSlash设为false(默认值):app/routes/path/index.mdx=>/pathtrailingSlash设为true:app/routes/path/index.mdx=>/path/
从路由中排除文件和目录
默认情况下,以 - 开头的目录和文件会从路由中排除。
示例:
routes/
├── posts.tsx
├── -post-list.tsx // 👈🏼 ignored
├── -components/ // 👈🏼 ignored
│ ├── header.tsx // 👈🏼 ignored
│ ├── footer.tsx // 👈🏼 ignored
│ └── ...
在本示例中,routes/posts.tsx 会被路由至 /posts,但其他以 - 开头的项不会被路由。
此功能对于代码共存非常有用。
使用 Tailwind CSS
由于 HonoX 是以 Vite 为中心的,如果你希望使用 Tailwind CSS,基本上需遵循 官方指南。
编写 app/style.css 时,你必须显式设置源检测的基准路径:
@import 'tailwindcss' source('../app');
在渲染器文件中导入它。使用 Link 组件将在构建后引用正确的 CSS 文件路径。
// app/routes/_renderer.tsx
import { jsxRenderer } from 'hono/jsx-renderer'
import { Link } from 'honox/server'
export default jsxRenderer(({ children }) => {
return (
<html lang='en'>
<head>
<meta charset='UTF-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<Link href='/app/style.css' rel='stylesheet' />
</head>
<body>{children}</body>
</html>
)
})
最后,添加 vite.config.ts 配置以输出生产环境的资源。
import honox from 'honox/vite'
import { defineConfig } from 'vite'
import build from '@hono/vite-build/cloudflare-workers'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [
honox({
client: {
input: [
'/app/client.ts', // the default value -> must be added if input is overridden
'/app/style.css', // add the style file entrypoint
],
},
}),
build(),
tailwindcss(),
],
})
MDX
也可以使用 MDX。以下是 vite.config.ts。
import devServer from '@hono/vite-dev-server'
import mdx from '@mdx-js/rollup'
import honox from 'honox/vite'
import remarkFrontmatter from 'remark-frontmatter'
import remarkMdxFrontmatter from 'remark-mdx-frontmatter'
import { defineConfig } from 'vite'
export default defineConfig(() => {
return {
plugins: [
honox(),
mdx({
jsxImportSource: 'hono/jsx',
remarkPlugins: [remarkFrontmatter, remarkMdxFrontmatter],
}),
],
}
})
可以创建博客网站。
// app/routes/index.tsx
import type { Meta } from '../types'
export default function Top() {
const posts = import.meta.glob<{ frontmatter: Meta }>('./posts/*.mdx', {
eager: true,
})
return (
<div>
<h2>Posts</h2>
<ul class='article-list'>
{Object.entries(posts).map(([id, module]) => {
if (module.frontmatter) {
return (
<li>
<a href={`${id.replace(/\.mdx$/, '')}`}>{module.frontmatter.title}</a>
</li>
)
}
})}
</ul>
</div>
)
}
Cloudflare 绑定
如果您想在开发环境中使用 Cloudflare 的 Bindings,请创建 wrangler.jsonc 并进行正确配置。
// wrangler.jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-project-name",
"main": "./dist/index.js",
"compatibility_date": "2025-08-03",
"compatibility_flags": ["nodejs_compat"],
"assets": {
"directory": "./dist",
},
}
在 vite.config.ts 中,使用 @hono/vite-dev-server 中的 Cloudflare Adapter。
import honox from 'honox/vite'
import adapter from '@hono/vite-dev-server/cloudflare'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
honox({
devServer: {
adapter,
},
}),
],
})
SSG - 静态站点生成
借助 Hono 的 SSG 功能,你可以为每个路由生成静态 HTML。
// vite.config.ts
import { defineConfig } from 'vite'
import honox from 'honox/vite'
import ssg from '@hono/vite-ssg'
const entry = './app/server.ts'
export default defineConfig(() => {
return {
plugins: [honox(), ssg({ entry })],
}
})
如果您想包含客户端脚本和资源:
// vite.config.ts
import ssg from '@hono/vite-ssg'
import honox from 'honox/vite'
import client from 'honox/vite/client'
import { defineConfig } from 'vite'
const entry = './app/server.ts'
export default defineConfig(({ mode }) => {
if (mode === 'client') {
return {
plugins: [client()],
}
} else {
return {
build: {
emptyOutDir: false,
},
plugins: [honox(), ssg({ entry })],
}
}
})
构建命令(包含客户端):
vite build --mode client && vite build
部署
HonoX 由 Hono 实例和 Vite 配置组成,因此可以部署在任何 Hono 支持的平台上。
@hono/vite-build 提供了适用于 Cloudflare Workers、Node.js、Bun 以及许多其他平台的构建配置。
Cloudflare Workers
如果使用 create-hono 命令创建项目并选择 x-basic,则默认已包含部署到 Cloudflare Workers 的配置。
添加 wrangler.jsonc:
// wrangler.jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-project-name",
"main": "./dist/index.js",
"compatibility_date": "2025-08-03",
"compatibility_flags": ["nodejs_compat"],
"assets": {
"directory": "./dist",
},
}
设置 vite.config.ts:
// vite.config.ts
import build from '@hono/vite-build/cloudflare-workers'
import adapter from '@hono/vite-dev-server/cloudflare'
import tailwindcss from '@tailwindcss/vite'
import honox from 'honox/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
honox({
devServer: { adapter },
client: { input: ['/app/client.ts', '/app/style.css'] },
}),
tailwindcss(),
build(),
],
})
构建命令(包含客户端):
vite build --mode client && vite build
构建完成后,使用以下命令进行部署。确保已安装 Wrangler:
wrangler deploy
本地部署或其他平台
您可以为本地环境或各种其他平台构建 HonoX 应用。有关支持平台的完整列表,请参阅 @hono/vite-build 的 README。例如,您可以为 Bun 构建应用:
// vite.config.ts
import build from '@hono/vite-build/bun' // Change to Bun
import adapter from '@hono/vite-dev-server/bun' // Change to Bun
import tailwindcss from '@tailwindcss/vite'
import honox from 'honox/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
honox({
devServer: { adapter },
client: { input: ['/app/client.ts', '/app/style.css'] },
}),
tailwindcss(),
build(),
],
})
构建命令(包含客户端):
vite build --mode client && vite build
使用 Bun 运行服务器:
cd ./dist && bun index.js
注意:在本地运行时,请确保将工作目录切换到输出目录(例如 cd ./dist)。否则,JavaScript、CSS 和静态资源可能无法正确解析。
在 HonoX 应用中使用环境变量时,你可能会发现 process.env.MY_VAR 这类变量在开发环境中有效,但在构建后的应用中却无效。这是因为 Vite 在构建过程中会将 process.env 优化为空对象。
要确保环境变量在运行时可用,请在你的 vite.config.ts 中添加以下内容:
export default defineConfig({
define: {
'process.env': 'process.env', // <=== Add this line
},
plugins: [
honox({
devServer: { adapter },
client: { input: ['/app/client.ts', '/app/style.css'] },
}),
tailwindcss(),
build(),
],
})
这会禁用 Vite 对 process.env 的优化,使构建后的应用能够按预期访问环境变量。有关更多详细信息,请参阅 issue #307。
测试
集成测试
HonoX 中的集成测试旨在通过对 createApp() 创建的 Hono 实例使用 app.request() 来运行应用,并对响应进行断言。这些测试对于验证路由、中间件、渲染器、404 页面和其他功能的行为非常有用。
HonoX 在内部依赖于多个 Vite 特定的扩展。因此,我们建议使用 Vitest 运行集成测试,Vitest 是一个与 Vite 紧密集成的测试运行器。只有在其他测试运行器提供与 Vite 的兼容性时,才应使用它们。
如果您的项目尚未包含 Vitest,请将其作为开发依赖安装:
npm install -D vitest
以下是一个使用 Vitest 编写集成测试的极简示例:
// tests/integration/index.test.ts
import { describe, expect, it } from 'vitest'
import { createApp } from 'honox/server'
const app = createApp()
describe('Top page', () => {
it("should return 'Hello, Hono!' when name query param is 'Hono'", async () => {
const res = await app.request('/?name=Hono')
const text = await res.text()
expect(res.status).toBe(200)
expect(res.headers.get('content-type')).toMatch(/text\/html/)
expect(text).toMatch(/<h1[^>]*>\s*Hello, Hono!\s*<\/h1>/)
})
})
你可以使用以下命令运行测试:
npx vitest run
当存在 vitest.config 文件时,Vitest 将优先使用该文件并覆盖 vite.config 中的设置。如果添加了 Vitest 特定配置,请确保将其与 Vite 配置合并。有关更多详细信息,请参阅 Configuring Vitest | Vitest。
// vitest.config.ts
import { defineConfig, mergeConfig } from 'vitest/config'
import viteConfig from './vite.config'
export default mergeConfig(
viteConfig,
defineConfig({
// Your Vitest-specific configuration here
})
)
示例
相关项目
作者
- Yusuke Wada https://github.com/yusukebe
许可证
MIT