@pajecawav/yamf 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +32 -1
  2. package/dist/components/Head.d.ts +2 -3
  3. package/dist/components/Head.d.ts.map +1 -1
  4. package/dist/context/ssr.d.ts +1 -2
  5. package/dist/context/ssr.d.ts.map +1 -1
  6. package/dist/hooks/useEvent.d.ts +1 -2
  7. package/dist/hooks/useEvent.d.ts.map +1 -1
  8. package/dist/hooks/useHead.d.ts +2 -3
  9. package/dist/hooks/useHead.d.ts.map +1 -1
  10. package/dist/hooks/useHead.js.map +1 -1
  11. package/dist/island/types.d.ts +2 -3
  12. package/dist/island/types.d.ts.map +1 -1
  13. package/dist/page.d.ts +3 -4
  14. package/dist/page.d.ts.map +1 -1
  15. package/dist/server/entry.d.mts +3 -4
  16. package/dist/server/entry.d.mts.map +1 -1
  17. package/dist/server/entry.mjs +11 -1
  18. package/dist/server/entry.mjs.map +1 -1
  19. package/dist/server/island/server.d.mts +2 -3
  20. package/dist/server/island/server.d.mts.map +1 -1
  21. package/dist/server/island/server.mjs +2 -2
  22. package/dist/server/island/server.mjs.map +1 -1
  23. package/dist/server/island/types.d.mts +1 -2
  24. package/dist/server/island/types.d.mts.map +1 -1
  25. package/dist/server/shared/assets.d.mts +1 -2
  26. package/dist/server/shared/assets.d.mts.map +1 -1
  27. package/dist/server/shared/head.d.mts +1 -2
  28. package/dist/server/shared/head.d.mts.map +1 -1
  29. package/dist/shared/assets.d.ts +2 -3
  30. package/dist/shared/assets.d.ts.map +1 -1
  31. package/dist/shared/head.d.ts +1 -2
  32. package/dist/shared/head.d.ts.map +1 -1
  33. package/dist/vite/index.d.mts +2 -2
  34. package/dist/vite/index.d.mts.map +1 -1
  35. package/dist/vite/index.mjs +3 -1
  36. package/dist/vite/index.mjs.map +1 -1
  37. package/dist/vite/islands.mjs +38 -59
  38. package/dist/vite/islands.mjs.map +1 -1
  39. package/dist/vite/virtual-assets.mjs +1 -1
  40. package/dist/vite/virtual-assets.mjs.map +1 -1
  41. package/dist/vite/virtual-error-handler.mjs +23 -0
  42. package/dist/vite/virtual-error-handler.mjs.map +1 -0
  43. package/dist/vite/virtual-pages.mjs +1 -1
  44. package/dist/vite/virtual-pages.mjs.map +1 -1
  45. package/dist/vite/virtual-root.mjs +1 -1
  46. package/dist/vite/virtual-root.mjs.map +1 -1
  47. package/dist/vite/virtual-template.mjs +1 -1
  48. package/dist/vite/virtual-template.mjs.map +1 -1
  49. package/package.json +22 -31
  50. package/src/island/server.tsx +7 -5
  51. package/src/server/entry.tsx +25 -3
  52. package/src/virtual.d.ts +8 -0
  53. package/src/vite/index.ts +2 -0
  54. package/src/vite/islands.ts +76 -175
  55. package/src/vite/virtual-error-handler.ts +40 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # yamf
2
2
 
3
- SSR meta-framework on top of [Vite](https://vite.dev), [Nitro](https://nitro.build/), and [Hono JSX](https://hono.dev/docs/guides/jsx). File-based routing for HTML pages, islands architecture for client interactivity, head/SEO via [unhead](https://unhead.unjs.io/), and full Nitro feature set (presets, caching, middleware, API routes).
3
+ SSR meta-framework on top of [Vite](https://vite.dev), [Nitro](https://nitro.build/), and [Hono JSX](https://hono.dev/docs/guides/jsx). File-based routing for HTML pages, islands architecture for client interactivity, client-side routing via [wouter](https://github.com/molefrog/wouter), React-ecosystem compatibility through [@hono/react-compat](https://github.com/honojs/react-compat), head/SEO via [unhead](https://unhead.unjs.io/), and full Nitro feature set (presets, caching, middleware, API routes).
4
4
 
5
5
  ## Install
6
6
 
@@ -149,6 +149,37 @@ export default definePage({
149
149
 
150
150
  Props are serialized with `devalue` (supports `Date`, `Map`, `Set`, `URL`, `RegExp`, `Error`, `BigInt`, cycles).
151
151
 
152
+ ### React ecosystem compatibility
153
+
154
+ The Vite plugin aliases `react` and `react-dom` to [`@hono/react-compat`](https://github.com/honojs/react-compat), which reimplements the React API on top of `hono/jsx`. This means libraries from the React ecosystem (wouter, tanstack/react-query, etc.) work inside islands and the render tree without shipping React. `use-sync-external-store` is also aliased to `@hono/react-compat`.
155
+
156
+ ## Routing
157
+
158
+ Every page renders inside a [wouter](https://github.com/molefrog/wouter) `<Router>`, seeded with the current request's `pathname` and `search` for SSR. After hydration, navigation is client-side — wouter hooks and components work inside islands and the root layout:
159
+
160
+ ```tsx
161
+ // src/components/Search.island.tsx
162
+ import { useSearchParams } from "wouter";
163
+
164
+ export const Search = () => {
165
+ const [params, setParams] = useSearchParams();
166
+
167
+ return (
168
+ <input
169
+ value={params.get("q") ?? ""}
170
+ onChange={e =>
171
+ setParams(prev => {
172
+ prev.set("q", e.target.value);
173
+ return prev;
174
+ })
175
+ }
176
+ />
177
+ );
178
+ };
179
+ ```
180
+
181
+ wouter's `Link`, `Route`, `useLocation`, `useRoute`, and `useSearchParams` are all available. Note that yamf's file-based routing (see [File routing](#file-routing)) handles full-page SSR routes, while wouter handles client-side navigation and query-param state within a page.
182
+
152
183
  ## Client entry
153
184
 
154
185
  ```ts
@@ -1,7 +1,6 @@
1
1
  import { ResolvableHead } from "unhead/types";
2
2
  //#region src/components/Head.d.ts
3
- type HeadProps = ResolvableHead;
4
- declare const Head: (props: HeadProps) => void;
3
+ export type HeadProps = ResolvableHead;
4
+ export declare const Head: (props: HeadProps) => void;
5
5
  //#endregion
6
- export { Head, HeadProps };
7
6
  //# sourceMappingURL=Head.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Head.d.ts","names":[],"sources":["../../src/components/Head.tsx"],"mappings":";;KAGY,YAAY;cAEX,OAAQ,OAAO"}
1
+ {"version":3,"file":"Head.d.ts","names":[],"sources":["../../src/components/Head.tsx"],"mappings":";;YAGY,YAAY;qBAEX,OAAQ,OAAO"}
@@ -6,7 +6,6 @@ interface SSRContextValue {
6
6
  head: ServerUnhead;
7
7
  event: H3Event;
8
8
  }
9
- declare const useSSRContext: () => SSRContextValue | null;
9
+ export declare const useSSRContext: () => SSRContextValue | null;
10
10
  //#endregion
11
- export { useSSRContext };
12
11
  //# sourceMappingURL=ssr.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ssr.d.ts","names":[],"sources":["../../src/context/ssr.ts"],"mappings":";;;;UAIU;EACT,MAAM;EACN,OAAO;;cAOK,qBAAoB"}
1
+ {"version":3,"file":"ssr.d.ts","names":[],"sources":["../../src/context/ssr.ts"],"mappings":";;;;UAIU;EACT,MAAM;EACN,OAAO;;qBAOK,qBAAoB"}
@@ -1,6 +1,5 @@
1
1
  import { H3Event } from "nitro";
2
2
  //#region src/hooks/useEvent.d.ts
3
- declare const useEvent: () => H3Event;
3
+ export declare const useEvent: () => H3Event;
4
4
  //#endregion
5
- export { useEvent };
6
5
  //# sourceMappingURL=useEvent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useEvent.d.ts","names":[],"sources":["../../src/hooks/useEvent.tsx"],"mappings":";;cAGa,gBAAe"}
1
+ {"version":3,"file":"useEvent.d.ts","names":[],"sources":["../../src/hooks/useEvent.tsx"],"mappings":";;qBAGa,gBAAe"}
@@ -6,8 +6,7 @@ declare global {
6
6
  __UNHEAD__?: ClientUnhead;
7
7
  }
8
8
  }
9
- declare const useHead: (input?: ResolvableHead) => void;
10
- declare const useSeoMeta: (input?: UseSeoMetaInput) => void;
9
+ export declare const useHead: (input?: ResolvableHead) => void;
10
+ export declare const useSeoMeta: (input?: UseSeoMetaInput) => void;
11
11
  //#endregion
12
- export { useHead, useSeoMeta };
13
12
  //# sourceMappingURL=useHead.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useHead.d.ts","names":[],"sources":["../../src/hooks/useHead.tsx"],"mappings":";;;QAMe;YACJ;IACT,aAAa;;;cAQF,UAAW,QAAQ;cAYnB,aAAc,QAAQ"}
1
+ {"version":3,"file":"useHead.d.ts","names":[],"sources":["../../src/hooks/useHead.tsx"],"mappings":";;;QAMe;YACJ;IACT,aAAa;;;qBAQF,UAAW,QAAQ;qBAYnB,aAAc,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"useHead.js","names":["useHead","useSeoMeta"],"sources":["../../src/hooks/useHead.tsx"],"sourcesContent":["import { useHead as _useHead, useSeoMeta as _useSeoMeta } from \"unhead\";\nimport type { ClientUnhead } from \"unhead/client\";\nimport { createHead } from \"unhead/client\";\nimport type { ResolvableHead, UseSeoMetaInput } from \"unhead/types\";\nimport { useSSRContext } from \"#/context/ssr\";\n\ndeclare global {\n\tinterface Window {\n\t\t__UNHEAD__?: ClientUnhead;\n\t}\n}\n\nif (!import.meta.env.SSR) {\n\twindow.__UNHEAD__ = createHead();\n}\n\nexport const useHead = (input?: ResolvableHead): void => {\n\tif (import.meta.env.SSR) {\n\t\tconst ctx = useSSRContext();\n\n\t\tif (ctx?.head) {\n\t\t\t_useHead(ctx.head, input);\n\t\t}\n\t} else if (window.__UNHEAD__) {\n\t\t_useHead(window.__UNHEAD__, input);\n\t}\n};\n\nexport const useSeoMeta = (input?: UseSeoMetaInput): void => {\n\tif (import.meta.env.SSR) {\n\t\tconst ctx = useSSRContext();\n\n\t\tif (ctx?.head) {\n\t\t\t_useSeoMeta(ctx.head, input);\n\t\t}\n\t} else if (window.__UNHEAD__) {\n\t\t_useSeoMeta(window.__UNHEAD__, input);\n\t}\n};\n"],"mappings":";;;;AAYA,IAAI,CAAC,OAAO,KAAK,IAAI,KACpB,OAAO,aAAa,WAAW;AAGhC,MAAaA,aAAW,UAAiC;CACxD,IAAI,OAAO,KAAK,IAAI,KAAK;EACxB,MAAM,MAAM,cAAc;EAE1B,IAAI,KAAK,MACR,QAAS,IAAI,MAAM,KAAK;CAE1B,OAAO,IAAI,OAAO,YACjB,QAAS,OAAO,YAAY,KAAK;AAEnC;AAEA,MAAaC,gBAAc,UAAkC;CAC5D,IAAI,OAAO,KAAK,IAAI,KAAK;EACxB,MAAM,MAAM,cAAc;EAE1B,IAAI,KAAK,MACR,WAAY,IAAI,MAAM,KAAK;CAE7B,OAAO,IAAI,OAAO,YACjB,WAAY,OAAO,YAAY,KAAK;AAEtC"}
1
+ {"version":3,"file":"useHead.js","names":["useHead","useSeoMeta"],"sources":["../../src/hooks/useHead.tsx"],"sourcesContent":["import { useHead as _useHead, useSeoMeta as _useSeoMeta } from \"unhead\";\nimport type { ClientUnhead } from \"unhead/client\";\nimport { createHead } from \"unhead/client\";\nimport type { ResolvableHead, UseSeoMetaInput } from \"unhead/types\";\nimport { useSSRContext } from \"#/context/ssr\";\n\ndeclare global {\n\tinterface Window {\n\t\t__UNHEAD__?: ClientUnhead;\n\t}\n}\n\nif (!import.meta.env.SSR) {\n\twindow.__UNHEAD__ = createHead();\n}\n\nexport const useHead = (input?: ResolvableHead): void => {\n\tif (import.meta.env.SSR) {\n\t\tconst ctx = useSSRContext();\n\n\t\tif (ctx?.head) {\n\t\t\t_useHead(ctx.head, input);\n\t\t}\n\t} else if (window.__UNHEAD__) {\n\t\t_useHead(window.__UNHEAD__, input);\n\t}\n};\n\nexport const useSeoMeta = (input?: UseSeoMetaInput): void => {\n\tif (import.meta.env.SSR) {\n\t\tconst ctx = useSSRContext();\n\n\t\tif (ctx?.head) {\n\t\t\t_useSeoMeta(ctx.head, input);\n\t\t}\n\t} else if (window.__UNHEAD__) {\n\t\t_useSeoMeta(window.__UNHEAD__, input);\n\t}\n};\n"],"mappings":";;;;AAYA,IAAI,CAAC,YAAY,IAAI,KACpB,OAAO,aAAa,WAAW;AAGhC,MAAaA,aAAW,UAAiC;CACxD,IAAI,YAAY,IAAI,KAAK;EACxB,MAAM,MAAM,cAAc;EAE1B,IAAI,KAAK,MACR,QAAS,IAAI,MAAM,KAAK;CAE1B,OAAO,IAAI,OAAO,YACjB,QAAS,OAAO,YAAY,KAAK;AAEnC;AAEA,MAAaC,gBAAc,UAAkC;CAC5D,IAAI,YAAY,IAAI,KAAK;EACxB,MAAM,MAAM,cAAc;EAE1B,IAAI,KAAK,MACR,WAAY,IAAI,MAAM,KAAK;CAE7B,OAAO,IAAI,OAAO,YACjB,WAAY,OAAO,YAAY,KAAK;AAEtC"}
@@ -1,8 +1,7 @@
1
1
  //#region src/island/types.d.ts
2
- type IslandClientDirective = "load" | "idle" | "visible" | "skip" | boolean;
3
- interface IslandProps {
2
+ export type IslandClientDirective = "load" | "idle" | "visible" | "skip" | boolean;
3
+ export interface IslandProps {
4
4
  "yamf-client"?: IslandClientDirective;
5
5
  }
6
6
  //#endregion
7
- export { IslandClientDirective, IslandProps };
8
7
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/island/types.ts"],"mappings":";KAAY;UASK;EAChB,gBAAgB"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/island/types.ts"],"mappings":";YAAY;iBASK;EAChB,gBAAgB"}
package/dist/page.d.ts CHANGED
@@ -5,11 +5,11 @@ import { EventHandlerResponse, H3Event, HTTPResponse } from "nitro/h3";
5
5
  import { Unhead } from "unhead/server";
6
6
  import { UseSeoMetaInput } from "unhead/types";
7
7
  //#region src/page.d.ts
8
- type PageHandler = (event: H3Event, params: {
8
+ export type PageHandler = (event: H3Event, params: {
9
9
  assets: ImportAssetsResult;
10
10
  head?: YamfHead;
11
11
  }) => EventHandlerResponse;
12
- type PageRenderer = (event: H3Event, params: {
12
+ export type PageRenderer = (event: H3Event, params: {
13
13
  head: Unhead;
14
14
  seoHead: (input: UseSeoMetaInput) => void;
15
15
  }) => HTTPResponse | Child | Promise<Child | HTTPResponse>;
@@ -17,7 +17,6 @@ interface DefinePageOptions {
17
17
  render: PageRenderer;
18
18
  stream?: boolean;
19
19
  }
20
- declare const definePage: (options: DefinePageOptions) => PageHandler;
20
+ export declare const definePage: (options: DefinePageOptions) => PageHandler;
21
21
  //#endregion
22
- export { PageHandler, PageRenderer, definePage };
23
22
  //# sourceMappingURL=page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"page.d.ts","names":[],"sources":["../src/page.tsx"],"mappings":";;;;;;;KAiBY,eACX,OAAO,SACP;EACC,QAAQ;EACR,OAAO;MAEJ;KAEO,gBACX,OAAO,SACP;EACC,MAAM;EACN,UAAU,OAAO;MAEd,eAAe,QAAQ,QAAQ,QAAQ;UAElC;EACT,QAAQ;EACR;;cAGY,aAAc,SAAS,sBAAoB"}
1
+ {"version":3,"file":"page.d.ts","names":[],"sources":["../src/page.tsx"],"mappings":";;;;;;;YAiBY,eACX,OAAO,SACP;EACC,QAAQ;EACR,OAAO;MAEJ;YAEO,gBACX,OAAO,SACP;EACC,MAAM;EACN,UAAU,OAAO;MAEd,eAAe,QAAQ,QAAQ,QAAQ;UAElC;EACT,QAAQ;EACR;;qBAGY,aAAc,SAAS,sBAAoB"}
@@ -1,12 +1,11 @@
1
1
  import { YamfHead } from "./shared/head.mjs";
2
2
  import { EventHandlerRequest, EventHandlerWithFetch, H3Event } from "nitro/h3";
3
3
  //#region src/server/entry.d.ts
4
- type ServerEntry = EventHandlerWithFetch<EventHandlerRequest, Promise<unknown>>;
5
- interface DefineServerEntryOptions {
4
+ export type ServerEntry = EventHandlerWithFetch<EventHandlerRequest, Promise<unknown>>;
5
+ export interface DefineServerEntryOptions {
6
6
  head?: YamfHead | ((event: H3Event) => YamfHead);
7
7
  disableEarlyHints?: boolean;
8
8
  }
9
- declare const defineServerEntry: (options?: DefineServerEntryOptions) => ServerEntry;
9
+ export declare const defineServerEntry: (options?: DefineServerEntryOptions) => ServerEntry;
10
10
  //#endregion
11
- export { DefineServerEntryOptions, ServerEntry, defineServerEntry };
12
11
  //# sourceMappingURL=entry.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entry.d.mts","names":[],"sources":["../../src/server/entry.tsx"],"mappings":";;;KA8CY,cAAc,sBAAsB,qBAAqB;UAEpD;EAChB,OAAO,aAAa,OAAO,YAAY;EACvC;;cAGY,oBAAqB,UAAU,6BAA2B"}
1
+ {"version":3,"file":"entry.d.mts","names":[],"sources":["../../src/server/entry.tsx"],"mappings":";;;YAsDY,cAAc,sBAAsB,qBAAqB;iBAEpD;EAChB,OAAO,aAAa,OAAO,YAAY;EACvC;;qBAGY,oBAAqB,UAAU,6BAA2B"}
@@ -3,6 +3,7 @@ import { HTTPError, defineHandler, writeEarlyHints } from "nitro/h3";
3
3
  import { addRoute, createRouter, findRoute } from "rou3";
4
4
  import { withLeadingSlash, withoutTrailingSlash } from "ufo";
5
5
  import { clientAssets } from "virtual:yamf:assets";
6
+ import { errorHandler } from "virtual:yamf:error-handler";
6
7
  import { assets, pages } from "virtual:yamf:pages";
7
8
  import { rootAssets } from "virtual:yamf:root";
8
9
  //#region src/server/entry.tsx
@@ -19,7 +20,7 @@ for (const [relativePath, handler] of Object.entries(pages).toSorted((a, b) => a
19
20
  });
20
21
  }
21
22
  const defineServerEntry = (options) => {
22
- return defineHandler(async (event) => {
23
+ const rootHandler = async (event) => {
23
24
  const route = findRoute(router, "GET", event.url.pathname);
24
25
  if (!route) throw new HTTPError("Not found", { status: 404 });
25
26
  const { handler, serverAssets } = route.data;
@@ -33,6 +34,15 @@ const defineServerEntry = (options) => {
33
34
  assets,
34
35
  head: typeof options?.head === "function" ? options.head(event) : options?.head
35
36
  });
37
+ };
38
+ return defineHandler(async (event) => {
39
+ if (!errorHandler) return rootHandler(event);
40
+ try {
41
+ return await rootHandler(event);
42
+ } catch (error) {
43
+ const httpError = error instanceof HTTPError ? error : new HTTPError({ cause: error });
44
+ return errorHandler(httpError, event);
45
+ }
36
46
  });
37
47
  };
38
48
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"entry.mjs","names":["pagesServerAssets"],"sources":["../../src/server/entry.tsx"],"sourcesContent":["import path from \"node:path\";\nimport type { EventHandlerRequest, EventHandlerWithFetch, H3Event } from \"nitro/h3\";\nimport { defineHandler, HTTPError, writeEarlyHints } from \"nitro/h3\";\nimport { addRoute, createRouter, findRoute } from \"rou3\";\nimport { withLeadingSlash, withoutTrailingSlash } from \"ufo\";\nimport { clientAssets } from \"virtual:yamf:assets\";\nimport { pages, assets as pagesServerAssets } from \"virtual:yamf:pages\";\nimport { rootAssets } from \"virtual:yamf:root\";\nimport type { PageHandler } from \"#/page\";\nimport { YamfHead } from \"#/shared/head\";\n\ninterface Route {\n\thandler: () => Promise<PageHandler>;\n\tserverAssets?: ImportAssetsResult;\n}\n\nconst router = createRouter<Route>();\n\nfor (const [relativePath, handler] of Object.entries(pages).toSorted((a, b) =>\n\ta[0].localeCompare(b[0]),\n)) {\n\tconst ext = path.extname(relativePath);\n\n\tlet route = path.relative(\"/src/pages\", relativePath);\n\n\tif (ext.length) {\n\t\troute = route.slice(0, -ext.length);\n\t}\n\n\troute =\n\t\troute\n\t\t\t.replace(/\\.[A-Za-z]+$/, \"\")\n\t\t\t.replace(/\\(([^(/\\\\]+)\\)[/\\\\]/g, \"\")\n\t\t\t.replace(/\\[\\.{3}]/g, \"**\")\n\t\t\t.replace(/\\[\\.{3}([^\\]]+)]/g, (_, p: string) => \"**:\" + p.replace(/[^\\w-]/g, \"_\"))\n\t\t\t.replace(/\\[([^/\\]]+)]/g, (_, p: string) => \":\" + p.replace(/[^\\w-]/g, \"_\"))\n\t\t\t.replace(/(\\/|^)index$/, \"\") || \"/\";\n\n\troute = withLeadingSlash(withoutTrailingSlash(route));\n\n\taddRoute(router, \"GET\", route, {\n\t\thandler,\n\t\tserverAssets: pagesServerAssets[relativePath],\n\t});\n}\n\nexport type ServerEntry = EventHandlerWithFetch<EventHandlerRequest, Promise<unknown>>;\n\nexport interface DefineServerEntryOptions {\n\thead?: YamfHead | ((event: H3Event) => YamfHead);\n\tdisableEarlyHints?: boolean;\n}\n\nexport const defineServerEntry = (options?: DefineServerEntryOptions): ServerEntry => {\n\treturn defineHandler(async event => {\n\t\tconst route = findRoute(router, \"GET\", event.url.pathname);\n\n\t\tif (!route) {\n\t\t\tthrow new HTTPError(\"Not found\", { status: 404 });\n\t\t}\n\n\t\tconst { handler, serverAssets } = route.data;\n\t\tevent.context.params = route.params;\n\n\t\tconst assets = clientAssets.merge(...[rootAssets, serverAssets].filter(x => !!x));\n\n\t\tif (!options?.disableEarlyHints) {\n\t\t\tconst link = [\n\t\t\t\t...assets.js.map(script => `<${script.href}>; rel=modulepreload`),\n\t\t\t\t...assets.css.map(style => `<${style.href}>; rel=preload; as=style`),\n\t\t\t];\n\n\t\t\tif (link.length) {\n\t\t\t\tawait writeEarlyHints(event, { link });\n\t\t\t}\n\t\t}\n\n\t\treturn (await handler())(event, {\n\t\t\tassets,\n\t\t\thead: typeof options?.head === \"function\" ? options.head(event) : options?.head,\n\t\t});\n\t});\n};\n"],"mappings":";;;;;;;;AAgBA,MAAM,SAAS,aAAoB;AAEnC,KAAK,MAAM,CAAC,cAAc,YAAY,OAAO,QAAQ,KAAK,CAAC,CAAC,UAAU,GAAG,MACxE,EAAE,EAAE,CAAC,cAAc,EAAE,EAAE,CACxB,GAAG;CACF,MAAM,MAAM,KAAK,QAAQ,YAAY;CAErC,IAAI,QAAQ,KAAK,SAAS,cAAc,YAAY;CAEpD,IAAI,IAAI,QACP,QAAQ,MAAM,MAAM,GAAG,CAAC,IAAI,MAAM;CAGnC,QACC,MACE,QAAQ,gBAAgB,EAAE,CAAC,CAC3B,QAAQ,wBAAwB,EAAE,CAAC,CACnC,QAAQ,aAAa,IAAI,CAAC,CAC1B,QAAQ,sBAAsB,GAAG,MAAc,QAAQ,EAAE,QAAQ,WAAW,GAAG,CAAC,CAAC,CACjF,QAAQ,kBAAkB,GAAG,MAAc,MAAM,EAAE,QAAQ,WAAW,GAAG,CAAC,CAAC,CAC3E,QAAQ,gBAAgB,EAAE,KAAK;CAElC,QAAQ,iBAAiB,qBAAqB,KAAK,CAAC;CAEpD,SAAS,QAAQ,OAAO,OAAO;EAC9B;EACA,cAAcA,OAAkB;CACjC,CAAC;AACF;AASA,MAAa,qBAAqB,YAAoD;CACrF,OAAO,cAAc,OAAM,UAAS;EACnC,MAAM,QAAQ,UAAU,QAAQ,OAAO,MAAM,IAAI,QAAQ;EAEzD,IAAI,CAAC,OACJ,MAAM,IAAI,UAAU,aAAa,EAAE,QAAQ,IAAI,CAAC;EAGjD,MAAM,EAAE,SAAS,iBAAiB,MAAM;EACxC,MAAM,QAAQ,SAAS,MAAM;EAE7B,MAAM,SAAS,aAAa,MAAM,GAAG,CAAC,YAAY,YAAY,CAAC,CAAC,QAAO,MAAK,CAAC,CAAC,CAAC,CAAC;EAEhF,IAAI,CAAC,SAAS,mBAAmB;GAChC,MAAM,OAAO,CACZ,GAAG,OAAO,GAAG,KAAI,WAAU,IAAI,OAAO,KAAK,qBAAqB,GAChE,GAAG,OAAO,IAAI,KAAI,UAAS,IAAI,MAAM,KAAK,yBAAyB,CACpE;GAEA,IAAI,KAAK,QACR,MAAM,gBAAgB,OAAO,EAAE,KAAK,CAAC;EAEvC;EAEA,QAAQ,MAAM,QAAQ,EAAA,CAAG,OAAO;GAC/B;GACA,MAAM,OAAO,SAAS,SAAS,aAAa,QAAQ,KAAK,KAAK,IAAI,SAAS;EAC5E,CAAC;CACF,CAAC;AACF"}
1
+ {"version":3,"file":"entry.mjs","names":["pagesServerAssets"],"sources":["../../src/server/entry.tsx"],"sourcesContent":["import path from \"node:path\";\nimport {\n\tdefineHandler,\n\tEventHandler,\n\tH3Event,\n\tHTTPError,\n\twriteEarlyHints,\n\ttype EventHandlerRequest,\n\ttype EventHandlerWithFetch,\n} from \"nitro/h3\";\nimport { addRoute, createRouter, findRoute } from \"rou3\";\nimport { withLeadingSlash, withoutTrailingSlash } from \"ufo\";\nimport { clientAssets } from \"virtual:yamf:assets\";\nimport { errorHandler } from \"virtual:yamf:error-handler\";\nimport { pages, assets as pagesServerAssets } from \"virtual:yamf:pages\";\nimport { rootAssets } from \"virtual:yamf:root\";\nimport type { PageHandler } from \"#/page\";\nimport { YamfHead } from \"#/shared/head\";\n\ninterface Route {\n\thandler: () => Promise<PageHandler>;\n\tserverAssets?: ImportAssetsResult;\n}\n\nconst router = createRouter<Route>();\n\nfor (const [relativePath, handler] of Object.entries(pages).toSorted((a, b) =>\n\ta[0].localeCompare(b[0]),\n)) {\n\tconst ext = path.extname(relativePath);\n\n\tlet route = path.relative(\"/src/pages\", relativePath);\n\n\tif (ext.length) {\n\t\troute = route.slice(0, -ext.length);\n\t}\n\n\troute =\n\t\troute\n\t\t\t.replace(/\\.[A-Za-z]+$/, \"\")\n\t\t\t.replace(/\\(([^(/\\\\]+)\\)[/\\\\]/g, \"\")\n\t\t\t.replace(/\\[\\.{3}]/g, \"**\")\n\t\t\t.replace(/\\[\\.{3}([^\\]]+)]/g, (_, p: string) => \"**:\" + p.replace(/[^\\w-]/g, \"_\"))\n\t\t\t.replace(/\\[([^/\\]]+)]/g, (_, p: string) => \":\" + p.replace(/[^\\w-]/g, \"_\"))\n\t\t\t.replace(/(\\/|^)index$/, \"\") || \"/\";\n\n\troute = withLeadingSlash(withoutTrailingSlash(route));\n\n\taddRoute(router, \"GET\", route, {\n\t\thandler,\n\t\tserverAssets: pagesServerAssets[relativePath],\n\t});\n}\n\nexport type ServerEntry = EventHandlerWithFetch<EventHandlerRequest, Promise<unknown>>;\n\nexport interface DefineServerEntryOptions {\n\thead?: YamfHead | ((event: H3Event) => YamfHead);\n\tdisableEarlyHints?: boolean;\n}\n\nexport const defineServerEntry = (options?: DefineServerEntryOptions): ServerEntry => {\n\tconst rootHandler: EventHandler<EventHandlerRequest, Promise<unknown>> = async event => {\n\t\tconst route = findRoute(router, \"GET\", event.url.pathname);\n\n\t\tif (!route) {\n\t\t\tthrow new HTTPError(\"Not found\", { status: 404 });\n\t\t}\n\n\t\tconst { handler, serverAssets } = route.data;\n\t\tevent.context.params = route.params;\n\n\t\tconst assets = clientAssets.merge(...[rootAssets, serverAssets].filter(x => !!x));\n\n\t\tif (!options?.disableEarlyHints) {\n\t\t\tconst link = [\n\t\t\t\t...assets.js.map(script => `<${script.href}>; rel=modulepreload`),\n\t\t\t\t...assets.css.map(style => `<${style.href}>; rel=preload; as=style`),\n\t\t\t];\n\n\t\t\tif (link.length) {\n\t\t\t\tawait writeEarlyHints(event, { link });\n\t\t\t}\n\t\t}\n\n\t\treturn (await handler())(event, {\n\t\t\tassets,\n\t\t\thead: typeof options?.head === \"function\" ? options.head(event) : options?.head,\n\t\t});\n\t};\n\n\treturn defineHandler(async event => {\n\t\tif (!errorHandler) {\n\t\t\treturn rootHandler(event);\n\t\t}\n\n\t\ttry {\n\t\t\treturn await rootHandler(event);\n\t\t} catch (error) {\n\t\t\tconst httpError = error instanceof HTTPError ? error : new HTTPError({ cause: error });\n\n\t\t\treturn errorHandler(httpError, event);\n\t\t}\n\t});\n};\n"],"mappings":";;;;;;;;;AAwBA,MAAM,SAAS,aAAoB;AAEnC,KAAK,MAAM,CAAC,cAAc,YAAY,OAAO,QAAQ,KAAK,CAAC,CAAC,UAAU,GAAG,MACxE,EAAE,EAAE,CAAC,cAAc,EAAE,EAAE,CACxB,GAAG;CACF,MAAM,MAAM,KAAK,QAAQ,YAAY;CAErC,IAAI,QAAQ,KAAK,SAAS,cAAc,YAAY;CAEpD,IAAI,IAAI,QACP,QAAQ,MAAM,MAAM,GAAG,CAAC,IAAI,MAAM;CAGnC,QACC,MACE,QAAQ,gBAAgB,EAAE,CAAC,CAC3B,QAAQ,wBAAwB,EAAE,CAAC,CACnC,QAAQ,aAAa,IAAI,CAAC,CAC1B,QAAQ,sBAAsB,GAAG,MAAc,QAAQ,EAAE,QAAQ,WAAW,GAAG,CAAC,CAAC,CACjF,QAAQ,kBAAkB,GAAG,MAAc,MAAM,EAAE,QAAQ,WAAW,GAAG,CAAC,CAAC,CAC3E,QAAQ,gBAAgB,EAAE,KAAK;CAElC,QAAQ,iBAAiB,qBAAqB,KAAK,CAAC;CAEpD,SAAS,QAAQ,OAAO,OAAO;EAC9B;EACA,cAAcA,OAAkB;CACjC,CAAC;AACF;AASA,MAAa,qBAAqB,YAAoD;CACrF,MAAM,cAAmE,OAAM,UAAS;EACvF,MAAM,QAAQ,UAAU,QAAQ,OAAO,MAAM,IAAI,QAAQ;EAEzD,IAAI,CAAC,OACJ,MAAM,IAAI,UAAU,aAAa,EAAE,QAAQ,IAAI,CAAC;EAGjD,MAAM,EAAE,SAAS,iBAAiB,MAAM;EACxC,MAAM,QAAQ,SAAS,MAAM;EAE7B,MAAM,SAAS,aAAa,MAAM,GAAG,CAAC,YAAY,YAAY,CAAC,CAAC,QAAO,MAAK,CAAC,CAAC,CAAC,CAAC;EAEhF,IAAI,CAAC,SAAS,mBAAmB;GAChC,MAAM,OAAO,CACZ,GAAG,OAAO,GAAG,KAAI,WAAU,IAAI,OAAO,KAAK,qBAAqB,GAChE,GAAG,OAAO,IAAI,KAAI,UAAS,IAAI,MAAM,KAAK,yBAAyB,CACpE;GAEA,IAAI,KAAK,QACR,MAAM,gBAAgB,OAAO,EAAE,KAAK,CAAC;EAEvC;EAEA,QAAQ,MAAM,QAAQ,EAAA,CAAG,OAAO;GAC/B;GACA,MAAM,OAAO,SAAS,SAAS,aAAa,QAAQ,KAAK,KAAK,IAAI,SAAS;EAC5E,CAAC;CACF;CAEA,OAAO,cAAc,OAAM,UAAS;EACnC,IAAI,CAAC,cACJ,OAAO,YAAY,KAAK;EAGzB,IAAI;GACH,OAAO,MAAM,YAAY,KAAK;EAC/B,SAAS,OAAO;GACf,MAAM,YAAY,iBAAiB,YAAY,QAAQ,IAAI,UAAU,EAAE,OAAO,MAAM,CAAC;GAErF,OAAO,aAAa,WAAW,KAAK;EACrC;CACD,CAAC;AACF"}
@@ -9,14 +9,13 @@ declare module "hono/jsx" {
9
9
  "island-props"?: string;
10
10
  "island-src": string;
11
11
  "island-entry": string;
12
- "island-client": IslandClientDirective;
12
+ "island-client"?: IslandClientDirective;
13
13
  children: Child;
14
14
  style?: JSX.CSSProperties;
15
15
  };
16
16
  }
17
17
  }
18
18
  }
19
- declare const createIsland: (Component: FC, exportName: string, assets: ImportAssetsResultRaw) => FC;
19
+ export declare const createIsland: (Component: FC, exportName: string, assets: ImportAssetsResultRaw) => FC;
20
20
  //#endregion
21
- export { createIsland };
22
21
  //# sourceMappingURL=server.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../../../src/island/server.tsx"],"mappings":";;;;;YAMW;cACC;MACT;QACC;QACA;QACA;QACA,iBAAiB;QACjB,UAAU;QACV,QAAQ,IAAI;;;;;cAMH,eACZ,WAAW,IACX,oBACA,QAAQ,0BACN"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../../../src/island/server.tsx"],"mappings":";;;;;YAMW;cACC;MACT;QACC;QACA;QACA;QACA,kBAAkB;QAClB,UAAU;QACV,QAAQ,IAAI;;;;;qBAMH,eACZ,WAAW,IACX,oBACA,QAAQ,0BACN"}
@@ -2,13 +2,13 @@ import { stringify } from "devalue";
2
2
  import { jsx } from "hono/jsx/jsx-runtime";
3
3
  //#region src/island/server.tsx
4
4
  const createIsland = (Component, exportName, assets) => {
5
- const ComponentWrapper = (props) => {
5
+ const ComponentWrapper = ({ "yamf-client": clientDirective, ...props }) => {
6
6
  if (!assets.entry) throw new Error(`Missing island entry for island ${Component.name}`);
7
7
  return /* @__PURE__ */ jsx("yamf-island", {
8
8
  "island-props": stringify(props),
9
9
  "island-src": assets.entry,
10
10
  "island-entry": exportName,
11
- "island-client": props["yamf-client"],
11
+ "island-client": clientDirective,
12
12
  style: { display: "contents" },
13
13
  children: /* @__PURE__ */ jsx(Component, { ...props })
14
14
  });
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","names":[],"sources":["../../../src/island/server.tsx"],"sourcesContent":["import { stringify } from \"devalue\";\nimport type { Child, FC } from \"hono/jsx\";\nimport type { ImportAssetsResultRaw } from \"#/shared/assets\";\nimport type { IslandClientDirective } from \"./types\";\n\ndeclare module \"hono/jsx\" {\n\tnamespace JSX {\n\t\tinterface IntrinsicElements {\n\t\t\t\"yamf-island\": {\n\t\t\t\t\"island-props\"?: string;\n\t\t\t\t\"island-src\": string;\n\t\t\t\t\"island-entry\": string;\n\t\t\t\t\"island-client\": IslandClientDirective;\n\t\t\t\tchildren: Child;\n\t\t\t\tstyle?: JSX.CSSProperties;\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport const createIsland = (\n\tComponent: FC,\n\texportName: string,\n\tassets: ImportAssetsResultRaw,\n): FC => {\n\tconst ComponentWrapper: FC & { name: string } = props => {\n\t\tif (!assets.entry) {\n\t\t\tthrow new Error(`Missing island entry for island ${Component.name}`);\n\t\t}\n\n\t\treturn (\n\t\t\t<yamf-island\n\t\t\t\tisland-props={stringify(props)}\n\t\t\t\tisland-src={assets.entry}\n\t\t\t\tisland-entry={exportName}\n\t\t\t\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion\n\t\t\t\tisland-client={props[\"yamf-client\"] as IslandClientDirective}\n\t\t\t\t// TODO: export CSS?\n\t\t\t\tstyle={{ display: \"contents\" }}\n\t\t\t>\n\t\t\t\t<Component {...props} />\n\t\t\t</yamf-island>\n\t\t);\n\t};\n\n\tObject.defineProperty(ComponentWrapper, \"name\", {\n\t\tvalue: Component.name,\n\t});\n\n\treturn ComponentWrapper;\n};\n"],"mappings":";;;AAoBA,MAAa,gBACZ,WACA,YACA,WACQ;CACR,MAAM,oBAA0C,UAAS;EACxD,IAAI,CAAC,OAAO,OACX,MAAM,IAAI,MAAM,mCAAmC,UAAU,MAAM;EAGpE,OACC,oBAAC,eAAD;GACC,gBAAc,UAAU,KAAK;GAC7B,cAAY,OAAO;GACnB,gBAAc;GAEd,iBAAe,MAAM;GAErB,OAAO,EAAE,SAAS,WAAW;GAE7B,UAAA,oBAAC,WAAD,EAAW,GAAI,MAAQ,CAAA;EACX,CAAA;CAEf;CAEA,OAAO,eAAe,kBAAkB,QAAQ,EAC/C,OAAO,UAAU,KAClB,CAAC;CAED,OAAO;AACR"}
1
+ {"version":3,"file":"server.mjs","names":[],"sources":["../../../src/island/server.tsx"],"sourcesContent":["import { stringify } from \"devalue\";\nimport type { Child, FC } from \"hono/jsx\";\nimport type { ImportAssetsResultRaw } from \"#/shared/assets\";\nimport type { IslandClientDirective, IslandProps } from \"./types\";\n\ndeclare module \"hono/jsx\" {\n\tnamespace JSX {\n\t\tinterface IntrinsicElements {\n\t\t\t\"yamf-island\": {\n\t\t\t\t\"island-props\"?: string;\n\t\t\t\t\"island-src\": string;\n\t\t\t\t\"island-entry\": string;\n\t\t\t\t\"island-client\"?: IslandClientDirective;\n\t\t\t\tchildren: Child;\n\t\t\t\tstyle?: JSX.CSSProperties;\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport const createIsland = (\n\tComponent: FC,\n\texportName: string,\n\tassets: ImportAssetsResultRaw,\n): FC => {\n\tconst ComponentWrapper: FC<IslandProps> & { name: string } = ({\n\t\t\"yamf-client\": clientDirective,\n\t\t...props\n\t}) => {\n\t\tif (!assets.entry) {\n\t\t\tthrow new Error(`Missing island entry for island ${Component.name}`);\n\t\t}\n\n\t\treturn (\n\t\t\t<yamf-island\n\t\t\t\tisland-props={stringify(props)}\n\t\t\t\tisland-src={assets.entry}\n\t\t\t\tisland-entry={exportName}\n\t\t\t\tisland-client={clientDirective}\n\t\t\t\t// TODO: export CSS?\n\t\t\t\tstyle={{ display: \"contents\" }}\n\t\t\t>\n\t\t\t\t<Component {...props} />\n\t\t\t</yamf-island>\n\t\t);\n\t};\n\n\tObject.defineProperty(ComponentWrapper, \"name\", {\n\t\tvalue: Component.name,\n\t});\n\n\treturn ComponentWrapper;\n};\n"],"mappings":";;;AAoBA,MAAa,gBACZ,WACA,YACA,WACQ;CACR,MAAM,oBAAwD,EAC7D,eAAe,iBACf,GAAG,YACE;EACL,IAAI,CAAC,OAAO,OACX,MAAM,IAAI,MAAM,mCAAmC,UAAU,MAAM;EAGpE,OACC,oBAAC,eAAD;GACC,gBAAc,UAAU,KAAK;GAC7B,cAAY,OAAO;GACnB,gBAAc;GACd,iBAAe;GAEf,OAAO,EAAE,SAAS,WAAW;GAE7B,UAAA,oBAAC,WAAD,EAAW,GAAI,MAAQ,CAAA;EACX,CAAA;CAEf;CAEA,OAAO,eAAe,kBAAkB,QAAQ,EAC/C,OAAO,UAAU,KAClB,CAAC;CAED,OAAO;AACR"}
@@ -1,5 +1,4 @@
1
1
  //#region src/island/types.d.ts
2
- type IslandClientDirective = "load" | "idle" | "visible" | "skip" | boolean;
2
+ export type IslandClientDirective = "load" | "idle" | "visible" | "skip" | boolean;
3
3
  //#endregion
4
- export { IslandClientDirective };
5
4
  //# sourceMappingURL=types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/island/types.ts"],"mappings":";KAAY"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/island/types.ts"],"mappings":";YAAY"}
@@ -1,5 +1,5 @@
1
1
  //#region src/shared/assets.d.ts
2
- type ImportAssetsResultRaw = {
2
+ export type ImportAssetsResultRaw = {
3
3
  entry?: string;
4
4
  js: {
5
5
  href: string;
@@ -10,5 +10,4 @@ type ImportAssetsResultRaw = {
10
10
  }[];
11
11
  };
12
12
  //#endregion
13
- export { ImportAssetsResultRaw };
14
13
  //# sourceMappingURL=assets.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assets.d.mts","names":[],"sources":["../../../src/shared/assets.ts"],"mappings":";KAKY;EACX;EACA;IAAM;;EACN;IAAO;IAAc"}
1
+ {"version":3,"file":"assets.d.mts","names":[],"sources":["../../../src/shared/assets.ts"],"mappings":";YAKY;EACX;EACA;IAAM;;EACN;IAAO;IAAc"}
@@ -1,8 +1,7 @@
1
1
  import { ResolvableHead, UseSeoMetaInput } from "unhead/types";
2
2
  //#region src/shared/head.d.ts
3
- type YamfHead = ResolvableHead & {
3
+ export type YamfHead = ResolvableHead & {
4
4
  seo?: UseSeoMetaInput;
5
5
  };
6
6
  //#endregion
7
- export { YamfHead };
8
7
  //# sourceMappingURL=head.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"head.d.mts","names":[],"sources":["../../../src/shared/head.ts"],"mappings":";;KAEY,WAAW;EAAmB,MAAM"}
1
+ {"version":3,"file":"head.d.mts","names":[],"sources":["../../../src/shared/head.ts"],"mappings":";;YAEY,WAAW;EAAmB,MAAM"}
@@ -1,8 +1,8 @@
1
1
  //#region src/shared/assets.d.ts
2
- type ImportAssetsResult = ImportAssetsResultRaw & {
2
+ export type ImportAssetsResult = ImportAssetsResultRaw & {
3
3
  merge(...args: ImportAssetsResultRaw[]): ImportAssetsResult;
4
4
  };
5
- type ImportAssetsResultRaw = {
5
+ export type ImportAssetsResultRaw = {
6
6
  entry?: string;
7
7
  js: {
8
8
  href: string;
@@ -13,5 +13,4 @@ type ImportAssetsResultRaw = {
13
13
  }[];
14
14
  };
15
15
  //#endregion
16
- export { ImportAssetsResult, ImportAssetsResultRaw };
17
16
  //# sourceMappingURL=assets.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assets.d.ts","names":[],"sources":["../../src/shared/assets.ts"],"mappings":";KACY,qBAAqB;EAChC,SAAS,MAAM,0BAA0B;;KAG9B;EACX;EACA;IAAM;;EACN;IAAO;IAAc"}
1
+ {"version":3,"file":"assets.d.ts","names":[],"sources":["../../src/shared/assets.ts"],"mappings":";YACY,qBAAqB;EAChC,SAAS,MAAM,0BAA0B;;YAG9B;EACX;EACA;IAAM;;EACN;IAAO;IAAc"}
@@ -1,8 +1,7 @@
1
1
  import { ResolvableHead, UseSeoMetaInput } from "unhead/types";
2
2
  //#region src/shared/head.d.ts
3
- type YamfHead = ResolvableHead & {
3
+ export type YamfHead = ResolvableHead & {
4
4
  seo?: UseSeoMetaInput;
5
5
  };
6
6
  //#endregion
7
- export { YamfHead };
8
7
  //# sourceMappingURL=head.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"head.d.ts","names":[],"sources":["../../src/shared/head.ts"],"mappings":";;KAEY,WAAW;EAAmB,MAAM"}
1
+ {"version":3,"file":"head.d.ts","names":[],"sources":["../../src/shared/head.ts"],"mappings":";;YAEY,WAAW;EAAmB,MAAM"}
@@ -1,10 +1,10 @@
1
1
  import { NitroPluginConfig } from "nitro/vite";
2
2
  import { PluginOption } from "vite";
3
3
  //#region src/vite/index.d.ts
4
- interface YamfOptions {
4
+ export interface YamfOptions {
5
5
  nitro?: NitroPluginConfig;
6
6
  }
7
7
  declare const yamf: (options?: YamfOptions) => PluginOption[];
8
8
  //#endregion
9
- export { YamfOptions, yamf as default };
9
+ export { yamf as default };
10
10
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/vite/index.ts"],"mappings":";;;UAUiB;EAChB,QAAQ;;cAGH,OAAQ,UAAU,gBAAc"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/vite/index.ts"],"mappings":";;;iBAWiB;EAChB,QAAQ;;cAGH,OAAQ,UAAU,gBAAc"}
@@ -1,5 +1,6 @@
1
1
  import { islands } from "./islands.mjs";
2
2
  import { virtualAssets } from "./virtual-assets.mjs";
3
+ import { virtualErrorHandler } from "./virtual-error-handler.mjs";
3
4
  import { virtualPages } from "./virtual-pages.mjs";
4
5
  import { virtualRoot } from "./virtual-root.mjs";
5
6
  import { virtualTemplate } from "./virtual-template.mjs";
@@ -45,6 +46,7 @@ const yamf = (options) => {
45
46
  }
46
47
  });
47
48
  plugins.push(islands());
49
+ plugins.push(virtualErrorHandler(options));
48
50
  plugins.push(virtualAssets());
49
51
  plugins.push(virtualPages());
50
52
  plugins.push(virtualTemplate());
@@ -60,7 +62,7 @@ const yamf = (options) => {
60
62
  publicAssets: [{
61
63
  baseURL: "assets",
62
64
  dir: "./public/assets",
63
- maxAge: 365 * 24 * 60 * 60
65
+ maxAge: 31536e3
64
66
  }]
65
67
  }));
66
68
  return plugins;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/vite/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport type { NitroPluginConfig } from \"nitro/vite\";\nimport { nitro } from \"nitro/vite\";\nimport type { EnvironmentOptions, PluginOption } from \"vite\";\nimport { islands } from \"./islands\";\nimport { virtualAssets } from \"./virtual-assets\";\nimport { virtualPages } from \"./virtual-pages\";\nimport { virtualRoot } from \"./virtual-root\";\nimport { virtualTemplate } from \"./virtual-template\";\n\nexport interface YamfOptions {\n\tnitro?: NitroPluginConfig;\n}\n\nconst yamf = (options?: YamfOptions): PluginOption[] => {\n\tconst plugins: PluginOption[] = [];\n\n\t// TODO: extendable config\n\tplugins.push({\n\t\tname: \"yamf:config\",\n\t\tconfig() {\n\t\t\tconst ssrEnv: EnvironmentOptions = {\n\t\t\t\tbuild: {\n\t\t\t\t\t// TODO: figure out if this should be true\n\t\t\t\t\tcssCodeSplit: false,\n\t\t\t\t\trolldownOptions: {\n\t\t\t\t\t\tinput: \"./src/server.tsx\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\tssr: {\n\t\t\t\t\t// we need to inline because otherwise fullstack plugin fails to build manifest for assets imports\n\t\t\t\t\t// also, we need to bundle everything so that the `react` -> `@hono/react-compat` alias\n\t\t\t\t\t// is applied to all dependencies (e.g. wouter) in dev mode. Externalized deps are\n\t\t\t\t\t// loaded natively by Node, bypassing Vite's resolve.alias.\n\t\t\t\t\tnoExternal: true,\n\t\t\t\t},\n\t\t\t\toptimizeDeps: {\n\t\t\t\t\tinclude: [\n\t\t\t\t\t\t\"hono\",\n\t\t\t\t\t\t\"hono/jsx/dom/client\",\n\t\t\t\t\t\t\"hono/jsx/jsx-runtime\",\n\t\t\t\t\t\t\"devalue\",\n\t\t\t\t\t\t\"ufo\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tresolve: {\n\t\t\t\t\talias: [\n\t\t\t\t\t\t{ find: \"react\", replacement: \"@hono/react-compat\" },\n\t\t\t\t\t\t{ find: \"react-dom\", replacement: \"@hono/react-compat\" },\n\t\t\t\t\t\t// use-sync-external-store is a CJS package that requires(\"react\").\n\t\t\t\t\t\t// Vite's SSR module runner can't process CJS, so we alias it to\n\t\t\t\t\t\t// @hono/react-compat which exports useSyncExternalStore from hono/jsx.\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfind: /^use-sync-external-store(?:\\/shim(?:\\/.*)?)?$/,\n\t\t\t\t\t\t\treplacement: \"@hono/react-compat\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tenvironments: {\n\t\t\t\t\t...(existsSync(\"./src/server.tsx\") ? { ssr: ssrEnv } : {}),\n\t\t\t\t\tclient: {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\trolldownOptions: {\n\t\t\t\t\t\t\t\tinput: \"./src/client/index.ts\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tplugins.push(islands());\n\n\tplugins.push(virtualAssets());\n\tplugins.push(virtualPages());\n\tplugins.push(virtualTemplate());\n\tplugins.push(virtualRoot());\n\n\tplugins.push(\n\t\tnitro({\n\t\t\tserverDir: \"./src\",\n\t\t\trenderer: false,\n\t\t\t...options?.nitro,\n\t\t\tcompressPublicAssets: {\n\t\t\t\tgzip: true,\n\t\t\t\tbrotli: true,\n\t\t\t},\n\t\t\tpublicAssets: [\n\t\t\t\t{\n\t\t\t\t\tbaseURL: \"assets\",\n\t\t\t\t\tdir: \"./public/assets\",\n\t\t\t\t\tmaxAge: 365 * 24 * 60 * 60,\n\t\t\t\t},\n\t\t\t],\n\t\t}),\n\t);\n\n\treturn plugins;\n};\n\nexport default yamf;\n"],"mappings":";;;;;;;;AAcA,MAAM,QAAQ,YAA0C;CACvD,MAAM,UAA0B,CAAC;CAGjC,QAAQ,KAAK;EACZ,MAAM;EACN,SAAS;GAWR,OAAO;IACN,KAAK,EAKJ,YAAY,KACb;IACA,cAAc,EACb,SAAS;KACR;KACA;KACA;KACA;KACA;IACD,EACD;IACA,SAAS,EACR,OAAO;KACN;MAAE,MAAM;MAAS,aAAa;KAAqB;KACnD;MAAE,MAAM;MAAa,aAAa;KAAqB;KAIvD;MACC,MAAM;MACN,aAAa;KACd;IACD,EACD;IACA,cAAc;KACb,GAAI,WAAW,kBAAkB,IAAI,EAAE,KAAK,EAxC7C,OAAO;MAEN,cAAc;MACd,iBAAiB,EAChB,OAAO,mBACR;KACD,EAkCkD,EAAE,IAAI,CAAC;KACxD,QAAQ,EACP,OAAO,EACN,iBAAiB,EAChB,OAAO,wBACR,EACD,EACD;IACD;GACD;EACD;CACD,CAAC;CAED,QAAQ,KAAK,QAAQ,CAAC;CAEtB,QAAQ,KAAK,cAAc,CAAC;CAC5B,QAAQ,KAAK,aAAa,CAAC;CAC3B,QAAQ,KAAK,gBAAgB,CAAC;CAC9B,QAAQ,KAAK,YAAY,CAAC;CAE1B,QAAQ,KACP,MAAM;EACL,WAAW;EACX,UAAU;EACV,GAAG,SAAS;EACZ,sBAAsB;GACrB,MAAM;GACN,QAAQ;EACT;EACA,cAAc,CACb;GACC,SAAS;GACT,KAAK;GACL,QAAQ,MAAM,KAAK,KAAK;EACzB,CACD;CACD,CAAC,CACF;CAEA,OAAO;AACR"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/vite/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport type { NitroPluginConfig } from \"nitro/vite\";\nimport { nitro } from \"nitro/vite\";\nimport type { EnvironmentOptions, PluginOption } from \"vite\";\nimport { islands } from \"./islands\";\nimport { virtualAssets } from \"./virtual-assets\";\nimport { virtualErrorHandler } from \"./virtual-error-handler\";\nimport { virtualPages } from \"./virtual-pages\";\nimport { virtualRoot } from \"./virtual-root\";\nimport { virtualTemplate } from \"./virtual-template\";\n\nexport interface YamfOptions {\n\tnitro?: NitroPluginConfig;\n}\n\nconst yamf = (options?: YamfOptions): PluginOption[] => {\n\tconst plugins: PluginOption[] = [];\n\n\t// TODO: extendable config\n\tplugins.push({\n\t\tname: \"yamf:config\",\n\t\tconfig() {\n\t\t\tconst ssrEnv: EnvironmentOptions = {\n\t\t\t\tbuild: {\n\t\t\t\t\t// TODO: figure out if this should be true\n\t\t\t\t\tcssCodeSplit: false,\n\t\t\t\t\trolldownOptions: {\n\t\t\t\t\t\tinput: \"./src/server.tsx\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\tssr: {\n\t\t\t\t\t// we need to inline because otherwise fullstack plugin fails to build manifest for assets imports\n\t\t\t\t\t// also, we need to bundle everything so that the `react` -> `@hono/react-compat` alias\n\t\t\t\t\t// is applied to all dependencies (e.g. wouter) in dev mode. Externalized deps are\n\t\t\t\t\t// loaded natively by Node, bypassing Vite's resolve.alias.\n\t\t\t\t\tnoExternal: true,\n\t\t\t\t},\n\t\t\t\toptimizeDeps: {\n\t\t\t\t\tinclude: [\n\t\t\t\t\t\t\"hono\",\n\t\t\t\t\t\t\"hono/jsx/dom/client\",\n\t\t\t\t\t\t\"hono/jsx/jsx-runtime\",\n\t\t\t\t\t\t\"devalue\",\n\t\t\t\t\t\t\"ufo\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tresolve: {\n\t\t\t\t\talias: [\n\t\t\t\t\t\t{ find: \"react\", replacement: \"@hono/react-compat\" },\n\t\t\t\t\t\t{ find: \"react-dom\", replacement: \"@hono/react-compat\" },\n\t\t\t\t\t\t// use-sync-external-store is a CJS package that requires(\"react\").\n\t\t\t\t\t\t// Vite's SSR module runner can't process CJS, so we alias it to\n\t\t\t\t\t\t// @hono/react-compat which exports useSyncExternalStore from hono/jsx.\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfind: /^use-sync-external-store(?:\\/shim(?:\\/.*)?)?$/,\n\t\t\t\t\t\t\treplacement: \"@hono/react-compat\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tenvironments: {\n\t\t\t\t\t...(existsSync(\"./src/server.tsx\") ? { ssr: ssrEnv } : {}),\n\t\t\t\t\tclient: {\n\t\t\t\t\t\tbuild: {\n\t\t\t\t\t\t\trolldownOptions: {\n\t\t\t\t\t\t\t\tinput: \"./src/client/index.ts\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tplugins.push(islands());\n\n\tplugins.push(virtualErrorHandler(options));\n\tplugins.push(virtualAssets());\n\tplugins.push(virtualPages());\n\tplugins.push(virtualTemplate());\n\tplugins.push(virtualRoot());\n\n\tplugins.push(\n\t\tnitro({\n\t\t\tserverDir: \"./src\",\n\t\t\trenderer: false,\n\t\t\t...options?.nitro,\n\t\t\tcompressPublicAssets: {\n\t\t\t\tgzip: true,\n\t\t\t\tbrotli: true,\n\t\t\t},\n\t\t\tpublicAssets: [\n\t\t\t\t{\n\t\t\t\t\tbaseURL: \"assets\",\n\t\t\t\t\tdir: \"./public/assets\",\n\t\t\t\t\tmaxAge: 365 * 24 * 60 * 60,\n\t\t\t\t},\n\t\t\t],\n\t\t}),\n\t);\n\n\treturn plugins;\n};\n\nexport default yamf;\n"],"mappings":";;;;;;;;;AAeA,MAAM,QAAQ,YAA0C;CACvD,MAAM,UAA0B,CAAC;CAGjC,QAAQ,KAAK;EACZ,MAAM;EACN,SAAS;GAWR,OAAO;IACN,KAAK,EAKJ,YAAY,KACb;IACA,cAAc,EACb,SAAS;KACR;KACA;KACA;KACA;KACA;IACD,EACD;IACA,SAAS,EACR,OAAO;KACN;MAAE,MAAM;MAAS,aAAa;KAAqB;KACnD;MAAE,MAAM;MAAa,aAAa;KAAqB;KAIvD;MACC,MAAM;MACN,aAAa;KACd;IACD,EACD;IACA,cAAc;KACb,GAAI,WAAW,kBAAkB,IAAI,EAAE,KAAK,EAxC7C,OAAO;MAEN,cAAc;MACd,iBAAiB,EAChB,OAAO,mBACR;KACD,EAkCkD,EAAE,IAAI,CAAC;KACxD,QAAQ,EACP,OAAO,EACN,iBAAiB,EAChB,OAAO,wBACR,EACD,EACD;IACD;GACD;EACD;CACD,CAAC;CAED,QAAQ,KAAK,QAAQ,CAAC;CAEtB,QAAQ,KAAK,oBAAoB,OAAO,CAAC;CACzC,QAAQ,KAAK,cAAc,CAAC;CAC5B,QAAQ,KAAK,aAAa,CAAC;CAC3B,QAAQ,KAAK,gBAAgB,CAAC;CAC9B,QAAQ,KAAK,YAAY,CAAC;CAE1B,QAAQ,KACP,MAAM;EACL,WAAW;EACX,UAAU;EACV,GAAG,SAAS;EACZ,sBAAsB;GACrB,MAAM;GACN,QAAQ;EACT;EACA,cAAc,CACb;GACC,SAAS;GACT,KAAK;GACL,QAAQ;EACT,CACD;CACD,CAAC,CACF;CAEA,OAAO;AACR"}
@@ -1,81 +1,60 @@
1
- import { generate } from "@babel/generator";
2
- import { parse } from "@babel/parser";
3
- import _traverse from "@babel/traverse";
4
- import { callExpression, exportDefaultDeclaration, exportNamedDeclaration, functionDeclaration, functionExpression, identifier, importDeclaration, importDefaultSpecifier, importNamespaceSpecifier, memberExpression, stringLiteral, variableDeclaration, variableDeclarator } from "@babel/types";
1
+ import { withMagicString } from "rolldown-string";
2
+ import { Visitor } from "vite";
5
3
  //#region src/vite/islands.ts
6
- const traverse = _traverse.default ?? _traverse;
7
4
  const ISLAND_REGEX = /\.island\.(j|t)sx?$/;
5
+ function langFromId(id) {
6
+ if (id.endsWith(".tsx")) return "tsx";
7
+ if (id.endsWith(".ts")) return "ts";
8
+ if (id.endsWith(".jsx")) return "jsx";
9
+ return "js";
10
+ }
8
11
  const islands = () => {
9
12
  return [{
10
13
  name: "yamf:islands",
11
14
  transform: {
12
15
  filter: { id: ISLAND_REGEX },
13
- handler(code, id) {
16
+ handler: withMagicString(function(s, id) {
14
17
  if (this.environment.name !== "ssr") return;
18
+ const program = this.parse(s.original, { lang: langFromId(id) });
19
+ s.prepend(`import * as __runtime from "@pajecawav/yamf/server";\n`);
20
+ s.prepend(`import __assets from "${id}?assets=client";\n`);
15
21
  const seenExports = /* @__PURE__ */ new Set();
16
- const ast = parse(code, {
17
- sourceType: "module",
18
- plugins: ["typescript", "jsx"]
19
- });
20
- traverse(ast, {
21
- Program(path) {
22
- path.unshiftContainer("body", importDeclaration([importNamespaceSpecifier(identifier("__runtime"))], stringLiteral("@pajecawav/yamf/server")));
23
- path.unshiftContainer("body", importDeclaration([importDefaultSpecifier(identifier("__assets"))], stringLiteral(`${id}?assets=client`)));
22
+ new Visitor({
23
+ ExportDefaultDeclaration(node) {
24
+ const declaration = node.declaration;
25
+ if (declaration.type !== "FunctionDeclaration" && declaration.type !== "FunctionExpression" && declaration.type !== "ArrowFunctionExpression") return;
26
+ s.overwrite(node.start, declaration.start, "const __ISLAND__ = ");
27
+ s.appendRight(declaration.end, `; export default __runtime.createIsland(__ISLAND__, "default", __assets)`);
24
28
  },
25
- ExportDefaultDeclaration(path) {
26
- const declarationType = path.node.declaration.type;
27
- if (!(declarationType === "FunctionDeclaration" || declarationType === "FunctionExpression" || declarationType === "ArrowFunctionExpression")) return;
28
- const originalFunction = path.node.declaration.type === "FunctionExpression" || path.node.declaration.type === "ArrowFunctionExpression" ? path.node.declaration : functionExpression(null, path.node.declaration.params, path.node.declaration.body, void 0, path.node.declaration.async);
29
- const islandIdentifier = identifier("__ISLAND__");
30
- path.insertBefore(variableDeclaration("const", [variableDeclarator(islandIdentifier, originalFunction)]));
31
- path.replaceWith(exportDefaultDeclaration(callExpression(memberExpression(identifier("__runtime"), identifier("createIsland")), [
32
- islandIdentifier,
33
- stringLiteral("default"),
34
- identifier("__assets")
35
- ])));
36
- },
37
- ExportNamedDeclaration(path) {
38
- if (path.node.declaration?.type === "VariableDeclaration") {
39
- const declaration = path.node.declaration.declarations.at(0);
40
- if (!declaration || declaration.id.type !== "Identifier" || seenExports.has(declaration.id.name)) return;
41
- const exportName = declaration.id.name;
29
+ ExportNamedDeclaration(node) {
30
+ const declaration = node.declaration;
31
+ if (declaration?.type === "VariableDeclaration") {
32
+ const declarator = declaration.declarations[0];
33
+ if (!declarator || declarator.id.type !== "Identifier" || !declarator.init || seenExports.has(declarator.id.name)) return;
34
+ const exportName = declarator.id.name;
42
35
  seenExports.add(exportName);
43
- const islandIdentifier = identifier(`__wrap_${exportName}`);
44
- path.insertBefore(variableDeclaration("const", [variableDeclarator(islandIdentifier, declaration.init)]));
45
- path.replaceWith(exportNamedDeclaration(variableDeclaration("const", [variableDeclarator(identifier(exportName), callExpression(memberExpression(identifier("__runtime"), identifier("createIsland")), [
46
- islandIdentifier,
47
- stringLiteral(exportName),
48
- identifier("__assets")
49
- ]))])));
50
- } else if (path.node.declaration?.type === "FunctionDeclaration") {
51
- const declaration = path.node.declaration;
52
- if (!declaration || declaration.id?.type !== "Identifier" || seenExports.has(declaration.id.name)) return;
53
- const exportName = declaration.id.name;
36
+ s.overwrite(node.start, declarator.init.start, `const __wrap_${exportName} = `);
37
+ s.appendRight(declarator.init.end, `; export const ${exportName} = __runtime.createIsland(__wrap_${exportName}, "${exportName}", __assets)`);
38
+ } else if (declaration?.type === "FunctionDeclaration") {
39
+ const fnId = declaration.id;
40
+ if (!fnId || fnId.type !== "Identifier" || seenExports.has(fnId.name)) return;
41
+ const exportName = fnId.name;
54
42
  seenExports.add(exportName);
55
- const islandIdentifier = identifier(`__wrap_${exportName}`);
56
- path.insertBefore(functionDeclaration(islandIdentifier, declaration.params, declaration.body, declaration.generator, declaration.async));
57
- path.replaceWith(exportNamedDeclaration(variableDeclaration("const", [variableDeclarator(identifier(exportName), callExpression(memberExpression(identifier("__runtime"), identifier("createIsland")), [
58
- islandIdentifier,
59
- stringLiteral(exportName),
60
- identifier("__assets")
61
- ]))])));
43
+ s.remove(node.start, declaration.start);
44
+ s.overwrite(fnId.start, fnId.end, `__wrap_${exportName}`);
45
+ s.appendRight(declaration.end, `; export const ${exportName} = __runtime.createIsland(__wrap_${exportName}, "${exportName}", __assets)`);
62
46
  }
63
47
  }
64
- });
65
- const result = generate(ast);
66
- return {
67
- code: result.code,
68
- map: result.map
69
- };
70
- }
48
+ }).visit(program);
49
+ })
71
50
  }
72
51
  }, {
73
52
  name: "yamf:islands:raw-import",
74
53
  transform: {
75
54
  order: "post",
76
- handler(code) {
77
- if (code.includes("__island_raw_import__")) return code.replaceAll("__island_raw_import__", "import");
78
- }
55
+ handler: withMagicString(function(s) {
56
+ if (s.original.includes("__island_raw_import__")) s.replaceAll("__island_raw_import__", "import");
57
+ })
79
58
  }
80
59
  }];
81
60
  };