@pajecawav/yamf 0.0.5 → 0.0.6
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.
- package/dist/client/index.d.ts +1 -1
- package/dist/hooks/useHead.d.ts.map +1 -1
- package/dist/island/client.js +2 -2
- package/dist/island/client.js.map +1 -1
- package/dist/island/types.d.ts.map +1 -1
- package/dist/page.d.ts.map +1 -1
- package/dist/page.js +6 -1
- package/dist/page.js.map +1 -1
- package/dist/server/island/server.mjs.map +1 -1
- package/dist/vite/index.mjs +15 -1
- package/dist/vite/index.mjs.map +1 -1
- package/dist/vite/virtual-template.mjs +1 -0
- package/dist/vite/virtual-template.mjs.map +1 -1
- package/package.json +14 -11
- package/src/island/client.tsx +4 -4
- package/src/island/types.ts +7 -0
- package/src/page.tsx +4 -1
- package/src/vite/index.ts +17 -1
- package/src/vite/virtual-template.ts +1 -2
package/dist/client/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useHead.d.ts","names":[],"sources":["../../src/hooks/useHead.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"useHead.d.ts","names":[],"sources":["../../src/hooks/useHead.tsx"],"mappings":";;;QAMe;YACJ;IACT,aAAa;;;cAQF,UAAW,QAAQ;cAYnB,aAAc,QAAQ"}
|
package/dist/island/client.js
CHANGED
|
@@ -36,7 +36,7 @@ customElements.define("yamf-island", class extends HTMLElement {
|
|
|
36
36
|
__island_raw_import__(src).then(hydrateIsland);
|
|
37
37
|
};
|
|
38
38
|
switch (islandClient) {
|
|
39
|
-
case true:
|
|
39
|
+
case "true":
|
|
40
40
|
case "load":
|
|
41
41
|
initIsland();
|
|
42
42
|
break;
|
|
@@ -47,7 +47,7 @@ customElements.define("yamf-island", class extends HTMLElement {
|
|
|
47
47
|
if (this.firstElementChild) observe(this.firstElementChild, initIsland);
|
|
48
48
|
else initIsland();
|
|
49
49
|
break;
|
|
50
|
-
case false:
|
|
50
|
+
case "false":
|
|
51
51
|
case "skip": break;
|
|
52
52
|
default: throw new Error(`Invalid island-client value: ${islandClient}`);
|
|
53
53
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../../src/island/client.tsx"],"sourcesContent":["import { parse } from \"devalue\";\nimport type { FC } from \"hono/jsx\";\nimport { hydrateRoot } from \"hono/jsx/dom/client\";\nimport { withLeadingSlash } from \"ufo\";\nimport type {
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../src/island/client.tsx"],"sourcesContent":["import { parse } from \"devalue\";\nimport type { FC } from \"hono/jsx\";\nimport { hydrateRoot } from \"hono/jsx/dom/client\";\nimport { withLeadingSlash } from \"ufo\";\nimport type { IslandClientDirectiveSerialized } from \"./types\";\n\ndeclare let __island_raw_import__: <T>(file: string) => Promise<T>;\n\nconst listeners = new WeakMap<Element, VoidFunction>();\n\nconst observer = new IntersectionObserver(entries => {\n\tfor (const entry of entries) {\n\t\tif (entry.isIntersecting) {\n\t\t\tlisteners.get(entry.target)?.();\n\t\t\tunobserve(entry.target);\n\t\t}\n\t}\n});\n\nconst observe = (target: Element, cb: VoidFunction) => {\n\tobserver.observe(target);\n\tlisteners.set(target, cb);\n};\n\nconst unobserve = (target: Element) => {\n\tobserver.unobserve(target);\n\tlisteners.delete(target);\n};\n\ncustomElements.define(\n\t\"yamf-island\",\n\tclass extends HTMLElement {\n\t\tpublic connectedCallback() {\n\t\t\tconst islandProps = parse(this.getAttribute(\"island-props\") ?? \"{}\");\n\t\t\tconst islandSrc = this.getAttribute(\"island-src\");\n\t\t\tconst islandEntry = this.getAttribute(\"island-entry\");\n\t\t\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion\n\t\t\tconst islandClient = (this.getAttribute(\"island-client\") ??\n\t\t\t\t\"load\") as IslandClientDirectiveSerialized;\n\n\t\t\tif (!islandSrc) {\n\t\t\t\tthrow new Error(\"Missing island-src attribute\");\n\t\t\t}\n\n\t\t\tif (!islandEntry) {\n\t\t\t\tthrow new Error(\"Missing island-entry attribute\");\n\t\t\t}\n\n\t\t\tconst hydrateIsland = (mod: Record<string, FC>) => {\n\t\t\t\tconst Comp = mod[islandEntry];\n\n\t\t\t\tif (!Comp) {\n\t\t\t\t\tthrow new Error(`Missing island entry ${islandEntry} in ${islandSrc}`);\n\t\t\t\t}\n\n\t\t\t\thydrateRoot(this, <Comp {...islandProps} />);\n\t\t\t};\n\n\t\t\tconst initIsland = () => {\n\t\t\t\tconst src = withLeadingSlash(islandSrc);\n\t\t\t\tvoid __island_raw_import__<Record<string, FC>>(src).then(hydrateIsland);\n\t\t\t};\n\n\t\t\tswitch (islandClient) {\n\t\t\t\tcase \"true\":\n\t\t\t\tcase \"load\":\n\t\t\t\t\tinitIsland();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"idle\":\n\t\t\t\t\trequestIdleCallback(initIsland);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"visible\":\n\t\t\t\t\t// yamf-island has `display: contents` which breaks IntersectionObserver\n\t\t\t\t\t// so we have to observe the first child instead if it exists\n\t\t\t\t\tif (this.firstElementChild) {\n\t\t\t\t\t\tobserve(this.firstElementChild, initIsland);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinitIsland();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"false\":\n\t\t\t\tcase \"skip\":\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tislandClient satisfies never;\n\t\t\t\t\t// oxlint-disable-next-line typescript/restrict-template-expressions\n\t\t\t\t\tthrow new Error(`Invalid island-client value: ${islandClient}`);\n\t\t\t}\n\t\t}\n\n\t\tpublic disconnectedCallback() {\n\t\t\tunobserve(this);\n\t\t}\n\t},\n);\n"],"mappings":";;;;;AAQA,MAAM,4BAAY,IAAI,QAA+B;AAErD,MAAM,WAAW,IAAI,sBAAqB,YAAW;CACpD,KAAK,MAAM,SAAS,SACnB,IAAI,MAAM,gBAAgB;EACzB,UAAU,IAAI,MAAM,MAAM,CAAC,GAAG;EAC9B,UAAU,MAAM,MAAM;CACvB;AAEF,CAAC;AAED,MAAM,WAAW,QAAiB,OAAqB;CACtD,SAAS,QAAQ,MAAM;CACvB,UAAU,IAAI,QAAQ,EAAE;AACzB;AAEA,MAAM,aAAa,WAAoB;CACtC,SAAS,UAAU,MAAM;CACzB,UAAU,OAAO,MAAM;AACxB;AAEA,eAAe,OACd,eACA,cAAc,YAAY;CACzB,oBAA2B;EAC1B,MAAM,cAAc,MAAM,KAAK,aAAa,cAAc,KAAK,IAAI;EACnE,MAAM,YAAY,KAAK,aAAa,YAAY;EAChD,MAAM,cAAc,KAAK,aAAa,cAAc;EAEpD,MAAM,eAAgB,KAAK,aAAa,eAAe,KACtD;EAED,IAAI,CAAC,WACJ,MAAM,IAAI,MAAM,8BAA8B;EAG/C,IAAI,CAAC,aACJ,MAAM,IAAI,MAAM,gCAAgC;EAGjD,MAAM,iBAAiB,QAA4B;GAClD,MAAM,OAAO,IAAI;GAEjB,IAAI,CAAC,MACJ,MAAM,IAAI,MAAM,wBAAwB,YAAY,MAAM,WAAW;GAGtE,YAAY,MAAM,oBAAC,MAAD,EAAM,GAAI,YAAc,CAAA,CAAC;EAC5C;EAEA,MAAM,mBAAmB;GACxB,MAAM,MAAM,iBAAiB,SAAS;GACtC,sBAA+C,GAAG,CAAC,CAAC,KAAK,aAAa;EACvE;EAEA,QAAQ,cAAR;GACC,KAAK;GACL,KAAK;IACJ,WAAW;IACX;GACD,KAAK;IACJ,oBAAoB,UAAU;IAC9B;GACD,KAAK;IAGJ,IAAI,KAAK,mBACR,QAAQ,KAAK,mBAAmB,UAAU;SAE1C,WAAW;IAEZ;GACD,KAAK;GACL,KAAK,QACJ;GACD,SAGC,MAAM,IAAI,MAAM,gCAAgC,cAAc;EAChE;CACD;CAEA,uBAA8B;EAC7B,UAAU,IAAI;CACf;AACD,CACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/island/types.ts"],"mappings":";KAAY;
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/island/types.ts"],"mappings":";KAAY;UASK;EAChB,gBAAgB"}
|
package/dist/page.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","names":[],"sources":["../src/page.tsx"],"mappings":";;;;;;;
|
|
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"}
|
package/dist/page.js
CHANGED
|
@@ -8,6 +8,7 @@ import { transformHtmlTemplate } from "unhead/server";
|
|
|
8
8
|
import { createStreamableHead, wrapStream } from "unhead/stream/server";
|
|
9
9
|
import { Root } from "virtual:yamf:root";
|
|
10
10
|
import { template } from "virtual:yamf:template";
|
|
11
|
+
import { Router } from "wouter";
|
|
11
12
|
import { jsx } from "hono/jsx/jsx-runtime";
|
|
12
13
|
//#region src/page.tsx
|
|
13
14
|
const definePage = (options) => {
|
|
@@ -39,7 +40,11 @@ const definePage = (options) => {
|
|
|
39
40
|
head,
|
|
40
41
|
event
|
|
41
42
|
},
|
|
42
|
-
children: /* @__PURE__ */ jsx(
|
|
43
|
+
children: /* @__PURE__ */ jsx(Router, {
|
|
44
|
+
ssrPath: event.url.pathname,
|
|
45
|
+
ssrSearch: event.url.search,
|
|
46
|
+
children: /* @__PURE__ */ jsx(Root$1, { children: content })
|
|
47
|
+
})
|
|
43
48
|
});
|
|
44
49
|
const responseInit = { headers: { "Content-Type": "text/html; charset=utf-8" } };
|
|
45
50
|
if (!options.stream) return new Hono().get("/", async (c) => withServerTiming(event, "#render", async () => {
|
package/dist/page.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.js","names":["Root","RootComponent"],"sources":["../src/page.tsx"],"sourcesContent":["import { Fragment, type Child } from \"hono/jsx\";\nimport { renderToReadableStream } from \"hono/jsx/streaming\";\nimport { Hono } from \"hono/tiny\";\nimport type { EventHandlerResponse, H3Event } from \"nitro/h3\";\nimport { HTTPResponse, withServerTiming } from \"nitro/h3\";\nimport { useSeoMeta } from \"unhead\";\nimport type { Unhead } from \"unhead/server\";\nimport { transformHtmlTemplate } from \"unhead/server\";\nimport { createStreamableHead, wrapStream } from \"unhead/stream/server\";\nimport type { ResolvableLink, UseSeoMetaInput } from \"unhead/types\";\nimport { Root as RootComponent } from \"virtual:yamf:root\";\nimport { template } from \"virtual:yamf:template\";\nimport { SSRContext } from \"./context/ssr\";\nimport type { ImportAssetsResult } from \"./shared/assets\";\nimport { YamfHead } from \"./shared/head\";\n\nexport type PageHandler = (\n\tevent: H3Event,\n\tparams: {\n\t\tassets: ImportAssetsResult;\n\t\thead?: YamfHead;\n\t},\n) => EventHandlerResponse;\n\nexport type PageRenderer = (\n\tevent: H3Event,\n\tparams: {\n\t\thead: Unhead;\n\t\tseoHead: (input: UseSeoMetaInput) => void;\n\t},\n) => HTTPResponse | Child | Promise<Child | HTTPResponse>;\n\ninterface DefinePageOptions {\n\trender: PageRenderer;\n\tstream?: boolean;\n}\n\nexport const definePage = (options: DefinePageOptions): PageHandler => {\n\treturn async (event, { assets, head: headInit }) => {\n\t\tconst { head } = createStreamableHead({ init: [headInit] });\n\t\tconst seoHead = (input?: UseSeoMetaInput) => useSeoMeta(head, input);\n\t\tseoHead(headInit?.seo);\n\n\t\thead.push({\n\t\t\tlink: [\n\t\t\t\t...assets.js.map((attrs): ResolvableLink => ({ rel: \"modulepreload\", ...attrs })),\n\t\t\t\t...assets.css.map((attrs): ResolvableLink => ({ rel: \"stylesheet\", ...attrs })),\n\t\t\t],\n\t\t\tscript: [{ type: \"module\", src: assets.entry }],\n\t\t});\n\n\t\tconst content = await options.render(event, { head, seoHead });\n\n\t\tif (content instanceof HTTPResponse) {\n\t\t\treturn content;\n\t\t}\n\n\t\tconst Root = RootComponent ?? Fragment;\n\n\t\tconst App = async () => (\n\t\t\t<SSRContext value={{ head, event }}>\n\t\t\t\t<Root>{content}</Root>\n\t\t\t</SSRContext>\n\t\t);\n\n\t\tconst responseInit = {\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"text/html; charset=utf-8\",\n\t\t\t},\n\t\t};\n\n\t\tif (!options.stream) {\n\t\t\t// TODO: figure out how expensive this is\n\t\t\treturn new Hono()\n\t\t\t\t.get(\"/\", async c =>\n\t\t\t\t\twithServerTiming(event, \"#render\", async () => {\n\t\t\t\t\t\tconst response = await c.html(<App />);\n\n\t\t\t\t\t\tlet html = await response.text();\n\n\t\t\t\t\t\thtml = transformHtmlTemplate(\n\t\t\t\t\t\t\thead,\n\t\t\t\t\t\t\ttemplate.replace(\"<!--ssr-outlet-->\", html ?? \"\"),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn new Response(html, responseInit);\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.request(\"/\");\n\t\t}\n\n\t\tconst stream = wrapStream(head, renderToReadableStream(<App />), template);\n\n\t\treturn new Response(stream, responseInit);\n\t};\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"page.js","names":["Root","RootComponent"],"sources":["../src/page.tsx"],"sourcesContent":["import { Fragment, type Child } from \"hono/jsx\";\nimport { renderToReadableStream } from \"hono/jsx/streaming\";\nimport { Hono } from \"hono/tiny\";\nimport type { EventHandlerResponse, H3Event } from \"nitro/h3\";\nimport { HTTPResponse, withServerTiming } from \"nitro/h3\";\nimport { useSeoMeta } from \"unhead\";\nimport type { Unhead } from \"unhead/server\";\nimport { transformHtmlTemplate } from \"unhead/server\";\nimport { createStreamableHead, wrapStream } from \"unhead/stream/server\";\nimport type { ResolvableLink, UseSeoMetaInput } from \"unhead/types\";\nimport { Root as RootComponent } from \"virtual:yamf:root\";\nimport { template } from \"virtual:yamf:template\";\nimport { Router } from \"wouter\";\nimport { SSRContext } from \"./context/ssr\";\nimport type { ImportAssetsResult } from \"./shared/assets\";\nimport { YamfHead } from \"./shared/head\";\n\nexport type PageHandler = (\n\tevent: H3Event,\n\tparams: {\n\t\tassets: ImportAssetsResult;\n\t\thead?: YamfHead;\n\t},\n) => EventHandlerResponse;\n\nexport type PageRenderer = (\n\tevent: H3Event,\n\tparams: {\n\t\thead: Unhead;\n\t\tseoHead: (input: UseSeoMetaInput) => void;\n\t},\n) => HTTPResponse | Child | Promise<Child | HTTPResponse>;\n\ninterface DefinePageOptions {\n\trender: PageRenderer;\n\tstream?: boolean;\n}\n\nexport const definePage = (options: DefinePageOptions): PageHandler => {\n\treturn async (event, { assets, head: headInit }) => {\n\t\tconst { head } = createStreamableHead({ init: [headInit] });\n\t\tconst seoHead = (input?: UseSeoMetaInput) => useSeoMeta(head, input);\n\t\tseoHead(headInit?.seo);\n\n\t\thead.push({\n\t\t\tlink: [\n\t\t\t\t...assets.js.map((attrs): ResolvableLink => ({ rel: \"modulepreload\", ...attrs })),\n\t\t\t\t...assets.css.map((attrs): ResolvableLink => ({ rel: \"stylesheet\", ...attrs })),\n\t\t\t],\n\t\t\tscript: [{ type: \"module\", src: assets.entry }],\n\t\t});\n\n\t\tconst content = await options.render(event, { head, seoHead });\n\n\t\tif (content instanceof HTTPResponse) {\n\t\t\treturn content;\n\t\t}\n\n\t\tconst Root = RootComponent ?? Fragment;\n\n\t\tconst App = async () => (\n\t\t\t<SSRContext value={{ head, event }}>\n\t\t\t\t<Router ssrPath={event.url.pathname} ssrSearch={event.url.search}>\n\t\t\t\t\t<Root>{content}</Root>\n\t\t\t\t</Router>\n\t\t\t</SSRContext>\n\t\t);\n\n\t\tconst responseInit = {\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"text/html; charset=utf-8\",\n\t\t\t},\n\t\t};\n\n\t\tif (!options.stream) {\n\t\t\t// TODO: figure out how expensive this is\n\t\t\treturn new Hono()\n\t\t\t\t.get(\"/\", async c =>\n\t\t\t\t\twithServerTiming(event, \"#render\", async () => {\n\t\t\t\t\t\tconst response = await c.html(<App />);\n\n\t\t\t\t\t\tlet html = await response.text();\n\n\t\t\t\t\t\thtml = transformHtmlTemplate(\n\t\t\t\t\t\t\thead,\n\t\t\t\t\t\t\ttemplate.replace(\"<!--ssr-outlet-->\", html ?? \"\"),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn new Response(html, responseInit);\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.request(\"/\");\n\t\t}\n\n\t\tconst stream = wrapStream(head, renderToReadableStream(<App />), template);\n\n\t\treturn new Response(stream, responseInit);\n\t};\n};\n"],"mappings":";;;;;;;;;;;;;AAsCA,MAAa,cAAc,YAA4C;CACtE,OAAO,OAAO,OAAO,EAAE,QAAQ,MAAM,eAAe;EACnD,MAAM,EAAE,SAAS,qBAAqB,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;EAC1D,MAAM,WAAW,UAA4B,WAAW,MAAM,KAAK;EACnE,QAAQ,UAAU,GAAG;EAErB,KAAK,KAAK;GACT,MAAM,CACL,GAAG,OAAO,GAAG,KAAK,WAA2B;IAAE,KAAK;IAAiB,GAAG;GAAM,EAAE,GAChF,GAAG,OAAO,IAAI,KAAK,WAA2B;IAAE,KAAK;IAAc,GAAG;GAAM,EAAE,CAC/E;GACA,QAAQ,CAAC;IAAE,MAAM;IAAU,KAAK,OAAO;GAAM,CAAC;EAC/C,CAAC;EAED,MAAM,UAAU,MAAM,QAAQ,OAAO,OAAO;GAAE;GAAM;EAAQ,CAAC;EAE7D,IAAI,mBAAmB,cACtB,OAAO;EAGR,MAAMA,SAAOC,QAAiB;EAE9B,MAAM,MAAM,YACX,oBAAC,YAAD;GAAY,OAAO;IAAE;IAAM;GAAM;GAChC,UAAA,oBAAC,QAAD;IAAQ,SAAS,MAAM,IAAI;IAAU,WAAW,MAAM,IAAI;IACzD,UAAA,oBAACD,QAAD,EAAA,UAAO,QAAc,CAAA;GACd,CAAA;EACG,CAAA;EAGb,MAAM,eAAe,EACpB,SAAS,EACR,gBAAgB,2BACjB,EACD;EAEA,IAAI,CAAC,QAAQ,QAEZ,OAAO,IAAI,KAAK,CAAC,CACf,IAAI,KAAK,OAAM,MACf,iBAAiB,OAAO,WAAW,YAAY;GAG9C,IAAI,OAAO,OAAM,MAFM,EAAE,KAAK,oBAAC,KAAD,CAAM,CAAA,CAAC,EAAA,CAEX,KAAK;GAE/B,OAAO,sBACN,MACA,SAAS,QAAQ,qBAAqB,QAAQ,EAAE,CACjD;GAEA,OAAO,IAAI,SAAS,MAAM,YAAY;EACvC,CAAC,CACF,CAAC,CACA,QAAQ,GAAG;EAGd,MAAM,SAAS,WAAW,MAAM,uBAAuB,oBAAC,KAAD,CAAM,CAAA,CAAC,GAAG,QAAQ;EAEzE,OAAO,IAAI,SAAS,QAAQ,YAAY;CACzC;AACD"}
|
|
@@ -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;
|
|
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"}
|
package/dist/vite/index.mjs
CHANGED
|
@@ -12,7 +12,7 @@ const yamf = (options) => {
|
|
|
12
12
|
name: "yamf:config",
|
|
13
13
|
config() {
|
|
14
14
|
return {
|
|
15
|
-
ssr: { noExternal:
|
|
15
|
+
ssr: { noExternal: true },
|
|
16
16
|
optimizeDeps: { include: [
|
|
17
17
|
"hono",
|
|
18
18
|
"hono/jsx/dom/client",
|
|
@@ -20,6 +20,20 @@ const yamf = (options) => {
|
|
|
20
20
|
"devalue",
|
|
21
21
|
"ufo"
|
|
22
22
|
] },
|
|
23
|
+
resolve: { alias: [
|
|
24
|
+
{
|
|
25
|
+
find: "react",
|
|
26
|
+
replacement: "@hono/react-compat"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
find: "react-dom",
|
|
30
|
+
replacement: "@hono/react-compat"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
find: /^use-sync-external-store(?:\/shim(?:\/.*)?)?$/,
|
|
34
|
+
replacement: "@hono/react-compat"
|
|
35
|
+
}
|
|
36
|
+
] },
|
|
23
37
|
environments: {
|
|
24
38
|
...existsSync("./src/server.tsx") ? { ssr: { build: {
|
|
25
39
|
cssCodeSplit: false,
|
package/dist/vite/index.mjs.map
CHANGED
|
@@ -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\tnoExternal:
|
|
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"}
|
|
@@ -34,6 +34,7 @@ const virtualTemplate = () => {
|
|
|
34
34
|
if (relative(file, TEMPLATE_PATH) === "") {
|
|
35
35
|
const mod = server.moduleGraph.getModuleById(resolvedVirtualModuleId);
|
|
36
36
|
if (mod) server.moduleGraph.invalidateModule(mod);
|
|
37
|
+
server.ws.send({ type: "full-reload" });
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtual-template.mjs","names":[],"sources":["../../src/vite/virtual-template.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { relative } from \"node:path\";\nimport type { Plugin } from \"vite\";\nimport { js } from \"../shared/utils\";\n\nconst TEMPLATE_PATH = \"./src/template.html\";\n\nconst DEFAULT_TEMPLATE = /* html */ `\n<!DOCTYPE html>\n<html>\n <head></head>\n <body>\n <!--ssr-outlet-->\n </body>\n</html>\n`.trim();\n\nexport const virtualTemplate = (): Plugin => {\n\tconst virtualModuleId = \"virtual:yamf:template\";\n\tconst resolvedVirtualModuleId = \"\\0\" + virtualModuleId;\n\n\treturn {\n\t\tname: \"yamf:virtual-template\",\n\t\tresolveId(id) {\n\t\t\tif (id === virtualModuleId) {\n\t\t\t\treturn resolvedVirtualModuleId;\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t},\n\t\tasync load(id) {\n\t\t\tif (id !== resolvedVirtualModuleId) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst template = await readFile(TEMPLATE_PATH, \"utf8\");\n\n\t\t\t\treturn js`export const template = ${JSON.stringify(template)};`;\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n\t\t\t\t\treturn js`export const template = ${JSON.stringify(DEFAULT_TEMPLATE)};`;\n\t\t\t\t}\n\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\thandleHotUpdate({ file, server }) {\n\t\t\tif (relative(file, TEMPLATE_PATH) === \"\") {\n\t\t\t\tconst mod = server.moduleGraph.getModuleById(resolvedVirtualModuleId);\n\n\t\t\t\tif (mod) {\n\t\t\t\t\tserver.moduleGraph.invalidateModule(mod);\n\t\t\t\t}\n\n\t\t\t\
|
|
1
|
+
{"version":3,"file":"virtual-template.mjs","names":[],"sources":["../../src/vite/virtual-template.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { relative } from \"node:path\";\nimport type { Plugin } from \"vite\";\nimport { js } from \"../shared/utils\";\n\nconst TEMPLATE_PATH = \"./src/template.html\";\n\nconst DEFAULT_TEMPLATE = /* html */ `\n<!DOCTYPE html>\n<html>\n <head></head>\n <body>\n <!--ssr-outlet-->\n </body>\n</html>\n`.trim();\n\nexport const virtualTemplate = (): Plugin => {\n\tconst virtualModuleId = \"virtual:yamf:template\";\n\tconst resolvedVirtualModuleId = \"\\0\" + virtualModuleId;\n\n\treturn {\n\t\tname: \"yamf:virtual-template\",\n\t\tresolveId(id) {\n\t\t\tif (id === virtualModuleId) {\n\t\t\t\treturn resolvedVirtualModuleId;\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t},\n\t\tasync load(id) {\n\t\t\tif (id !== resolvedVirtualModuleId) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst template = await readFile(TEMPLATE_PATH, \"utf8\");\n\n\t\t\t\treturn js`export const template = ${JSON.stringify(template)};`;\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n\t\t\t\t\treturn js`export const template = ${JSON.stringify(DEFAULT_TEMPLATE)};`;\n\t\t\t\t}\n\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\thandleHotUpdate({ file, server }) {\n\t\t\tif (relative(file, TEMPLATE_PATH) === \"\") {\n\t\t\t\tconst mod = server.moduleGraph.getModuleById(resolvedVirtualModuleId);\n\n\t\t\t\tif (mod) {\n\t\t\t\t\tserver.moduleGraph.invalidateModule(mod);\n\t\t\t\t}\n\n\t\t\t\tserver.ws.send({ type: \"full-reload\" });\n\t\t\t}\n\t\t},\n\t};\n};\n"],"mappings":";;;;AAKA,MAAM,gBAAgB;AAEtB,MAAM,mBAA8B;;;;;;;;EAQlC,KAAK;AAEP,MAAa,wBAAgC;CAC5C,MAAM,kBAAkB;CACxB,MAAM,0BAA0B;CAEhC,OAAO;EACN,MAAM;EACN,UAAU,IAAI;GACb,IAAI,OAAO,iBACV,OAAO;EAIT;EACA,MAAM,KAAK,IAAI;GACd,IAAI,OAAO,yBACV;GAGD,IAAI;IACH,MAAM,WAAW,MAAM,SAAS,eAAe,MAAM;IAErD,OAAO,EAAE,2BAA2B,KAAK,UAAU,QAAQ,EAAE;GAC9D,SAAS,OAAO;IACf,IAAI,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,UAC/D,OAAO,EAAE,2BAA2B,KAAK,UAAU,gBAAgB,EAAE;IAGtE,MAAM;GACP;EACD;EACA,gBAAgB,EAAE,MAAM,UAAU;GACjC,IAAI,SAAS,MAAM,aAAa,MAAM,IAAI;IACzC,MAAM,MAAM,OAAO,YAAY,cAAc,uBAAuB;IAEpE,IAAI,KACH,OAAO,YAAY,iBAAiB,GAAG;IAGxC,OAAO,GAAG,KAAK,EAAE,MAAM,cAAc,CAAC;GACvC;EACD;CACD;AACD"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pajecawav/yamf",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.6",
|
|
5
5
|
"description": "Yet another meta framework",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/pajecawav/yamf#readme",
|
|
@@ -30,8 +30,9 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"hono": "^
|
|
34
|
-
"
|
|
33
|
+
"@hono/react-compat": "^0.0.3",
|
|
34
|
+
"hono": "^4.12.30",
|
|
35
|
+
"vite": "^8.1.5"
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"@babel/generator": "^7.29.7",
|
|
@@ -43,26 +44,28 @@
|
|
|
43
44
|
"nitro": "3.0.260610-beta",
|
|
44
45
|
"rou3": "^0.9.1",
|
|
45
46
|
"ufo": "^1.6.4",
|
|
46
|
-
"unhead": "^3.1.
|
|
47
|
+
"unhead": "^3.1.8",
|
|
48
|
+
"wouter": "^3.10.0"
|
|
47
49
|
},
|
|
48
50
|
"devDependencies": {
|
|
49
|
-
"@
|
|
51
|
+
"@hono/react-compat": "^0.0.3",
|
|
52
|
+
"@pajecawav/tools": "^0.0.7",
|
|
50
53
|
"@types/babel__generator": "^7.27.0",
|
|
51
54
|
"@types/babel__traverse": "^7.28.0",
|
|
52
55
|
"@types/node": "^24.13.3",
|
|
53
56
|
"@vitest/coverage-v8": "^4.1.10",
|
|
54
57
|
"@vitest/ui": "^4.1.10",
|
|
55
58
|
"cross-env": "^10.1.0",
|
|
56
|
-
"hono": "^4.12.
|
|
59
|
+
"hono": "^4.12.30",
|
|
57
60
|
"husky": "^9.1.7",
|
|
58
61
|
"npm-run-all2": "^9.0.2",
|
|
59
|
-
"oxfmt": "^0.
|
|
60
|
-
"oxlint": "^1.
|
|
61
|
-
"oxlint-tsgolint": "^0.
|
|
62
|
+
"oxfmt": "^0.59.0",
|
|
63
|
+
"oxlint": "^1.74.0",
|
|
64
|
+
"oxlint-tsgolint": "^0.25.0",
|
|
62
65
|
"publint": "^0.3.21",
|
|
63
|
-
"tsdown": "0.22.
|
|
66
|
+
"tsdown": "0.22.9",
|
|
64
67
|
"typescript": "~7.0.2",
|
|
65
|
-
"vite": "^8.
|
|
68
|
+
"vite": "^8.1.5",
|
|
66
69
|
"vitest": "^4.1.10"
|
|
67
70
|
},
|
|
68
71
|
"scripts": {
|
package/src/island/client.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import { parse } from "devalue";
|
|
|
2
2
|
import type { FC } from "hono/jsx";
|
|
3
3
|
import { hydrateRoot } from "hono/jsx/dom/client";
|
|
4
4
|
import { withLeadingSlash } from "ufo";
|
|
5
|
-
import type {
|
|
5
|
+
import type { IslandClientDirectiveSerialized } from "./types";
|
|
6
6
|
|
|
7
7
|
declare let __island_raw_import__: <T>(file: string) => Promise<T>;
|
|
8
8
|
|
|
@@ -36,7 +36,7 @@ customElements.define(
|
|
|
36
36
|
const islandEntry = this.getAttribute("island-entry");
|
|
37
37
|
// oxlint-disable-next-line typescript/no-unsafe-type-assertion
|
|
38
38
|
const islandClient = (this.getAttribute("island-client") ??
|
|
39
|
-
"load") as
|
|
39
|
+
"load") as IslandClientDirectiveSerialized;
|
|
40
40
|
|
|
41
41
|
if (!islandSrc) {
|
|
42
42
|
throw new Error("Missing island-src attribute");
|
|
@@ -62,7 +62,7 @@ customElements.define(
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
switch (islandClient) {
|
|
65
|
-
case true:
|
|
65
|
+
case "true":
|
|
66
66
|
case "load":
|
|
67
67
|
initIsland();
|
|
68
68
|
break;
|
|
@@ -78,7 +78,7 @@ customElements.define(
|
|
|
78
78
|
initIsland();
|
|
79
79
|
}
|
|
80
80
|
break;
|
|
81
|
-
case false:
|
|
81
|
+
case "false":
|
|
82
82
|
case "skip":
|
|
83
83
|
break;
|
|
84
84
|
default:
|
package/src/island/types.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export type IslandClientDirective = "load" | "idle" | "visible" | "skip" | boolean;
|
|
2
|
+
export type IslandClientDirectiveSerialized =
|
|
3
|
+
| "load"
|
|
4
|
+
| "idle"
|
|
5
|
+
| "visible"
|
|
6
|
+
| "skip"
|
|
7
|
+
| "true"
|
|
8
|
+
| "false";
|
|
2
9
|
|
|
3
10
|
export interface IslandProps {
|
|
4
11
|
"yamf-client"?: IslandClientDirective;
|
package/src/page.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import { createStreamableHead, wrapStream } from "unhead/stream/server";
|
|
|
10
10
|
import type { ResolvableLink, UseSeoMetaInput } from "unhead/types";
|
|
11
11
|
import { Root as RootComponent } from "virtual:yamf:root";
|
|
12
12
|
import { template } from "virtual:yamf:template";
|
|
13
|
+
import { Router } from "wouter";
|
|
13
14
|
import { SSRContext } from "./context/ssr";
|
|
14
15
|
import type { ImportAssetsResult } from "./shared/assets";
|
|
15
16
|
import { YamfHead } from "./shared/head";
|
|
@@ -59,7 +60,9 @@ export const definePage = (options: DefinePageOptions): PageHandler => {
|
|
|
59
60
|
|
|
60
61
|
const App = async () => (
|
|
61
62
|
<SSRContext value={{ head, event }}>
|
|
62
|
-
<
|
|
63
|
+
<Router ssrPath={event.url.pathname} ssrSearch={event.url.search}>
|
|
64
|
+
<Root>{content}</Root>
|
|
65
|
+
</Router>
|
|
63
66
|
</SSRContext>
|
|
64
67
|
);
|
|
65
68
|
|
package/src/vite/index.ts
CHANGED
|
@@ -32,7 +32,10 @@ const yamf = (options?: YamfOptions): PluginOption[] => {
|
|
|
32
32
|
return {
|
|
33
33
|
ssr: {
|
|
34
34
|
// we need to inline because otherwise fullstack plugin fails to build manifest for assets imports
|
|
35
|
-
|
|
35
|
+
// also, we need to bundle everything so that the `react` -> `@hono/react-compat` alias
|
|
36
|
+
// is applied to all dependencies (e.g. wouter) in dev mode. Externalized deps are
|
|
37
|
+
// loaded natively by Node, bypassing Vite's resolve.alias.
|
|
38
|
+
noExternal: true,
|
|
36
39
|
},
|
|
37
40
|
optimizeDeps: {
|
|
38
41
|
include: [
|
|
@@ -43,6 +46,19 @@ const yamf = (options?: YamfOptions): PluginOption[] => {
|
|
|
43
46
|
"ufo",
|
|
44
47
|
],
|
|
45
48
|
},
|
|
49
|
+
resolve: {
|
|
50
|
+
alias: [
|
|
51
|
+
{ find: "react", replacement: "@hono/react-compat" },
|
|
52
|
+
{ find: "react-dom", replacement: "@hono/react-compat" },
|
|
53
|
+
// use-sync-external-store is a CJS package that requires("react").
|
|
54
|
+
// Vite's SSR module runner can't process CJS, so we alias it to
|
|
55
|
+
// @hono/react-compat which exports useSyncExternalStore from hono/jsx.
|
|
56
|
+
{
|
|
57
|
+
find: /^use-sync-external-store(?:\/shim(?:\/.*)?)?$/,
|
|
58
|
+
replacement: "@hono/react-compat",
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
46
62
|
environments: {
|
|
47
63
|
...(existsSync("./src/server.tsx") ? { ssr: ssrEnv } : {}),
|
|
48
64
|
client: {
|