diff --git a/examples/ssr/src/pages/js-test.tsx b/examples/ssr/src/pages/js-test.tsx
index aaf9481..065b8ca 100644
--- a/examples/ssr/src/pages/js-test.tsx
+++ b/examples/ssr/src/pages/js-test.tsx
@@ -1,11 +1,11 @@
-import { frontend as fe } from 'hype'
+import { fe } from 'hype'
-fe(function test() {
+const test = fe(() => {
alert('ding dong')
})
export default () => (
)
\ No newline at end of file
diff --git a/src/frontend.ts b/src/frontend.ts
index 0b9b497..4ff25a8 100644
--- a/src/frontend.ts
+++ b/src/frontend.ts
@@ -1,14 +1,48 @@
import { AsyncLocalStorage } from 'async_hooks'
-export const fnStorage = new AsyncLocalStorage<{ fns: string[] }>()
+export const fnStorage = new AsyncLocalStorage<{
+ fns: Map
+ counter: number
+}>()
-// Designate a function in a .tsx file as frontend
-export function frontend(code: Function) {
+export function fe>(
+ fn: (args?: T) => void,
+ args?: T
+): string {
const store = fnStorage.getStore()
- store?.fns.push(code.toString())
+ if (!store) {
+ // Fallback to IIFE if outside request context
+ return args
+ ? `(${fn.toString()})(${JSON.stringify(args)})`
+ : `(${fn.toString()})()`
+ }
+
+ const fnStr = fn.toString()
+
+ // Dedupe by function body
+ for (const [name, body] of store.fns)
+ if (body === fnStr)
+ return args ? `${name}(${JSON.stringify(args)})` : `${name}()`
+
+ const name = `frontendFn${store.counter++}`
+ store.fns.set(name, fnStr)
+
+ return args ? `${name}(${JSON.stringify(args)})` : `${name}()`
}
export function feFunctions(): string[] {
const store = fnStorage.getStore()
- return store?.fns ?? []
+ if (!store?.fns.size) return []
+
+ return [...store.fns.entries()].map(([name, body]) => {
+ // Handle arrow functions vs regular functions
+ if (body.startsWith('(') || body.startsWith('async ('))
+ return `const ${name} = ${body};`
+
+ // Named function - rename it
+ return body.replace(/^(async\s+)?function\s*\w*/, `$1function ${name}`)
+ })
}
+
+// Keep for backwards compat
+export const frontend = fe
\ No newline at end of file
diff --git a/src/index.tsx b/src/index.tsx
index da5f62c..753d244 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -13,7 +13,7 @@ const CSS_RESET = await Bun.file(join(import.meta.dir, '/css/reset.css')).text()
const PICO_CSS = await Bun.file(join(import.meta.dir, '/css/pico.css')).text()
export * from './utils'
-export { frontend } from './frontend'
+export { frontend, frontend as fe } from './frontend'
export type { Context } from 'hono'
const pageCache = new Map()
@@ -94,7 +94,7 @@ export class Hype<
// serve frontend js
this.use('*', async (c, next) => {
- await fnStorage.run({ fns: [] }, async () => {
+ await fnStorage.run({ fns: new Map(), counter: 0 }, async () => {
await next()
const contentType = c.res.headers.get('content-type')