Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(ssg): Removal of Libraries Dependent on Node.js #2012

Merged
merged 14 commits into from
Jan 19, 2024
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- uses: denoland/setup-deno@v1
with:
deno-version: v1.x
- run: env NAME=Deno deno test --allow-read --allow-env -c runtime_tests/deno/deno.json runtime_tests/deno
- run: env NAME=Deno deno test --allow-read --allow-env --allow-write -c runtime_tests/deno/deno.json runtime_tests/deno
- run: deno test -c runtime_tests/deno-jsx/deno.precompile.json runtime_tests/deno-jsx
- run: deno test -c runtime_tests/deno-jsx/deno.react-jsx.json runtime_tests/deno-jsx

Expand Down
3 changes: 2 additions & 1 deletion deno_dist/adapter/deno/ssg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type { FileSystemModule, ToSSGAdaptorInterface } from '../../helper/ssg/i
*/
export const denoFileSystemModule: FileSystemModule = {
writeFile: async (path, data) => {
const uint8Data = typeof data === 'string' ? new TextEncoder().encode(data) : data
const uint8Data =
typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data)
await Deno.writeFile(path, uint8Data)
},
mkdir: async (path, options) => {
Expand Down
6 changes: 3 additions & 3 deletions deno_dist/helper/ssg/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Buffer } from "node:buffer";
import { replaceUrlParam } from '../../client/utils.ts'
import type { Context } from '../../context.ts'
import { inspectRoutes } from '../../helper/dev/index.ts'
import type { Hono } from '../../hono.ts'
import type { Env, MiddlewareHandler, Schema } from '../../types.ts'
import { bufferToString } from '../../utils/buffer.ts'
import { getExtension } from '../../utils/mime.ts'
import { joinPaths, dirname } from './utils.ts'

Expand All @@ -13,7 +13,7 @@ import { joinPaths, dirname } from './utils.ts'
* The API might be changed.
*/
export interface FileSystemModule {
writeFile(path: string, data: string | Buffer): Promise<void>
writeFile(path: string, data: string | ArrayBuffer | Uint8Array): Promise<void>
mkdir(path: string, options: { recursive: boolean }): Promise<void | string>
}

Expand Down Expand Up @@ -153,7 +153,7 @@ export const saveContentToFiles = async (
if (typeof content === 'string') {
await fsModule.writeFile(filePath, content)
} else if (content instanceof ArrayBuffer) {
await fsModule.writeFile(filePath, Buffer.from(content))
await fsModule.writeFile(filePath, bufferToString(content))
}
files.push(filePath)
}
Expand Down
1 change: 1 addition & 0 deletions deno_dist/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export * from './middleware/timing/index.ts'
export * from './middleware/pretty-json/index.ts'
export * from './middleware/secure-headers/index.ts'
export * from './adapter/deno/serve-static.ts'
export * from './adapter/deno/ssg.ts'
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"scripts": {
"test": "tsc --noEmit && vitest --run && vitest -c .vitest.config/jsx-runtime-default.ts --run && vitest -c .vitest.config/jsx-runtime-dom.ts --run",
"test:watch": "vitest --watch",
"test:deno": "env NAME=Deno deno test --allow-read --allow-env -c runtime_tests/deno/deno.json runtime_tests/deno && deno test --no-lock -c runtime_tests/deno-jsx/deno.precompile.json runtime_tests/deno-jsx && deno test --no-lock -c runtime_tests/deno-jsx/deno.react-jsx.json runtime_tests/deno-jsx",
"test:deno": "env NAME=Deno deno test --allow-read --allow-env --allow-write -c runtime_tests/deno/deno.json runtime_tests/deno && deno test --no-lock -c runtime_tests/deno-jsx/deno.precompile.json runtime_tests/deno-jsx && deno test --no-lock -c runtime_tests/deno-jsx/deno.react-jsx.json runtime_tests/deno-jsx",
"test:bun": "env NAME=Bun bun test --jsx-import-source ../../src/jsx runtime_tests/bun/index.test.tsx",
"test:fastly": "vitest --run --config ./runtime_tests/fastly/vitest.config.ts",
"test:node": "env NAME=Node vitest --run --config ./runtime_tests/node/vitest.config.ts",
Expand Down
65 changes: 63 additions & 2 deletions runtime_tests/bun/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { serveStatic } from '../../src/adapter/bun'
import { describe, it, expect, vi, beforeEach, afterAll } from 'vitest'
import { serveStatic, toSSG } from '../../src/adapter/bun'
import { Context } from '../../src/context'
import { env, getRuntimeKey } from '../../src/helper/adapter'
import { Hono } from '../../src/index'
Expand Down Expand Up @@ -207,3 +207,64 @@ describe('JSX Middleware', () => {
expect(await res.text()).toBe('<html><p>hello</p></html>')
})
})

describe('toSSG function', () => {
let app: Hono

beforeEach(() => {
app = new Hono()
app.get('/', (c) => c.text('Hello, World!'))
app.get('/about', (c) => c.text('About Page'))
app.get('/about/some', (c) => c.text('About Page 2tier'))
app.post('/about/some/thing', (c) => c.text('About Page 3tier'))
app.get('/bravo', (c) => c.html('Bravo Page'))
app.get('/Charlie', 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('/Charlie', (c) => {
return c.render('Hello!', { title: 'Charlies Page' })
})
})

it('Should correctly generate static HTML files for Hono routes', async () => {
const result = await toSSG(app, { dir: './static' })
expect(result.success).toBeTruly
expect(result.error).toBeUndefined()
expect(result.files).toBeDefined()
afterAll(async () => {
await deleteDirectory('./static')
})
})
})

const fs = require('fs').promises
const path = require('path')

async function deleteDirectory(dirPath) {
if (
await fs
.stat(dirPath)
.then((stat) => stat.isDirectory())
.catch(() => false)
) {
for (const entry of await fs.readdir(dirPath)) {
const entryPath = path.join(dirPath, entry)
await deleteDirectory(entryPath)
}
await fs.rmdir(dirPath)
} else {
await fs.unlink(dirPath)
}
}
57 changes: 57 additions & 0 deletions runtime_tests/deno/ssg.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/** @jsx jsx */
/** @jsxFrag Fragment */

import { toSSG } from '../../deno_dist/middleware.ts'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { jsx } from '../../deno_dist/middleware.ts'
import { Hono } from '../../deno_dist/mod.ts'
import { assertEquals } from '../deno/deps.ts'

Deno.test('toSSG function', async () => {
const app = new Hono()
app.get('/', (c) => c.text('Hello, World!'))
app.get('/about', (c) => c.text('About Page'))
app.get('/about/some', (c) => c.text('About Page 2tier'))
app.post('/about/some/thing', (c) => c.text('About Page 3tier'))
app.get('/bravo', (c) => c.html('Bravo Page'))
app.get('/Charlie', async (c, next) => {
c.setRenderer((content) => {
return c.html(
<html>
<body>
<p>{content}</p>
</body>
</html>
)
})
await next()
})
app.get('/Charlie', (c) => {
return c.render('Hello!')
})

const result = await toSSG(app, { dir: './ssg-static' })
assertEquals(result.success, true)
assertEquals(result.error, undefined)
assertEquals(result.files !== undefined, true)

await deleteDirectory('./ssg-static')
})

async function deleteDirectory(dirPath: string): Promise<void> {
try {
const stat = await Deno.stat(dirPath)

if (stat.isDirectory) {
for await (const dirEntry of Deno.readDir(dirPath)) {
const entryPath = `${dirPath}/${dirEntry.name}`
await deleteDirectory(entryPath)
}
await Deno.remove(dirPath)
} else {
await Deno.remove(dirPath)
}
} catch (error) {
console.error(`Error deleting directory: ${error}`)
}
}
12 changes: 6 additions & 6 deletions src/adapter/bun/ssg.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
// @denoify-ignore
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { mkdir, writeFile } from 'fs/promises'
import { toSSG as baseToSSG } from '../../helper/ssg'
import type { FileSystemModule, ToSSGAdaptorInterface } from '../../helper/ssg'

// @ts-ignore
const { write } = Bun
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import is the same as for the Bun.file because it took a long time to break other parts of the Bun type when it was introduced.


/**
* @experimental
* `bunFileSystemModule` is an experimental feature.
* The API might be changed.
*/
export const bunFileSystemModule: FileSystemModule = {
writeFile: (path, data) => {
return writeFile(path, data)
},
mkdir: async (path, options) => {
await mkdir(path, options)
writeFile: async (path, data) => {
await write(path, data)
},
mkdir: async () => {},
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/adapter/deno/ssg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type { FileSystemModule, ToSSGAdaptorInterface } from '../../helper/ssg/i
*/
export const denoFileSystemModule: FileSystemModule = {
writeFile: async (path, data) => {
const uint8Data = typeof data === 'string' ? new TextEncoder().encode(data) : data
const uint8Data =
typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data)
await Deno.writeFile(path, uint8Data)
},
mkdir: async (path, options) => {
Expand Down
5 changes: 3 additions & 2 deletions src/helper/ssg/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Context } from '../../context'
import { inspectRoutes } from '../../helper/dev'
import type { Hono } from '../../hono'
import type { Env, MiddlewareHandler, Schema } from '../../types'
import { bufferToString } from '../../utils/buffer'
import { getExtension } from '../../utils/mime'
import { joinPaths, dirname } from './utils'

Expand All @@ -12,7 +13,7 @@ import { joinPaths, dirname } from './utils'
* The API might be changed.
*/
export interface FileSystemModule {
writeFile(path: string, data: string | Buffer): Promise<void>
writeFile(path: string, data: string | ArrayBuffer | Uint8Array): Promise<void>
mkdir(path: string, options: { recursive: boolean }): Promise<void | string>
}

Expand Down Expand Up @@ -152,7 +153,7 @@ export const saveContentToFiles = async (
if (typeof content === 'string') {
await fsModule.writeFile(filePath, content)
} else if (content instanceof ArrayBuffer) {
await fsModule.writeFile(filePath, Buffer.from(content))
await fsModule.writeFile(filePath, bufferToString(content))
}
files.push(filePath)
}
Expand Down
1 change: 1 addition & 0 deletions src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export * from './middleware/timing'
export * from './middleware/pretty-json'
export * from './middleware/secure-headers'
export * from './adapter/deno/serve-static'
export * from './adapter/deno/ssg'