vinojs 0.0.1 → 0.1.0
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/README.md +172 -0
- package/dist/client.d.mts +41 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +287 -0
- package/dist/client.mjs.map +1 -0
- package/dist/compile-Lxl_tdxL.mjs +155 -0
- package/dist/compile-Lxl_tdxL.mjs.map +1 -0
- package/dist/component-wrap.d.mts +10 -0
- package/dist/component-wrap.d.mts.map +1 -0
- package/dist/component-wrap.mjs +33 -0
- package/dist/component-wrap.mjs.map +1 -0
- package/dist/constants-BVT2bJEd.mjs +27 -0
- package/dist/constants-BVT2bJEd.mjs.map +1 -0
- package/dist/definePage-Ba4r-TFh.mjs +51 -0
- package/dist/definePage-Ba4r-TFh.mjs.map +1 -0
- package/dist/types-CQITdkpF.d.mts +77 -0
- package/dist/types-CQITdkpF.d.mts.map +1 -0
- package/dist/vino.d.mts +144 -0
- package/dist/vino.d.mts.map +1 -0
- package/dist/vino.mjs +197 -0
- package/dist/vino.mjs.map +1 -0
- package/dist/vite.d.mts +10 -0
- package/dist/vite.d.mts.map +1 -0
- package/dist/vite.mjs +729 -0
- package/dist/vite.mjs.map +1 -0
- package/examples/basic/dist/client/.assetsignore +2 -0
- package/examples/basic/dist/client/about.html +1 -0
- package/examples/basic/dist/client/admin.html +1 -0
- package/examples/basic/dist/client/assets/Counter-BvqMZKON.js +1 -0
- package/examples/basic/dist/client/assets/_slug_-CYpOSbrn.js +1 -0
- package/examples/basic/dist/client/assets/about-BZXRzUyv.js +1 -0
- package/examples/basic/dist/client/assets/admin-DRE7uh2s.js +1 -0
- package/examples/basic/dist/client/assets/client-B6nFkut5.js +1 -0
- package/examples/basic/dist/client/assets/client-pages-Bc6cNZAm.js +2 -0
- package/examples/basic/dist/client/assets/components-DX9r6vHn.js +1 -0
- package/examples/basic/dist/client/assets/components-DsWJ6F73.js +2 -0
- package/examples/basic/dist/client/assets/counter-DBpvln_F.js +1 -0
- package/examples/basic/dist/client/assets/dom-B5sHIJ1E.js +1 -0
- package/examples/basic/dist/client/assets/honoto-9UtdLp4J.js +33 -0
- package/examples/basic/dist/client/assets/honoto-client-DEh86_WZ.css +1 -0
- package/examples/basic/dist/client/assets/honoto-client.js +2 -0
- package/examples/basic/dist/client/assets/hooks-Cz6AT21d.js +1 -0
- package/examples/basic/dist/client/assets/jsx-dev-runtime-92VDsVyo.js +1 -0
- package/examples/basic/dist/client/counter.html +1 -0
- package/examples/basic/dist/client/index.html +1 -0
- package/examples/basic/dist/client/jobs.html +1 -0
- package/examples/basic/dist/ssr/.vite/manifest.json +140 -0
- package/examples/basic/dist/ssr/assets/_slug_-CY3-kffX.js +46 -0
- package/examples/basic/dist/ssr/assets/about-CTDjNhkO.js +15 -0
- package/examples/basic/dist/ssr/assets/admin-DvS-UGJx.js +26 -0
- package/examples/basic/dist/ssr/assets/constants-UoriGYcX-CUecBFMT.js +6 -0
- package/examples/basic/dist/ssr/assets/counter-DfIbc9Sp.js +30 -0
- package/examples/basic/dist/ssr/assets/honoto-CA313cVy.js +2129 -0
- package/examples/basic/dist/ssr/assets/jobs-D9hh-UO9.js +42 -0
- package/examples/basic/dist/ssr/assets/jsx-CgYLQazd.js +1080 -0
- package/examples/basic/dist/ssr/assets/jsx-dev-runtime-BlUda7H8.js +742 -0
- package/examples/basic/dist/ssr/assets/jsx-renderer-CzZcZPnS.js +65 -0
- package/examples/basic/dist/ssr/assets/layout-DYvLwr2u.js +53 -0
- package/examples/basic/dist/ssr/assets/pages-DB6jeyrt.js +53 -0
- package/examples/basic/dist/ssr/assets/rolldown-runtime-D7D4PA-g.js +13 -0
- package/examples/basic/dist/ssr/assets/ssr-hooks-CBQr0cdH.js +7 -0
- package/examples/basic/dist/ssr/index.js +22 -0
- package/examples/basic/dist/ssr/wrangler.json +1 -0
- package/examples/full/dist/client/.assetsignore +2 -0
- package/examples/full/dist/client/assets/BookmarkButton-py0xGxgl.js +1 -0
- package/examples/full/dist/client/assets/_slug_-DZUFsE9O.js +1 -0
- package/examples/full/dist/client/assets/auth-client-D2Wtuobe.js +1 -0
- package/examples/full/dist/client/assets/bun-sqlite-dialect-C7ftEUSI-CsHdUKBY.js +1 -0
- package/examples/full/dist/client/assets/client-B6nFkut5.js +1 -0
- package/examples/full/dist/client/assets/client-pages-fshKs747.js +2 -0
- package/examples/full/dist/client/assets/components-DX9r6vHn.js +1 -0
- package/examples/full/dist/client/assets/components-S_-rWrKi.js +2 -0
- package/examples/full/dist/client/assets/d1-sqlite-dialect-BZmaVTp8-FPCaMZqX.js +1 -0
- package/examples/full/dist/client/assets/default-query-compiler-CUdqIu1h.js +1 -0
- package/examples/full/dist/client/assets/dist-BoGTNvkC.js +1 -0
- package/examples/full/dist/client/assets/dom-DCd3wYW7.js +1 -0
- package/examples/full/dist/client/assets/factory-Bgf4EtLx.js +8 -0
- package/examples/full/dist/client/assets/honoto-client-BSvNAnxN.css +1 -0
- package/examples/full/dist/client/assets/honoto-client.js +2 -0
- package/examples/full/dist/client/assets/hooks-Cz6AT21d.js +1 -0
- package/examples/full/dist/client/assets/jsx-dev-runtime-92VDsVyo.js +1 -0
- package/examples/full/dist/client/assets/kysely-adapter-BHhasAnc.js +1 -0
- package/examples/full/dist/client/assets/kysely-migration-tables-DFfmKhq--U5ujlMwE.js +1 -0
- package/examples/full/dist/client/assets/node-sqlite-dialect-DJDXH5Ot.js +1 -0
- package/examples/full/dist/client/assets/pages-CUQx6Eus.js +1 -0
- package/examples/full/dist/client/assets/saved-jIi74ncJ.js +1 -0
- package/examples/full/dist/client/assets/session-B-accyM3.js +611 -0
- package/examples/full/dist/client/assets/sign-in-BelI3gSs.js +1 -0
- package/examples/full/dist/client/assets/sign-up-pR94lfdu.js +1 -0
- package/examples/full/dist/client/index.html +1 -0
- package/examples/full/dist/client/saved.html +1 -0
- package/examples/full/dist/client/sign-in.html +1 -0
- package/examples/full/dist/client/sign-up.html +1 -0
- package/examples/full/dist/ssr/.dev.vars +1 -0
- package/examples/full/dist/ssr/.vite/manifest.json +219 -0
- package/examples/full/dist/ssr/assets/BookmarkButton-KS7z5_vi.js +298 -0
- package/examples/full/dist/ssr/assets/_slug_-rRStRaAN.js +89 -0
- package/examples/full/dist/ssr/assets/auth-DSFZ4iak.js +31434 -0
- package/examples/full/dist/ssr/assets/auth-client-BFSBVoML.js +894 -0
- package/examples/full/dist/ssr/assets/bun-sqlite-dialect-C7ftEUSI-BeXpIqKl.js +162 -0
- package/examples/full/dist/ssr/assets/compiled-query-DmoyCh28.js +8410 -0
- package/examples/full/dist/ssr/assets/d1-sqlite-dialect-BZmaVTp8-CjJdvL94.js +114 -0
- package/examples/full/dist/ssr/assets/default-query-compiler-D7xOzCCJ.js +1727 -0
- package/examples/full/dist/ssr/assets/dist-LmmDoNdk.js +6832 -0
- package/examples/full/dist/ssr/assets/dist-kFDN1l4Z.js +342 -0
- package/examples/full/dist/ssr/assets/factory-AD6s9SIW.js +2079 -0
- package/examples/full/dist/ssr/assets/jsx-renderer-mMLf5XLN.js +1926 -0
- package/examples/full/dist/ssr/assets/kysely-adapter-BCLenpM8.js +2 -0
- package/examples/full/dist/ssr/assets/kysely-migration-tables-DFfmKhq--BtVr6hRe.js +17 -0
- package/examples/full/dist/ssr/assets/layout-mVA7qP4j.js +44 -0
- package/examples/full/dist/ssr/assets/node-sqlite-dialect-D-wtYAD7.js +162 -0
- package/examples/full/dist/ssr/assets/pages-Do5kR_Ia.js +147 -0
- package/examples/full/dist/ssr/assets/saved-Dr4pP6B5.js +111 -0
- package/examples/full/dist/ssr/assets/session-BvIpX7tr.js +13 -0
- package/examples/full/dist/ssr/assets/sign-in-22pzTnJE.js +115 -0
- package/examples/full/dist/ssr/assets/sign-up-CN4j8Qg1.js +117 -0
- package/examples/full/dist/ssr/assets/sqlite-adapter-DVlms5wO.js +79 -0
- package/examples/full/dist/ssr/index.js +97 -0
- package/examples/full/dist/ssr/wrangler.json +1 -0
- package/package.json +62 -6
- package/index.js +0 -1
package/dist/vite.mjs
ADDED
|
@@ -0,0 +1,729 @@
|
|
|
1
|
+
import { d as VIRTUAL_ASSETS, f as VIRTUAL_CLIENT, g as VIRTUAL_SSR_HOOKS, h as VIRTUAL_MANIFEST, m as VIRTUAL_COMPONENTS, p as VIRTUAL_CLIENT_PAGES, s as PAGE_EXTS, u as SHELL_HEADER } from "./constants-BVT2bJEd.mjs";
|
|
2
|
+
import { c as usesDefinePage, o as readPageDefinition } from "./definePage-Ba4r-TFh.mjs";
|
|
3
|
+
import { a as pathDepth, c as SERVER_FN_KIND, f as usesDefineServerFn, i as pathCovers, n as compareRoutes, o as urlToHtmlFile, p as loadMergedConfig, r as compileFilePath, s as DEFINE_SERVER_FN_CALL, t as applyParams$1 } from "./compile-Lxl_tdxL.mjs";
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
8
|
+
//#region src/vino/prerender.ts
|
|
9
|
+
async function collectPrerenderUrls(pages) {
|
|
10
|
+
const urls = [];
|
|
11
|
+
for (const page of pages) {
|
|
12
|
+
const pageMod = await page.loadPage();
|
|
13
|
+
const config = loadMergedConfig(page, pageMod);
|
|
14
|
+
const ssgParams = config.ssgParams;
|
|
15
|
+
if (config.prerender === false) continue;
|
|
16
|
+
if (!page.isStatic) {
|
|
17
|
+
if (!ssgParams) continue;
|
|
18
|
+
const list = await ssgParams();
|
|
19
|
+
for (const params of list) urls.push(applyParams$1(page.path, params));
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
urls.push(page.path === "" ? "/" : page.path);
|
|
23
|
+
}
|
|
24
|
+
return [...new Set(urls)];
|
|
25
|
+
}
|
|
26
|
+
async function prerender(options) {
|
|
27
|
+
const globalMode = options.mode ?? "partial";
|
|
28
|
+
if (globalMode === false && !options.urls?.length) return { files: [] };
|
|
29
|
+
const urls = options.urls ?? await collectPrerenderUrls(options.pages);
|
|
30
|
+
const files = [];
|
|
31
|
+
for (const url of urls) {
|
|
32
|
+
const init = (options.urlModes?.[url] ?? (globalMode === false ? "full" : globalMode)) === "partial" ? { headers: { [SHELL_HEADER]: "1" } } : void 0;
|
|
33
|
+
const res = await options.app.request(url, init);
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
console.warn(`[vino] skip prerender ${url} (${res.status})`);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const html = await res.text();
|
|
39
|
+
const rel = urlToHtmlFile(url);
|
|
40
|
+
const dest = join(options.outDir, rel);
|
|
41
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
42
|
+
await writeFile(dest, html);
|
|
43
|
+
files.push(rel);
|
|
44
|
+
}
|
|
45
|
+
return { files };
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/vite/files.ts
|
|
49
|
+
function stripKnownExt(fileName) {
|
|
50
|
+
for (const ext of PAGE_EXTS) if (fileName.endsWith(ext)) return fileName.slice(0, -ext.length);
|
|
51
|
+
return fileName;
|
|
52
|
+
}
|
|
53
|
+
function isPageExt(fileName) {
|
|
54
|
+
if (fileName.endsWith(".d.ts")) return false;
|
|
55
|
+
return PAGE_EXTS.some((ext) => fileName.endsWith(ext));
|
|
56
|
+
}
|
|
57
|
+
/** Colocated server modules (`[slug].server.ts`) — not filesystem routes. */
|
|
58
|
+
function isServerModuleFile(filePath) {
|
|
59
|
+
const base = filePath.split(/[/\\]/).at(-1) ?? filePath;
|
|
60
|
+
return /\.server\.(tsx|ts|jsx|js|mjs)$/.test(base);
|
|
61
|
+
}
|
|
62
|
+
function isIgnoredPageFile(fileName) {
|
|
63
|
+
const base = fileName.split("/").at(-1) ?? fileName;
|
|
64
|
+
if (base.startsWith(".")) return true;
|
|
65
|
+
if (base.endsWith(".d.ts")) return true;
|
|
66
|
+
if (isServerModuleFile(base)) return true;
|
|
67
|
+
const name = stripKnownExt(base);
|
|
68
|
+
if (name.startsWith("_") || name.startsWith("+")) return true;
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
function isNamedComponentFile(filePath) {
|
|
72
|
+
return /\.component\.(tsx|ts|jsx|js|mjs)$/.test(filePath);
|
|
73
|
+
}
|
|
74
|
+
function isHydratableComponentFile(filePath, componentsDir) {
|
|
75
|
+
const posix = filePath.replaceAll("\\", "/");
|
|
76
|
+
const dir = componentsDir.replaceAll("\\", "/").replace(/\/$/, "");
|
|
77
|
+
if (posix.includes(`/${dir}/`) || posix.startsWith(`${dir}/`) || posix.includes(`${dir}/`)) {
|
|
78
|
+
const after = posix.split(`/${dir}/`).at(-1) ?? posix;
|
|
79
|
+
if (after && isPageExt(after) && !isIgnoredPageFile(after)) return true;
|
|
80
|
+
}
|
|
81
|
+
if (isNamedComponentFile(posix)) return true;
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/vite/crawl.ts
|
|
86
|
+
function toPosix$1(p) {
|
|
87
|
+
return p.replaceAll("\\", "/");
|
|
88
|
+
}
|
|
89
|
+
async function walkFiles(dir) {
|
|
90
|
+
const out = [];
|
|
91
|
+
let entries;
|
|
92
|
+
try {
|
|
93
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
94
|
+
} catch {
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
for (const entry of entries) {
|
|
98
|
+
if (entry.name.startsWith(".")) continue;
|
|
99
|
+
const full = join(dir, entry.name);
|
|
100
|
+
if (entry.isDirectory()) {
|
|
101
|
+
if (entry.name === "node_modules") continue;
|
|
102
|
+
out.push(...await walkFiles(full));
|
|
103
|
+
} else out.push(full);
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
async function crawlWrappers(dirAbs) {
|
|
108
|
+
const files = await walkFiles(dirAbs);
|
|
109
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
110
|
+
for (const file of files) {
|
|
111
|
+
const rel = toPosix$1(relative(dirAbs, file));
|
|
112
|
+
const base = rel.split("/").at(-1) ?? rel;
|
|
113
|
+
if (!isPageExt(base) || isIgnoredPageFile(base)) continue;
|
|
114
|
+
const compiled = compileFilePath(rel);
|
|
115
|
+
byPath.set(compiled.path, file);
|
|
116
|
+
}
|
|
117
|
+
return [...byPath.entries()].map(([path, file]) => ({
|
|
118
|
+
path,
|
|
119
|
+
file
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
function wrappersForPath(wrappers, pagePath) {
|
|
123
|
+
return wrappers.filter((w) => pathCovers(w.path, pagePath)).sort((a, b) => pathDepth(a.path) - pathDepth(b.path) || a.path.localeCompare(b.path)).map((w) => w.file);
|
|
124
|
+
}
|
|
125
|
+
async function crawlPages(options) {
|
|
126
|
+
const pagesAbs = join(options.root, options.pagesDir);
|
|
127
|
+
const componentsAbs = join(options.root, options.componentsDir);
|
|
128
|
+
const layoutsAbs = join(options.root, options.layoutsDir);
|
|
129
|
+
const files = await walkFiles(pagesAbs);
|
|
130
|
+
const compiledPages = [];
|
|
131
|
+
for (const file of files) {
|
|
132
|
+
const rel = toPosix$1(relative(pagesAbs, file));
|
|
133
|
+
const base = rel.split("/").at(-1) ?? rel;
|
|
134
|
+
if (!isPageExt(base)) continue;
|
|
135
|
+
if (isNamedComponentFile(rel) || isIgnoredPageFile(base)) continue;
|
|
136
|
+
compiledPages.push({
|
|
137
|
+
file,
|
|
138
|
+
rel,
|
|
139
|
+
compiled: compileFilePath(rel)
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
const layouts = await crawlWrappers(layoutsAbs);
|
|
143
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
144
|
+
for (const item of compiledPages) byPath.set(item.compiled.path, item);
|
|
145
|
+
const pages = [];
|
|
146
|
+
for (const [urlPath, item] of byPath) {
|
|
147
|
+
const compiled = item.compiled;
|
|
148
|
+
const pageFile = item.file;
|
|
149
|
+
const isClientPage = usesDefinePage(await readFile(pageFile, "utf8"));
|
|
150
|
+
pages.push({
|
|
151
|
+
...compiled,
|
|
152
|
+
path: urlPath,
|
|
153
|
+
isClientPage,
|
|
154
|
+
id: urlPath,
|
|
155
|
+
pageFile,
|
|
156
|
+
layouts: wrappersForPath(layouts, urlPath)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
pages.sort(compareRoutes);
|
|
160
|
+
const componentFiles = [...await walkFiles(componentsAbs), ...(await walkFiles(join(options.root, "src"))).filter((f) => isNamedComponentFile(toPosix$1(f)))];
|
|
161
|
+
return {
|
|
162
|
+
pages,
|
|
163
|
+
components: [...new Set(componentFiles)].filter((file) => {
|
|
164
|
+
const rel = toPosix$1(relative(options.root, file));
|
|
165
|
+
const base = rel.split("/").at(-1) ?? rel;
|
|
166
|
+
return isPageExt(base) && !isIgnoredPageFile(base);
|
|
167
|
+
}).sort()
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function componentId(absFile, root) {
|
|
171
|
+
return `/${toPosix$1(relative(root, absFile))}`;
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/vite/match.ts
|
|
175
|
+
function isSourceDirFile(id, dir) {
|
|
176
|
+
const file = id.split("?")[0].replaceAll("\\", "/");
|
|
177
|
+
if (file.includes("/node_modules/")) return false;
|
|
178
|
+
const prefix = dir.replaceAll("\\", "/").replace(/\/$/, "");
|
|
179
|
+
return file.includes(`/${prefix}/`) || file.startsWith(`${prefix}/`);
|
|
180
|
+
}
|
|
181
|
+
function isHydratableComponentId(id, componentsDir) {
|
|
182
|
+
const file = id.split("?")[0].replaceAll("\\", "/");
|
|
183
|
+
if (file.includes("/node_modules/")) return false;
|
|
184
|
+
return isHydratableComponentFile(file, componentsDir);
|
|
185
|
+
}
|
|
186
|
+
function isPagesDirFile(id, pagesDir) {
|
|
187
|
+
return isSourceDirFile(id, pagesDir);
|
|
188
|
+
}
|
|
189
|
+
function isLayoutsDirFile(id, layoutsDir) {
|
|
190
|
+
return isSourceDirFile(id, layoutsDir);
|
|
191
|
+
}
|
|
192
|
+
function isClientPageModule(id, code, pagesDir) {
|
|
193
|
+
return isPagesDirFile(id, pagesDir) && usesDefinePage(code);
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/vite/hmr.ts
|
|
197
|
+
const VINO_HMR_EVENT = "vino:hmr";
|
|
198
|
+
function hmrAcceptSnippet(kind, id) {
|
|
199
|
+
return `
|
|
200
|
+
if (import.meta.hot) {
|
|
201
|
+
import.meta.hot.accept((mod) => {
|
|
202
|
+
globalThis.__VINO_HMR__?.({ kind: ${JSON.stringify(kind)}, id: ${JSON.stringify(id)}, mod })
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
`;
|
|
206
|
+
}
|
|
207
|
+
function hmrRegistrySnippet(exportName) {
|
|
208
|
+
return `
|
|
209
|
+
if (import.meta.hot) {
|
|
210
|
+
import.meta.hot.accept((mod) => {
|
|
211
|
+
globalThis.__VINO_HMR__?.({ kind: "registry", ${exportName}: mod?.${exportName} })
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
`;
|
|
215
|
+
}
|
|
216
|
+
function classifyHmrFile(file, options) {
|
|
217
|
+
const posix = file.split("?")[0].replaceAll("\\", "/");
|
|
218
|
+
if (posix.includes("/node_modules/")) return;
|
|
219
|
+
if (!isPageExt(posix.split("/").at(-1) ?? posix) && !isServerModuleFile(posix)) return;
|
|
220
|
+
if (isHydratableComponentFile(posix, options.componentsDir)) return "component";
|
|
221
|
+
if (isLayoutsDirFile(posix, options.layoutsDir)) return "layout";
|
|
222
|
+
if (!isPagesDirFile(posix, options.pagesDir)) return;
|
|
223
|
+
if (isServerModuleFile(posix)) return "ssr";
|
|
224
|
+
if (new Set([...options.clientPageFiles ?? []].map((entry) => entry.replaceAll("\\", "/"))).has(posix)) return "client-page";
|
|
225
|
+
return "ssr";
|
|
226
|
+
}
|
|
227
|
+
function clientPageFlagChanged(file, tree, code) {
|
|
228
|
+
const posix = file.replaceAll("\\", "/");
|
|
229
|
+
const page = tree?.pages.find((entry) => entry.pageFile.replaceAll("\\", "/") === posix);
|
|
230
|
+
if (!page) return false;
|
|
231
|
+
return usesDefinePage(code) !== page.isClientPage;
|
|
232
|
+
}
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/vite/server-fn.ts
|
|
235
|
+
const CLIENT_STUB_ERROR = "[vino] server function cannot run on the client";
|
|
236
|
+
function listModuleExports(code) {
|
|
237
|
+
const named = /* @__PURE__ */ new Set();
|
|
238
|
+
let hasDefault = /(?:^|[\n\r;])\s*export\s+default\b/.test(code);
|
|
239
|
+
for (const m of code.matchAll(/\bexport\s+(?:async\s+)?(?:function|class)\s+([A-Za-z_$][\w$]*)/g)) named.add(m[1]);
|
|
240
|
+
for (const m of code.matchAll(/\bexport\s+(?:const|let|var)\s+([A-Za-z_$][\w$]*)/g)) named.add(m[1]);
|
|
241
|
+
for (const m of code.matchAll(/\bexport\s*\{([^}]+)\}/g)) for (const part of m[1].split(",")) {
|
|
242
|
+
const bits = part.trim();
|
|
243
|
+
if (!bits) continue;
|
|
244
|
+
const asMatch = /\bas\s+([A-Za-z_$][\w$]*)$/.exec(bits);
|
|
245
|
+
const name = asMatch ? asMatch[1] : bits.split(/\s+/)[0];
|
|
246
|
+
if (name === "default") hasDefault = true;
|
|
247
|
+
else if (name) named.add(name);
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
hasDefault,
|
|
251
|
+
named: [...named]
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function stubFn(id) {
|
|
255
|
+
return `Object.assign(function(){throw new Error(${JSON.stringify(CLIENT_STUB_ERROR)})},{kind:${JSON.stringify(SERVER_FN_KIND)},id:${JSON.stringify(id)}})`;
|
|
256
|
+
}
|
|
257
|
+
/** Replace a `*.server.*` module with client stubs of its exports (implementation stays on the server). */
|
|
258
|
+
function stubServerModule(code, fileId) {
|
|
259
|
+
const { hasDefault, named } = listModuleExports(code);
|
|
260
|
+
const lines = [];
|
|
261
|
+
for (const name of named) lines.push(`export const ${name} = ${stubFn(`${fileId}#${name}`)}`);
|
|
262
|
+
if (hasDefault || named.length === 0) lines.push(`export default ${stubFn(`${fileId}#default`)}`);
|
|
263
|
+
return `${lines.join("\n")}\n`;
|
|
264
|
+
}
|
|
265
|
+
function skipQuoted(code, start) {
|
|
266
|
+
const quote = code[start];
|
|
267
|
+
let escaped = false;
|
|
268
|
+
for (let i = start + 1; i < code.length; i++) {
|
|
269
|
+
const ch = code[i];
|
|
270
|
+
if (!escaped && ch === quote) return i + 1;
|
|
271
|
+
escaped = !escaped && ch === "\\";
|
|
272
|
+
}
|
|
273
|
+
return code.length;
|
|
274
|
+
}
|
|
275
|
+
function findMatchingParen(code, openIndex) {
|
|
276
|
+
let depth = 0;
|
|
277
|
+
for (let i = openIndex; i < code.length; i++) {
|
|
278
|
+
const ch = code[i];
|
|
279
|
+
const next = code[i + 1];
|
|
280
|
+
if (ch === "'" || ch === "\"" || ch === "`") {
|
|
281
|
+
i = skipQuoted(code, i) - 1;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (ch === "/" && next === "/") {
|
|
285
|
+
const nl = code.indexOf("\n", i);
|
|
286
|
+
if (nl < 0) return -1;
|
|
287
|
+
i = nl;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (ch === "/" && next === "*") {
|
|
291
|
+
const end = code.indexOf("*/", i + 2);
|
|
292
|
+
if (end < 0) return -1;
|
|
293
|
+
i = end + 1;
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (ch === "(") depth++;
|
|
297
|
+
else if (ch === ")") {
|
|
298
|
+
depth--;
|
|
299
|
+
if (depth === 0) return i;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return -1;
|
|
303
|
+
}
|
|
304
|
+
/** True for the vino runtime that *defines* `defineServerFn`. */
|
|
305
|
+
function isDefineServerFnImplementation(code) {
|
|
306
|
+
return /(?:^|[^\w$])function\s+defineServerFn\s*\(/.test(code);
|
|
307
|
+
}
|
|
308
|
+
/** Skip transforming this package's dist (and any `defineServerFn` implementation). */
|
|
309
|
+
function skipServerFnTransform(file, code = "") {
|
|
310
|
+
const normalized = file.replaceAll("\\", "/");
|
|
311
|
+
if (normalized.includes("/node_modules/")) return true;
|
|
312
|
+
if (normalized.includes("/vinojs/dist/")) return true;
|
|
313
|
+
if (/\/dist\/(?:vinojs|client|vite|component-wrap|compile-[^/]+)\.m?js$/.test(normalized)) return true;
|
|
314
|
+
return isDefineServerFnImplementation(code);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Drop `defineServerFn` implementations from client source so handlers are not bundled.
|
|
318
|
+
* The wrapper stays; later this is where an RPC stub id can be injected.
|
|
319
|
+
*/
|
|
320
|
+
function stripServerFnHandlers(code, fileId = "") {
|
|
321
|
+
if (!usesDefineServerFn(code) || isDefineServerFnImplementation(code)) return code;
|
|
322
|
+
let out = "";
|
|
323
|
+
let last = 0;
|
|
324
|
+
DEFINE_SERVER_FN_CALL.lastIndex = 0;
|
|
325
|
+
let match;
|
|
326
|
+
while (match = DEFINE_SERVER_FN_CALL.exec(code)) {
|
|
327
|
+
const open = match.index + match[0].length - 1;
|
|
328
|
+
const close = findMatchingParen(code, open);
|
|
329
|
+
if (close < 0) break;
|
|
330
|
+
out += code.slice(last, open + 1);
|
|
331
|
+
const id = fileId ? JSON.stringify(`${fileId}#fn`) : void 0;
|
|
332
|
+
const stub = id ? `Object.assign(function(){throw new Error(${JSON.stringify(CLIENT_STUB_ERROR)})},{kind:${JSON.stringify(SERVER_FN_KIND)},id:${id}})` : `function(){throw new Error(${JSON.stringify(CLIENT_STUB_ERROR)})}`;
|
|
333
|
+
out += stub;
|
|
334
|
+
last = close;
|
|
335
|
+
DEFINE_SERVER_FN_CALL.lastIndex = close;
|
|
336
|
+
}
|
|
337
|
+
out += code.slice(last);
|
|
338
|
+
return out;
|
|
339
|
+
}
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region src/vite/plugin.ts
|
|
342
|
+
const RESOLVED = {
|
|
343
|
+
manifest: `\0${VIRTUAL_MANIFEST}`,
|
|
344
|
+
components: `\0${VIRTUAL_COMPONENTS}`,
|
|
345
|
+
assets: `\0${VIRTUAL_ASSETS}`,
|
|
346
|
+
client: `\0${VIRTUAL_CLIENT}`,
|
|
347
|
+
clientPages: `\0${VIRTUAL_CLIENT_PAGES}`,
|
|
348
|
+
ssrHooks: `\0${VIRTUAL_SSR_HOOKS}`
|
|
349
|
+
};
|
|
350
|
+
const WRAP = "?vino-wrap";
|
|
351
|
+
const ORIG = "?vino-orig";
|
|
352
|
+
function applyParams(path, params) {
|
|
353
|
+
let url = path;
|
|
354
|
+
for (const [key, value] of Object.entries(params)) url = url.replace(`:${key}`, value);
|
|
355
|
+
if (!url.startsWith("/")) url = `/${url}`;
|
|
356
|
+
return url;
|
|
357
|
+
}
|
|
358
|
+
function resolveOptions(options = {}) {
|
|
359
|
+
return {
|
|
360
|
+
pagesDir: options.pagesDir ?? "src/pages",
|
|
361
|
+
layoutsDir: options.layoutsDir ?? "src/layout",
|
|
362
|
+
componentsDir: options.componentsDir ?? "src/components",
|
|
363
|
+
entry: options.entry ?? "src/server.ts",
|
|
364
|
+
prerender: options.prerender ?? "partial",
|
|
365
|
+
clientRouting: options.clientRouting ?? true,
|
|
366
|
+
client: options.client
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
function toPosix(p) {
|
|
370
|
+
return p.replaceAll("\\", "/");
|
|
371
|
+
}
|
|
372
|
+
function importPath(abs) {
|
|
373
|
+
return JSON.stringify(toPosix(abs));
|
|
374
|
+
}
|
|
375
|
+
function generateManifest(tree, defaults) {
|
|
376
|
+
const baked = JSON.stringify({
|
|
377
|
+
clientRouting: defaults.clientRouting === true,
|
|
378
|
+
prerender: defaults.prerender
|
|
379
|
+
});
|
|
380
|
+
return `
|
|
381
|
+
export const manifest = {
|
|
382
|
+
defaults: ${baked},
|
|
383
|
+
pages: [${tree.pages.map((page) => {
|
|
384
|
+
return `{
|
|
385
|
+
id: ${JSON.stringify(page.id)},
|
|
386
|
+
path: ${JSON.stringify(page.path)},
|
|
387
|
+
pattern: ${JSON.stringify(page.pattern)},
|
|
388
|
+
isClientPage: ${page.isClientPage},
|
|
389
|
+
isStatic: ${page.isStatic},
|
|
390
|
+
isCatchAll: ${page.isCatchAll},
|
|
391
|
+
paramNames: ${JSON.stringify(page.paramNames)},
|
|
392
|
+
config: ${baked},
|
|
393
|
+
loadPage: () => import(${importPath(page.pageFile)}),
|
|
394
|
+
${page.isClientPage ? `loadClientPage: () => import(${importPath(page.pageFile)}),` : ""}
|
|
395
|
+
loadLayouts: [${page.layouts.map((f) => `() => import(${importPath(f)})`).join(", ")}],
|
|
396
|
+
}`;
|
|
397
|
+
}).join(",\n")}],
|
|
398
|
+
}
|
|
399
|
+
`;
|
|
400
|
+
}
|
|
401
|
+
function generateComponents(tree, root) {
|
|
402
|
+
return `export const components = {\n${tree.components.map((file) => `${JSON.stringify(componentId(file, root))}: () => import(${importPath(file)})`).join(",\n")}\n}\n`;
|
|
403
|
+
}
|
|
404
|
+
function generateClientPages(tree) {
|
|
405
|
+
return `export const clientPages = {\n${tree.pages.filter((p) => p.isClientPage).map((p) => `${JSON.stringify(p.path)}: () => import(${importPath(p.pageFile)})`).join(",\n")}\n}\n`;
|
|
406
|
+
}
|
|
407
|
+
function rewriteJsxToDom(code) {
|
|
408
|
+
return code.replaceAll("hono/jsx/jsx-runtime", "hono/jsx/dom/jsx-runtime").replaceAll("hono/jsx/jsx-dev-runtime", "hono/jsx/dom/jsx-dev-runtime").replaceAll(/from\s*(['"])hono\/jsx\1/g, "from $1hono/jsx/dom$1");
|
|
409
|
+
}
|
|
410
|
+
let cachedTree;
|
|
411
|
+
let cachedRoot;
|
|
412
|
+
async function treeFor(root, resolved) {
|
|
413
|
+
if (cachedTree && cachedRoot === root) return cachedTree;
|
|
414
|
+
cachedTree = await crawlPages({
|
|
415
|
+
root,
|
|
416
|
+
pagesDir: resolved.pagesDir,
|
|
417
|
+
componentsDir: resolved.componentsDir,
|
|
418
|
+
layoutsDir: resolved.layoutsDir
|
|
419
|
+
});
|
|
420
|
+
cachedRoot = root;
|
|
421
|
+
return cachedTree;
|
|
422
|
+
}
|
|
423
|
+
function invalidateTree() {
|
|
424
|
+
cachedTree = void 0;
|
|
425
|
+
}
|
|
426
|
+
function inWatchedDirs(file, resolved) {
|
|
427
|
+
const posix = toPosix(file);
|
|
428
|
+
return [
|
|
429
|
+
resolved.pagesDir,
|
|
430
|
+
resolved.layoutsDir,
|
|
431
|
+
resolved.componentsDir
|
|
432
|
+
].some((dir) => posix.includes(toPosix(dir)));
|
|
433
|
+
}
|
|
434
|
+
function reloadRouteVirtuals(server) {
|
|
435
|
+
for (const id of [
|
|
436
|
+
RESOLVED.manifest,
|
|
437
|
+
RESOLVED.components,
|
|
438
|
+
RESOLVED.clientPages
|
|
439
|
+
]) {
|
|
440
|
+
const mod = server.moduleGraph.getModuleById(id);
|
|
441
|
+
if (mod) server.reloadModule(mod);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function watchPages(server, resolved) {
|
|
445
|
+
const dirs = [
|
|
446
|
+
resolved.pagesDir,
|
|
447
|
+
resolved.layoutsDir,
|
|
448
|
+
resolved.componentsDir
|
|
449
|
+
];
|
|
450
|
+
for (const dir of dirs) server.watcher.add(join(server.config.root, dir));
|
|
451
|
+
const onTreeChange = (file) => {
|
|
452
|
+
if (!inWatchedDirs(file, resolved)) return;
|
|
453
|
+
invalidateTree();
|
|
454
|
+
reloadRouteVirtuals(server);
|
|
455
|
+
};
|
|
456
|
+
const onChange = (file) => {
|
|
457
|
+
if (!inWatchedDirs(file, resolved)) return;
|
|
458
|
+
try {
|
|
459
|
+
const code = readFileSync(file, "utf8");
|
|
460
|
+
if (!clientPageFlagChanged(file, cachedTree, code)) return;
|
|
461
|
+
} catch {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
invalidateTree();
|
|
465
|
+
reloadRouteVirtuals(server);
|
|
466
|
+
};
|
|
467
|
+
server.watcher.on("add", onTreeChange);
|
|
468
|
+
server.watcher.on("unlink", onTreeChange);
|
|
469
|
+
server.watcher.on("change", onChange);
|
|
470
|
+
}
|
|
471
|
+
function notifyBrowserHmr(server, kind) {
|
|
472
|
+
const client = server.environments.client;
|
|
473
|
+
setTimeout(() => {
|
|
474
|
+
client?.hot.send({
|
|
475
|
+
type: "custom",
|
|
476
|
+
event: VINO_HMR_EVENT,
|
|
477
|
+
data: { kind }
|
|
478
|
+
});
|
|
479
|
+
}, 0);
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Vite plugin: filesystem routes, hydratable components, client entry, and SSG.
|
|
483
|
+
*/
|
|
484
|
+
function vino(options = {}) {
|
|
485
|
+
const resolved = resolveOptions(options);
|
|
486
|
+
let config;
|
|
487
|
+
let command = "serve";
|
|
488
|
+
const clientScriptSrc = "/assets/vino-client.js";
|
|
489
|
+
return [
|
|
490
|
+
{
|
|
491
|
+
name: "vino:config",
|
|
492
|
+
config(_cfg, env) {
|
|
493
|
+
command = env.command;
|
|
494
|
+
return {
|
|
495
|
+
resolve: { dedupe: ["hono"] },
|
|
496
|
+
ssr: { noExternal: ["vinojs", "hono"] },
|
|
497
|
+
optimizeDeps: { exclude: ["vinojs", "hono"] }
|
|
498
|
+
};
|
|
499
|
+
},
|
|
500
|
+
configEnvironment(name) {
|
|
501
|
+
if (name === "ssr") return {
|
|
502
|
+
resolve: { noExternal: ["vinojs", "hono"] },
|
|
503
|
+
optimizeDeps: { exclude: ["hono"] }
|
|
504
|
+
};
|
|
505
|
+
if (name === "client") return { build: { rollupOptions: {
|
|
506
|
+
input: { "vino-client": VIRTUAL_CLIENT },
|
|
507
|
+
output: { entryFileNames: (chunk) => {
|
|
508
|
+
if (chunk.name === "vino-client") return "assets/vino-client.js";
|
|
509
|
+
return "assets/[name]-[hash].js";
|
|
510
|
+
} }
|
|
511
|
+
} } };
|
|
512
|
+
},
|
|
513
|
+
configResolved(c) {
|
|
514
|
+
config = c;
|
|
515
|
+
const detected = join(c.root, "src/client.ts");
|
|
516
|
+
if (!resolved.client && existsSync(detected)) resolved.client = detected;
|
|
517
|
+
},
|
|
518
|
+
configureServer(server) {
|
|
519
|
+
watchPages(server, resolved);
|
|
520
|
+
},
|
|
521
|
+
hotUpdate({ file, server }) {
|
|
522
|
+
const kind = classifyHmrFile(file, {
|
|
523
|
+
pagesDir: resolved.pagesDir,
|
|
524
|
+
layoutsDir: resolved.layoutsDir,
|
|
525
|
+
componentsDir: resolved.componentsDir,
|
|
526
|
+
clientPageFiles: cachedTree?.pages.filter((page) => page.isClientPage).map((page) => page.pageFile)
|
|
527
|
+
});
|
|
528
|
+
if (!kind) return;
|
|
529
|
+
if (kind === "component" || kind === "client-page") return;
|
|
530
|
+
if (this.environment.name === "client") {
|
|
531
|
+
if (!server.environments.ssr) notifyBrowserHmr(server, kind);
|
|
532
|
+
return [];
|
|
533
|
+
}
|
|
534
|
+
if (this.environment.name === "ssr") notifyBrowserHmr(server, kind);
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
name: "vino:virtual",
|
|
539
|
+
resolveId(id) {
|
|
540
|
+
if (id === "virtual:vino/manifest") return RESOLVED.manifest;
|
|
541
|
+
if (id === "virtual:vino/components") return RESOLVED.components;
|
|
542
|
+
if (id === "virtual:vino/assets") return RESOLVED.assets;
|
|
543
|
+
if (id === "virtual:vino/client") return RESOLVED.client;
|
|
544
|
+
if (id === "virtual:vino/client-pages") return RESOLVED.clientPages;
|
|
545
|
+
if (id === "virtual:vino/ssr-hooks") return RESOLVED.ssrHooks;
|
|
546
|
+
},
|
|
547
|
+
async load(id) {
|
|
548
|
+
const root = config?.root ?? process.cwd();
|
|
549
|
+
const isDev = command === "serve";
|
|
550
|
+
if (id === RESOLVED.manifest) return generateManifest(await treeFor(root, resolved), {
|
|
551
|
+
clientRouting: resolved.clientRouting,
|
|
552
|
+
prerender: resolved.prerender
|
|
553
|
+
});
|
|
554
|
+
if (id === RESOLVED.components) {
|
|
555
|
+
const code = generateComponents(await treeFor(root, resolved), root);
|
|
556
|
+
return isDev ? `${code}${hmrRegistrySnippet("components")}` : code;
|
|
557
|
+
}
|
|
558
|
+
if (id === RESOLVED.clientPages) {
|
|
559
|
+
const code = generateClientPages(await treeFor(root, resolved));
|
|
560
|
+
return isDev ? `${code}${hmrRegistrySnippet("clientPages")}` : code;
|
|
561
|
+
}
|
|
562
|
+
if (id === RESOLVED.assets) return `export const isDev = ${isDev}\nexport const clientScriptSrc = ${JSON.stringify(isDev ? "/@id/virtual:vino/client" : clientScriptSrc)}\n`;
|
|
563
|
+
if (id === RESOLVED.ssrHooks) return `
|
|
564
|
+
export function useState(initial) {
|
|
565
|
+
const value = typeof initial === 'function' ? initial() : initial
|
|
566
|
+
return [value, () => {}]
|
|
567
|
+
}
|
|
568
|
+
export function useEffect() {}
|
|
569
|
+
export function useLayoutEffect() {}
|
|
570
|
+
export function useInsertionEffect() {}
|
|
571
|
+
export function useCallback(fn) { return fn }
|
|
572
|
+
export function useMemo(fn) { return fn() }
|
|
573
|
+
export function useRef(initial) { return { current: initial } }
|
|
574
|
+
export function useId() { return 'vino-ssr' }
|
|
575
|
+
export function useReducer(reducer, initial) {
|
|
576
|
+
const value = typeof initial === 'function' ? initial() : initial
|
|
577
|
+
return [value, () => {}]
|
|
578
|
+
}
|
|
579
|
+
export * from 'hono/jsx'
|
|
580
|
+
`;
|
|
581
|
+
if (id === RESOLVED.client) {
|
|
582
|
+
const user = resolved.client;
|
|
583
|
+
const userAbs = user ? isAbsolute(user) ? user : join(root, user) : void 0;
|
|
584
|
+
return `${userAbs && existsSync(userAbs) ? `import ${importPath(userAbs)}\n` : ""}import { createClient } from 'vinojs/client'
|
|
585
|
+
const vino = createClient()
|
|
586
|
+
if (import.meta.hot) {
|
|
587
|
+
import.meta.hot.accept()
|
|
588
|
+
import.meta.hot.on(${JSON.stringify(VINO_HMR_EVENT)}, (data) => vino.hmr(data))
|
|
589
|
+
}
|
|
590
|
+
`;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
name: "vino:server-fn",
|
|
596
|
+
enforce: "pre",
|
|
597
|
+
transform(code, id, extra) {
|
|
598
|
+
if (extra?.ssr) return null;
|
|
599
|
+
const file = id.split("?")[0].replaceAll("\\", "/");
|
|
600
|
+
if (skipServerFnTransform(file, code)) return null;
|
|
601
|
+
if (isServerModuleFile(file)) return {
|
|
602
|
+
code: stubServerModule(code, file),
|
|
603
|
+
map: null
|
|
604
|
+
};
|
|
605
|
+
if (!usesDefineServerFn(code)) return null;
|
|
606
|
+
return {
|
|
607
|
+
code: stripServerFnHandlers(code, file),
|
|
608
|
+
map: null
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
name: "vino:components",
|
|
614
|
+
enforce: "pre",
|
|
615
|
+
async resolveId(source, importer, extra) {
|
|
616
|
+
if (source.includes(ORIG)) return source.slice(0, source.indexOf(ORIG));
|
|
617
|
+
if (source.includes(WRAP) || importer?.includes(WRAP) || importer?.includes(ORIG)) return;
|
|
618
|
+
if (!importer || !extra?.ssr) return;
|
|
619
|
+
const next = await this.resolve(source, importer, { skipSelf: true });
|
|
620
|
+
if (!next) return;
|
|
621
|
+
const file = next.id.split("?")[0];
|
|
622
|
+
if (isHydratableComponentId(file, resolved.componentsDir)) return `${file}${WRAP}`;
|
|
623
|
+
},
|
|
624
|
+
load(id) {
|
|
625
|
+
if (!id.includes(WRAP)) return;
|
|
626
|
+
const file = id.split("?")[0];
|
|
627
|
+
const cid = componentId(file, config?.root ?? process.cwd());
|
|
628
|
+
return `
|
|
629
|
+
import Component from ${JSON.stringify(file + ORIG)}
|
|
630
|
+
import { wrapComponent } from 'vinojs/component-wrap'
|
|
631
|
+
export default wrapComponent(Component, ${JSON.stringify(cid)}, 'default')
|
|
632
|
+
`;
|
|
633
|
+
},
|
|
634
|
+
async transform(code, id, extra) {
|
|
635
|
+
const file = id.split("?")[0];
|
|
636
|
+
const hydratable = isHydratableComponentId(file, resolved.componentsDir);
|
|
637
|
+
const clientPage = isClientPageModule(id, code, resolved.pagesDir);
|
|
638
|
+
if (!hydratable && !clientPage) return null;
|
|
639
|
+
if (extra?.ssr) return {
|
|
640
|
+
code: code.replaceAll(/from\s*(['"])hono\/jsx(?:\/dom)?\1/g, `from '${VIRTUAL_SSR_HOOKS}'`),
|
|
641
|
+
map: null
|
|
642
|
+
};
|
|
643
|
+
let next = rewriteJsxToDom(code);
|
|
644
|
+
if (command === "serve") {
|
|
645
|
+
if (hydratable) next += hmrAcceptSnippet("component", componentId(file, config?.root ?? process.cwd()));
|
|
646
|
+
else if (clientPage) {
|
|
647
|
+
const page = (await treeFor(config?.root ?? process.cwd(), resolved)).pages.find((entry) => toPosix(entry.pageFile) === toPosix(file));
|
|
648
|
+
if (page) next += hmrAcceptSnippet("client-page", page.path);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return {
|
|
652
|
+
code: next,
|
|
653
|
+
map: null
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
name: "vino:prerender",
|
|
659
|
+
apply: "build",
|
|
660
|
+
enforce: "post",
|
|
661
|
+
async closeBundle() {
|
|
662
|
+
if (!resolved.prerender) return;
|
|
663
|
+
const envName = this.environment?.name;
|
|
664
|
+
if (envName && envName !== "client") return;
|
|
665
|
+
const root = config.root;
|
|
666
|
+
try {
|
|
667
|
+
const ssrOutDir = config.environments?.ssr?.build?.outDir ? isAbsolute(config.environments.ssr.build.outDir) ? config.environments.ssr.build.outDir : join(root, config.environments.ssr.build.outDir) : join(root, "dist", "ssr");
|
|
668
|
+
const clientOut = config.environments?.client?.build?.outDir ? isAbsolute(config.environments.client.build.outDir) ? config.environments.client.build.outDir : join(root, config.environments.client.build.outDir) : join(root, "dist", "client");
|
|
669
|
+
const workerMain = join(ssrOutDir, "index.js");
|
|
670
|
+
if (!existsSync(workerMain)) {
|
|
671
|
+
console.warn(`[vino] prerender skipped: missing ${workerMain}`);
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
const app = (await import(pathToFileURL(workerMain).href)).default;
|
|
675
|
+
if (typeof app?.request !== "function") {
|
|
676
|
+
console.warn("[vino] prerender skipped: worker has no request()");
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
const tree = await treeFor(root, resolved);
|
|
680
|
+
const viteManifestPath = join(ssrOutDir, ".vite", "manifest.json");
|
|
681
|
+
const viteManifest = existsSync(viteManifestPath) ? JSON.parse(readFileSync(viteManifestPath, "utf8")) : {};
|
|
682
|
+
const loadBuilt = async (absFile) => {
|
|
683
|
+
const rel = toPosix(relative(root, absFile));
|
|
684
|
+
const chunk = viteManifest[rel] ?? viteManifest[`/${rel}`];
|
|
685
|
+
if (!chunk?.file) return void 0;
|
|
686
|
+
return import(pathToFileURL(join(ssrOutDir, chunk.file)).href);
|
|
687
|
+
};
|
|
688
|
+
const urls = [];
|
|
689
|
+
const urlModes = {};
|
|
690
|
+
for (const page of tree.pages) {
|
|
691
|
+
const pageMod = await loadBuilt(page.pageFile);
|
|
692
|
+
const inline = readPageDefinition(pageMod && typeof pageMod === "object" ? pageMod.default : void 0);
|
|
693
|
+
const pagePrerender = inline?.config?.prerender ?? resolved.prerender;
|
|
694
|
+
if (pagePrerender === false) continue;
|
|
695
|
+
const ssgParams = inline?.config?.ssgParams;
|
|
696
|
+
const mode = pagePrerender === "full" ? "full" : "partial";
|
|
697
|
+
if (page.isStatic) {
|
|
698
|
+
const url = page.path;
|
|
699
|
+
urls.push(url);
|
|
700
|
+
urlModes[url] = mode;
|
|
701
|
+
} else if (ssgParams) {
|
|
702
|
+
const list = await ssgParams();
|
|
703
|
+
for (const params of list) {
|
|
704
|
+
const url = applyParams(page.path, params);
|
|
705
|
+
urls.push(url);
|
|
706
|
+
urlModes[url] = mode;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
const result = await prerender({
|
|
711
|
+
app,
|
|
712
|
+
pages: [],
|
|
713
|
+
urls,
|
|
714
|
+
outDir: clientOut,
|
|
715
|
+
mode: resolved.prerender,
|
|
716
|
+
urlModes
|
|
717
|
+
});
|
|
718
|
+
if (result.files.length) console.info(`[vino] prerendered ${result.files.length} page(s) → ${clientOut}`);
|
|
719
|
+
} catch (err) {
|
|
720
|
+
console.warn("[vino] prerender skipped:", err);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
];
|
|
725
|
+
}
|
|
726
|
+
//#endregion
|
|
727
|
+
export { vino };
|
|
728
|
+
|
|
729
|
+
//# sourceMappingURL=vite.mjs.map
|