Skip to content

Commit

Permalink
test: add a mdx test and example (#13)
Browse files Browse the repository at this point in the history
* fix: tweak and add a mdx example

* test: add MDX test
  • Loading branch information
yusukebe committed Jan 22, 2024
1 parent c1746ef commit f38f8b4
Show file tree
Hide file tree
Showing 20 changed files with 1,664 additions and 145 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
dist
sandbox
.hono

# Cloudflare
worker
Expand Down
12 changes: 12 additions & 0 deletions examples/mdx/app/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// eslint-disable-next-line node/no-extraneous-import
import 'hono'
import type { Meta } from './types'

declare module 'hono' {
interface ContextRenderer {
(
content: string | Promise<string>,
meta?: Meta & { frontmatter: Meta }
): Response | Promise<Response>
}
}
32 changes: 32 additions & 0 deletions examples/mdx/app/routes/_renderer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { jsxRenderer } from 'hono/jsx-renderer'

export default jsxRenderer(
({ children, title, frontmatter }) => {
return (
<html lang='en'>
<head>
<meta charset='UTF-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
{<title>{title ?? frontmatter?.title ?? 'My Blog'}</title>}
<link rel='stylesheet' href='/static/style.css' />
</head>
<body>
<header>
<h1>
<a href='/'>My Blog</a>
</h1>
</header>
<main>
<article>{children}</article>
</main>
<footer>
<p>&copy; 2024 My Blog. All rights reserved.</p>
</footer>
</body>
</html>
)
},
{
docType: true,
}
)
23 changes: 23 additions & 0 deletions examples/mdx/app/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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>
)
}
7 changes: 7 additions & 0 deletions examples/mdx/app/routes/posts/hello.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: Hello World
---

## Hollo World

This is a test
8 changes: 8 additions & 0 deletions examples/mdx/app/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { showRoutes } from 'hono/dev'
import { createApp } from 'honox/server'

const app = createApp()

showRoutes(app)

export default app
3 changes: 3 additions & 0 deletions examples/mdx/app/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type Meta = {
title: string
}
21 changes: 21 additions & 0 deletions examples/mdx/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "mdx",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "wrangler pages dev ./dist",
"deploy": "$npm_execpath build && wrangler pages deploy ./dist"
},
"private": true,
"devDependencies": {
"@mdx-js/rollup": "^3.0.0",
"remark-frontmatter": "^5.0.0",
"remark-mdx-frontmatter": "^4.0.0",
"vite": "^5.0.12",
"wrangler": "^3.23.0"
},
"dependencies": {
"honox": "workspace:^"
}
}
44 changes: 44 additions & 0 deletions examples/mdx/public/static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
background: #f4f4f4;
color: #333;
}

a:link, a:visited {
color: #333;
text-decoration: none;
}

header, nav, main, footer {
padding: 20px;
}

header {
text-align: center;
}

article {
background: #fff;
padding: 20px;
margin-bottom: 20px;
}

footer {
text-align: center;
}

.article-list li {
margin: 10px 0;
}

.article-list li a {
text-decoration: none;
color: #333;
}

.article-list li a:hover {
color: #0275d8;
}
73 changes: 73 additions & 0 deletions examples/mdx/src/vite-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* This plugin will be improved and released as `@hono/vite-ssg-build`.
*/

import fs from 'fs/promises'
// eslint-disable-next-line node/no-extraneous-import
import type { Hono } from 'hono'
import { toSSG } from 'hono/ssg'
import type { Plugin } from 'vite'
import { createServer } from 'vite'

type BuildConfig = {
outDir?: string
publicDir?: string
}
type SSGOptions = {
entry?: string
outDir?: string
build?: BuildConfig
}

export const defaultOptions: Required<SSGOptions> = {
entry: './src/index.tsx',
outDir: '.hono',
build: {
outDir: '../dist',
publicDir: '../public',
},
}

const SSGBuild = (options?: SSGOptions): Plugin => {
const entry = options?.entry ?? defaultOptions.entry
const outDir = options?.outDir ?? defaultOptions.outDir
return {
name: 'hono-ssg-build',
apply: 'build',
config: async () => {
// Create a server to load the module
const server = await createServer({
plugins: [],
build: { ssr: true },
})
const module = await server.ssrLoadModule(entry)
server.close()

const app = module['default'] as Hono

if (!app) {
throw new Error(`Failed to find a named export "default" from ${entry}`)
}

const result = await toSSG(app, fs, { dir: outDir })

if (!result.success) {
throw result.error
}

return {
root: outDir,
publicDir: options?.build?.publicDir ?? defaultOptions.build.publicDir,
build: {
outDir: options?.build?.outDir ?? defaultOptions.build.outDir,
rollupOptions: {
input: result.files ? [...result.files] : [],
},
emptyOutDir: true,
},
}
},
}
}

export default SSGBuild
17 changes: 17 additions & 0 deletions examples/mdx/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"esModuleInterop": true,
"strict": true,
"lib": [
"esnext"
],
"types": [
"vite/client"
],
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
},
}
23 changes: 23 additions & 0 deletions examples/mdx/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import devServer from '@hono/vite-dev-server'
import mdx from '@mdx-js/rollup'
import { islandComponents } from 'honox/vite'
import remarkFrontmatter from 'remark-frontmatter'
import remarkMdxFrontmatter from 'remark-mdx-frontmatter'
import { defineConfig } from '../../node_modules/vite'
import ssg from './src/vite-plugin'

const entry = './app/server.ts'

export default defineConfig(() => {
return {
plugins: [
islandComponents(),
devServer({ entry }),
ssg({ entry }),
mdx({
jsxImportSource: 'hono/jsx',
remarkPlugins: [remarkFrontmatter, remarkMdxFrontmatter],
}),
],
}
})
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@
},
"homepage": "https://hono.dev",
"workspaces": [
"examples/basic"
"examples/basic",
"examples/mdx"
],
"dependencies": {
"@babel/generator": "^7.23.6",
Expand All @@ -95,6 +96,7 @@
},
"devDependencies": {
"@hono/eslint-config": "^0.0.3",
"@mdx-js/rollup": "^3.0.0",
"@playwright/test": "^1.41.0",
"@types/babel__generator": "^7",
"@types/babel__traverse": "^7",
Expand All @@ -106,8 +108,8 @@
"publint": "^0.2.7",
"tsup": "^8.0.1",
"typescript": "^5.3.3",
"vite": "^5.0.10",
"vitest": "^1.1.0"
"vite": "^5.0.12",
"vitest": "^1.2.1"
},
"packageManager": "[email protected]",
"engines": {
Expand Down
5 changes: 3 additions & 2 deletions src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>): Hono<E> =>
// Routes
const ROUTES_FILE =
options?.ROUTES ??
import.meta.glob<RouteFile | AppFile>('/app/routes/**/[a-z0-9[-][a-z0-9[_-]*.(ts|tsx|mdx)', {
import.meta.glob<RouteFile | AppFile>('/app/routes/**/[!_]*.(ts|tsx|mdx)', {
eager: true,
})

const routesMap = sortDirectoriesByDepth(groupByDirectory(ROUTES_FILE))

for (const map of routesMap) {
Expand Down Expand Up @@ -137,7 +138,7 @@ export const createApp = <E extends Env>(options?: ServerOptions<E>): Hono<E> =>
// export default function Helle() {}
if (typeof routeDefault === 'function') {
subApp.get(path, (c) => {
return c.render(routeDefault())
return c.render(routeDefault(), route as any)
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/vite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ function honox(options?: HonoXOptions): PluginOption[] {
]
}

export { devServerDefaultOptions }
export { devServerDefaultOptions, islandComponents }

export default honox
1 change: 1 addition & 0 deletions test/hono-jsx/app/routes/post.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Hello MDX
13 changes: 12 additions & 1 deletion test/hono-jsx/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { poweredBy } from 'hono/powered-by'
import { createApp } from '../../src/server'

describe('Basic', () => {
const ROUTES = import.meta.glob('./app/routes/**/[a-z[-][a-z[_-]*.(tsx|ts)', {
const ROUTES = import.meta.glob('./app/routes/**/[a-z[-][a-z[_-]*.(tsx|ts|mdx)', {
eager: true,
})

Expand Down Expand Up @@ -45,6 +45,11 @@ describe('Basic', () => {
{ path: '/api', method: 'POST', handler: expect.any(Function) },
{ path: '/api', method: 'GET', handler: expect.any(Function) },
{ path: '/', method: 'GET', handler: expect.any(Function) },
{
path: '/post',
method: 'GET',
handler: expect.any(Function),
},
{
path: '/throw_error',
method: 'GET',
Expand Down Expand Up @@ -80,6 +85,12 @@ describe('Basic', () => {
expect(res.status).toBe(201)
})

it('Should render MDX content - /post', async () => {
const res = await app.request('/post')
expect(res.status).toBe(200)
expect(await res.text()).toBe('<h1>Hello MDX</h1>')
})

it('Should return 500 response /throw_error', async () => {
global.console.trace = vi.fn()
const res = await app.request('/throw_error')
Expand Down
4 changes: 4 additions & 0 deletions test/hono-jsx/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import mdx from '@mdx-js/rollup'
import { defineConfig } from 'vite'
import honox from '../../src/vite'

Expand All @@ -6,5 +7,8 @@ export default defineConfig({
honox({
entry: './app/server.ts',
}),
mdx({
jsxImportSource: 'hono/jsx',
}),
],
})
Loading

0 comments on commit f38f8b4

Please sign in to comment.