fix(bun-transpiler): Apply headers when using serveStatic; Improvement: Make options optional; (#349)
* ✅ Add failing serveStatic test (headers not applied) * 🐛 Fix: Apply headers when using serveStatic * 🚸 Make options optional * 🔖 Add changeset * ✏️ Fix naming in comment * 🚸 Export defaultOptions * 🏷️ Improve Typing of defaultOptionspull/350/head
parent
935560f677
commit
b6e59dd19c
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@hono/bun-transpiler': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix: Apply headers when using serveStatic middleware; Improvement: Make options optional;
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@hono/bun-transpiler': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Export defaultOptions
|
|
@ -1,4 +1,5 @@
|
||||||
import { Hono } from 'hono'
|
import { Hono } from 'hono'
|
||||||
|
import { serveStatic } from 'hono/bun'
|
||||||
import { bunTranspiler } from '.'
|
import { bunTranspiler } from '.'
|
||||||
|
|
||||||
const HOST = 'http://localhost'
|
const HOST = 'http://localhost'
|
||||||
|
@ -20,6 +21,9 @@ describe('Bun Transpiler middleware', () => {
|
||||||
app.get('/script.tsx', (c) => c.text(TSX))
|
app.get('/script.tsx', (c) => c.text(TSX))
|
||||||
app.get('/bad.ts', (c) => c.text(BAD))
|
app.get('/bad.ts', (c) => c.text(BAD))
|
||||||
|
|
||||||
|
// serve middleware script to test compliance with serveStatic
|
||||||
|
app.get('/index.ts', serveStatic({ root: './src' }))
|
||||||
|
|
||||||
it('Should ignore non typescript content paths', async () => {
|
it('Should ignore non typescript content paths', async () => {
|
||||||
const res = await app.request(`${HOST}/script.js`)
|
const res = await app.request(`${HOST}/script.js`)
|
||||||
expect(res).not.toBeNull()
|
expect(res).not.toBeNull()
|
||||||
|
@ -50,4 +54,11 @@ describe('Bun Transpiler middleware', () => {
|
||||||
expect(await res.text()).toBe('Parse error')
|
expect(await res.text()).toBe('Parse error')
|
||||||
expect(res.headers.get('content-type')).toBe('text/plain')
|
expect(res.headers.get('content-type')).toBe('text/plain')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should apply headers when serveStatic is used', async () => {
|
||||||
|
const res = await app.request(`${HOST}/index.ts`)
|
||||||
|
expect(res).not.toBeNull()
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(res.headers.get('content-type')).toBe('application/javascript')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,36 +2,38 @@ import Bun from 'bun'
|
||||||
import { createMiddleware } from 'hono/factory'
|
import { createMiddleware } from 'hono/factory'
|
||||||
|
|
||||||
type BunTranspilerOptions = {
|
type BunTranspilerOptions = {
|
||||||
extensions: string[]
|
extensions?: string[]
|
||||||
headers: HeadersInit
|
headers?: Record<string, string | string[]>
|
||||||
transpilerOptions: Bun.TranspilerOptions
|
transpilerOptions?: Bun.TranspilerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
export const bunTranspiler = (
|
export const defaultOptions: Required<BunTranspilerOptions> = {
|
||||||
options: BunTranspilerOptions = {
|
|
||||||
extensions: ['.ts', '.tsx'],
|
extensions: ['.ts', '.tsx'],
|
||||||
headers: { 'content-type': 'application/javascript' },
|
headers: { 'content-type': 'application/javascript' },
|
||||||
transpilerOptions: {
|
transpilerOptions: {
|
||||||
minifyWhitespace: true,
|
minifyWhitespace: true,
|
||||||
target: 'browser',
|
target: 'browser',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
) => {
|
|
||||||
|
export const bunTranspiler = (options?: BunTranspilerOptions) => {
|
||||||
return createMiddleware(async (c, next) => {
|
return createMiddleware(async (c, next) => {
|
||||||
await next()
|
await next()
|
||||||
const url = new URL(c.req.url)
|
const url = new URL(c.req.url)
|
||||||
const { extensions, headers, transpilerOptions } = options
|
const extensions = options?.extensions ?? defaultOptions.extensions
|
||||||
|
const headers = options?.headers ?? defaultOptions.headers
|
||||||
|
|
||||||
if (extensions.every((ext) => !url.pathname.endsWith(ext))) return
|
if (extensions?.every((ext) => !url.pathname.endsWith(ext))) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const loader = url.pathname.split('.').pop() as Bun.TranspilerOptions['loader']
|
const loader = url.pathname.split('.').pop() as Bun.TranspilerOptions['loader']
|
||||||
|
const transpilerOptions = options?.transpilerOptions ?? defaultOptions.transpilerOptions
|
||||||
const transpiler = new Bun.Transpiler({
|
const transpiler = new Bun.Transpiler({
|
||||||
loader,
|
loader,
|
||||||
...transpilerOptions,
|
...transpilerOptions,
|
||||||
})
|
})
|
||||||
const transpiledCode = await transpiler.transformSync(await c.res.text())
|
const transpiledCode = await transpiler.transformSync(await c.res.text())
|
||||||
c.res = c.newResponse(transpiledCode, { headers })
|
c.res = c.newResponse(transpiledCode, 200, headers)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(`Error transpiling ${url.pathname}: ${error}`)
|
console.warn(`Error transpiling ${url.pathname}: ${error}`)
|
||||||
const errorHeaders = {
|
const errorHeaders = {
|
||||||
|
@ -39,15 +41,9 @@ export const bunTranspiler = (
|
||||||
'content-type': 'text/plain',
|
'content-type': 'text/plain',
|
||||||
}
|
}
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
c.res = c.newResponse(error.message, {
|
c.res = c.newResponse(error.message, 500, errorHeaders)
|
||||||
status: 500,
|
|
||||||
headers: errorHeaders,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
c.res = c.newResponse('Malformed Input', {
|
c.res = c.newResponse('Malformed Input', 500, errorHeaders)
|
||||||
status: 500,
|
|
||||||
headers: errorHeaders,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue