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 defaultOptions
pull/350/head
floriankapaun 2024-01-11 21:03:13 +01:00 committed by GitHub
parent 935560f677
commit b6e59dd19c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 24 deletions

View File

@ -0,0 +1,5 @@
---
'@hono/bun-transpiler': minor
---
Fix: Apply headers when using serveStatic middleware; Improvement: Make options optional;

View File

@ -0,0 +1,5 @@
---
'@hono/bun-transpiler': minor
---
Export defaultOptions

View File

@ -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')
})
}) })

View File

@ -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,
})
} }
} }
}) })