void-plugin-hono-jsx 0.1.0-alpha.2 → 0.1.0-alpha.4
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/CHANGELOG.md +59 -0
- package/README.md +73 -20
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/dist/browser/client.d.ts +2 -1
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/client.js +76 -22
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/document-head.d.ts +1 -1
- package/dist/browser/document-head.d.ts.map +1 -1
- package/dist/browser/document-head.js +22 -1
- package/dist/browser/document-head.js.map +1 -1
- package/dist/browser/form-view.d.ts +10 -0
- package/dist/browser/form-view.d.ts.map +1 -0
- package/dist/browser/form-view.js +16 -0
- package/dist/browser/form-view.js.map +1 -0
- package/dist/browser/form.d.ts +28 -12
- package/dist/browser/form.d.ts.map +1 -1
- package/dist/browser/form.js +84 -23
- package/dist/browser/form.js.map +1 -1
- package/dist/browser/markdown.d.ts +15 -0
- package/dist/browser/markdown.d.ts.map +1 -0
- package/dist/browser/markdown.js +6 -0
- package/dist/browser/markdown.js.map +1 -0
- package/dist/browser/navigation.d.ts +13 -0
- package/dist/browser/navigation.d.ts.map +1 -0
- package/dist/browser/navigation.js +83 -0
- package/dist/browser/navigation.js.map +1 -0
- package/dist/browser/pages.d.ts +33 -3
- package/dist/browser/pages.d.ts.map +1 -1
- package/dist/browser/pages.js +76 -13
- package/dist/browser/pages.js.map +1 -1
- package/dist/plugins/compatibility.d.ts +12 -1
- package/dist/plugins/compatibility.d.ts.map +1 -1
- package/dist/plugins/compatibility.js +65 -22
- package/dist/plugins/compatibility.js.map +1 -1
- package/dist/plugins/hono-islands.d.ts +1 -1
- package/dist/plugins/hono-islands.d.ts.map +1 -1
- package/dist/plugins/hono-islands.js +156 -24
- package/dist/plugins/hono-islands.js.map +1 -1
- package/dist/plugins/hono-markdown.d.ts +4 -0
- package/dist/plugins/hono-markdown.d.ts.map +1 -0
- package/dist/plugins/hono-markdown.js +91 -0
- package/dist/plugins/hono-markdown.js.map +1 -0
- package/dist/plugins/hono-pages.d.ts +10 -2
- package/dist/plugins/hono-pages.d.ts.map +1 -1
- package/dist/plugins/hono-pages.js +55 -18
- package/dist/plugins/hono-pages.js.map +1 -1
- package/dist/plugins/markdown-api.d.ts +10 -0
- package/dist/plugins/markdown-api.d.ts.map +1 -0
- package/dist/plugins/markdown-api.js +13 -0
- package/dist/plugins/markdown-api.js.map +1 -0
- package/dist/plugins/markdown-compiler.d.ts +43 -0
- package/dist/plugins/markdown-compiler.d.ts.map +1 -0
- package/dist/plugins/markdown-compiler.js +91 -0
- package/dist/plugins/markdown-compiler.js.map +1 -0
- package/dist/plugins/resolve-component.d.ts +3 -0
- package/dist/plugins/resolve-component.d.ts.map +1 -0
- package/dist/plugins/resolve-component.js +15 -0
- package/dist/plugins/resolve-component.js.map +1 -0
- package/dist/plugins/runtime-paths.d.ts +1 -0
- package/dist/plugins/runtime-paths.d.ts.map +1 -1
- package/dist/plugins/runtime-paths.js +2 -0
- package/dist/plugins/runtime-paths.js.map +1 -1
- package/dist/server/form-view.d.ts +10 -0
- package/dist/server/form-view.d.ts.map +1 -0
- package/dist/server/form-view.js +16 -0
- package/dist/server/form-view.js.map +1 -0
- package/dist/server/form.d.ts +28 -12
- package/dist/server/form.d.ts.map +1 -1
- package/dist/server/form.js +84 -23
- package/dist/server/form.js.map +1 -1
- package/dist/server/markdown.d.ts +15 -0
- package/dist/server/markdown.d.ts.map +1 -0
- package/dist/server/markdown.js +6 -0
- package/dist/server/markdown.js.map +1 -0
- package/dist/server/pages.d.ts +33 -3
- package/dist/server/pages.d.ts.map +1 -1
- package/dist/server/pages.js +76 -13
- package/dist/server/pages.js.map +1 -1
- package/package.json +24 -6
- package/src/plugins/compatibility.ts +56 -19
- package/src/plugins/hono-islands.ts +121 -23
- package/src/plugins/hono-markdown.ts +78 -0
- package/src/plugins/hono-pages.ts +54 -17
- package/src/plugins/markdown-api.ts +17 -0
- package/src/plugins/markdown-compiler.ts +77 -0
- package/src/plugins/resolve-component.ts +12 -0
- package/src/plugins/runtime-paths.ts +2 -0
- package/src/runtime/client.tsx +66 -24
- package/src/runtime/document-head.ts +20 -1
- package/src/runtime/form-view.tsx +23 -0
- package/src/runtime/form.ts +82 -41
- package/src/runtime/markdown.ts +7 -0
- package/src/runtime/navigation.ts +72 -0
- package/src/runtime/pages.tsx +77 -15
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, existsSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { join, relative, dirname } from 'node:path';
|
|
3
|
+
import { normalizePath } from 'vite';
|
|
4
|
+
import { resolvePagesDir } from 'void/pages';
|
|
5
|
+
import { resolveComponent } from './resolve-component.js';
|
|
6
|
+
import { compileMarkdown, extractMarkdown, renderChunks } from './markdown-compiler.js';
|
|
7
|
+
const clientId = 'virtual:void-hono-markdown-client';
|
|
8
|
+
const scriptQuery = '?hono-markdown-script';
|
|
9
|
+
const literal = (value) => `JSON.parse(${JSON.stringify(JSON.stringify(value))})`;
|
|
10
|
+
/** Optional authored Markdown compiler; independent of @void/md private files. */
|
|
11
|
+
export function voidHonoMarkdown() {
|
|
12
|
+
let root = process.cwd();
|
|
13
|
+
let pagesDir = resolvePagesDir(root);
|
|
14
|
+
const scripts = new Map();
|
|
15
|
+
const files = new Map();
|
|
16
|
+
function rescan() {
|
|
17
|
+
scripts.clear();
|
|
18
|
+
files.clear();
|
|
19
|
+
if (!existsSync(pagesDir))
|
|
20
|
+
return;
|
|
21
|
+
for (const entry of readdirSync(pagesDir, { recursive: true, withFileTypes: true })) {
|
|
22
|
+
if (!entry.isFile() || !entry.name.endsWith('.md'))
|
|
23
|
+
continue;
|
|
24
|
+
const file = join(entry.parentPath, entry.name);
|
|
25
|
+
const id = normalizePath(relative(pagesDir, file)).replace(/\.md$/, '').replace(/\.island$/, '').replace(/\/index$/, '').replace(/^index$/, '') || 'index';
|
|
26
|
+
const { clientCode } = extractMarkdown(readFileSync(file, 'utf8'));
|
|
27
|
+
if (clientCode) {
|
|
28
|
+
scripts.set(id, clientCode);
|
|
29
|
+
files.set(id, file);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const api = { adapter: 'hono', clientEntryId: clientId, getClientScripts() { rescan(); return scripts; }, getGraphSource(file) { return extractMarkdown(readFileSync(file, 'utf8')).graphSource; } };
|
|
34
|
+
return {
|
|
35
|
+
// Void's Markdown entry/asset convention is shared with @void/md.
|
|
36
|
+
name: 'void-md', enforce: 'pre', api,
|
|
37
|
+
config() { return { build: { rollupOptions: { input: { 'markdown-client': clientId } } } }; },
|
|
38
|
+
configResolved(config) { if (!config.plugins.some(plugin => plugin.name === 'void-hono:pages'))
|
|
39
|
+
throw new Error('Hono Markdown: configure voidHonoJsx() before voidHonoMarkdown().'); root = realpathSync(config.root); pagesDir = resolvePagesDir(root); rescan(); },
|
|
40
|
+
buildStart() { rescan(); },
|
|
41
|
+
hotUpdate({ file, timestamp }) {
|
|
42
|
+
if (!file.endsWith('.md') || !normalizePath(file).startsWith(normalizePath(pagesDir) + '/'))
|
|
43
|
+
return;
|
|
44
|
+
rescan();
|
|
45
|
+
const entry = this.environment.moduleGraph.getModuleById(`\0${clientId}`);
|
|
46
|
+
if (entry)
|
|
47
|
+
this.environment.moduleGraph.invalidateModule(entry, new Set(), timestamp, true);
|
|
48
|
+
},
|
|
49
|
+
resolveId(id) { if (id === clientId)
|
|
50
|
+
return `\0${id}`; },
|
|
51
|
+
load(id) {
|
|
52
|
+
if (id.endsWith(scriptQuery))
|
|
53
|
+
return extractMarkdown(readFileSync(id.slice(0, -scriptQuery.length), 'utf8')).clientCode || 'export {};';
|
|
54
|
+
if (id !== `\0${clientId}`)
|
|
55
|
+
return;
|
|
56
|
+
rescan();
|
|
57
|
+
if (!files.size)
|
|
58
|
+
return 'export {};';
|
|
59
|
+
return `const scripts = {${[...files].map(([id, file]) => `${JSON.stringify(id)}: () => import(${JSON.stringify(normalizePath(file) + scriptQuery)})`).join(',')}};
|
|
60
|
+
const id = document.getElementById('app')?.getAttribute('data-md-script');
|
|
61
|
+
if (id && scripts[id]) await scripts[id]();`;
|
|
62
|
+
},
|
|
63
|
+
transform: {
|
|
64
|
+
filter: { id: /\.md$/ },
|
|
65
|
+
handler(source, id) {
|
|
66
|
+
const result = compileMarkdown(source);
|
|
67
|
+
const imports = result.imports.map((entry, index) => {
|
|
68
|
+
const target = resolveComponent(entry.specifier, dirname(id), ['.tsx', '.jsx']);
|
|
69
|
+
if (!target || !entry.specifier.startsWith('.'))
|
|
70
|
+
throw new Error(`Hono Markdown: cannot resolve relative TSX/JSX island ${entry.specifier} in ${id}.`);
|
|
71
|
+
return { ...entry, alias: `__island${index}`, islandId: normalizePath(relative(root, realpathSync(target))) };
|
|
72
|
+
});
|
|
73
|
+
const chunks = renderChunks(result.html, new Set(imports.map(entry => entry.importName)));
|
|
74
|
+
const children = chunks.map(chunk => {
|
|
75
|
+
if ('html' in chunk)
|
|
76
|
+
return `raw(${JSON.stringify(chunk.html)})`;
|
|
77
|
+
const entry = imports.find(entry => entry.importName === chunk.name);
|
|
78
|
+
const props = literal(chunk.props);
|
|
79
|
+
return `jsx('div', { 'data-island': ${JSON.stringify(entry.islandId)}, 'data-hydrate': ${JSON.stringify(entry.hydrate)}, 'data-props': JSON.stringify(${props}), children: jsx(${entry.alias}, ${props}) })`;
|
|
80
|
+
});
|
|
81
|
+
return { code: `import { jsx, Fragment } from 'hono/jsx/jsx-runtime';
|
|
82
|
+
import { raw } from 'hono/html';
|
|
83
|
+
${imports.map(entry => `import ${entry.alias} from ${JSON.stringify(entry.specifier)};`).join('\n')}
|
|
84
|
+
export const frontmatter = ${literal(result.frontmatter)};
|
|
85
|
+
export const headings = ${literal(result.headings)};
|
|
86
|
+
export default function MarkdownPage() { return jsx(Fragment, { children: [${children.join(',')}] }); }`, map: null };
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=hono-markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hono-markdown.js","sourceRoot":"","sources":["../../src/plugins/hono-markdown.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, readdirSync, existsSync, realpathSync } from 'node:fs';\nimport { join, relative, dirname } from 'node:path';\nimport { normalizePath, type Plugin } from 'vite';\nimport { resolvePagesDir } from 'void/pages';\nimport { resolveComponent } from './resolve-component.ts';\nimport { compileMarkdown, extractMarkdown, renderChunks } from './markdown-compiler.ts';\nimport type { HonoMarkdownApi } from './markdown-api.ts';\n\nconst clientId = 'virtual:void-hono-markdown-client';\nconst scriptQuery = '?hono-markdown-script';\nconst literal = (value: unknown) => `JSON.parse(${JSON.stringify(JSON.stringify(value))})`;\n\n/** Optional authored Markdown compiler; independent of @void/md private files. */\nexport function voidHonoMarkdown(): Plugin {\n let root = process.cwd();\n let pagesDir = resolvePagesDir(root);\n const scripts = new Map<string, string>();\n const files = new Map<string, string>();\n function rescan() {\n scripts.clear(); files.clear();\n if (!existsSync(pagesDir)) return;\n for (const entry of readdirSync(pagesDir, { recursive: true, withFileTypes: true })) {\n if (!entry.isFile() || !entry.name.endsWith('.md')) continue;\n const file = join(entry.parentPath, entry.name);\n const id = normalizePath(relative(pagesDir, file)).replace(/\\.md$/, '').replace(/\\.island$/, '').replace(/\\/index$/, '').replace(/^index$/, '') || 'index';\n const { clientCode } = extractMarkdown(readFileSync(file, 'utf8'));\n if (clientCode) { scripts.set(id, clientCode); files.set(id, file); }\n }\n }\n const api: HonoMarkdownApi = { adapter: 'hono', clientEntryId: clientId, getClientScripts() { rescan(); return scripts; }, getGraphSource(file) { return extractMarkdown(readFileSync(file, 'utf8')).graphSource; } };\n return {\n // Void's Markdown entry/asset convention is shared with @void/md.\n name: 'void-md', enforce: 'pre', api,\n config() { return { build: { rollupOptions: { input: { 'markdown-client': clientId } } } }; },\n configResolved(config) { if (!config.plugins.some(plugin => plugin.name === 'void-hono:pages')) throw new Error('Hono Markdown: configure voidHonoJsx() before voidHonoMarkdown().'); root = realpathSync(config.root); pagesDir = resolvePagesDir(root); rescan(); },\n buildStart() { rescan(); },\n hotUpdate({ file, timestamp }) {\n if (!file.endsWith('.md') || !normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;\n rescan();\n const entry = this.environment.moduleGraph.getModuleById(`\\0${clientId}`);\n if (entry) this.environment.moduleGraph.invalidateModule(entry, new Set(), timestamp, true);\n },\n resolveId(id) { if (id === clientId) return `\\0${id}`; },\n load(id) {\n if (id.endsWith(scriptQuery)) return extractMarkdown(readFileSync(id.slice(0, -scriptQuery.length), 'utf8')).clientCode || 'export {};';\n if (id !== `\\0${clientId}`) return;\n rescan();\n if (!files.size) return 'export {};';\n return `const scripts = {${[...files].map(([id, file]) => `${JSON.stringify(id)}: () => import(${JSON.stringify(normalizePath(file) + scriptQuery)})`).join(',')}};\nconst id = document.getElementById('app')?.getAttribute('data-md-script');\nif (id && scripts[id]) await scripts[id]();`;\n },\n transform: {\n filter: { id: /\\.md$/ },\n handler(source, id) {\n const result = compileMarkdown(source);\n const imports = result.imports.map((entry, index) => {\n const target = resolveComponent(entry.specifier, dirname(id), ['.tsx', '.jsx']);\n if (!target || !entry.specifier.startsWith('.')) throw new Error(`Hono Markdown: cannot resolve relative TSX/JSX island ${entry.specifier} in ${id}.`);\n return { ...entry, alias: `__island${index}`, islandId: normalizePath(relative(root, realpathSync(target))) };\n });\n const chunks = renderChunks(result.html, new Set(imports.map(entry => entry.importName)));\n const children = chunks.map(chunk => {\n if ('html' in chunk) return `raw(${JSON.stringify(chunk.html)})`;\n const entry = imports.find(entry => entry.importName === chunk.name)!;\n const props = literal(chunk.props);\n return `jsx('div', { 'data-island': ${JSON.stringify(entry.islandId)}, 'data-hydrate': ${JSON.stringify(entry.hydrate)}, 'data-props': JSON.stringify(${props}), children: jsx(${entry.alias}, ${props}) })`;\n });\n return { code: `import { jsx, Fragment } from 'hono/jsx/jsx-runtime';\nimport { raw } from 'hono/html';\n${imports.map(entry => `import ${entry.alias} from ${JSON.stringify(entry.specifier)};`).join('\\n')}\nexport const frontmatter = ${literal(result.frontmatter)};\nexport const headings = ${literal(result.headings)};\nexport default function MarkdownPage() { return jsx(Fragment, { children: [${children.join(',')}] }); }`, map: null };\n },\n },\n };\n}\n"]}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
|
-
|
|
3
|
-
export
|
|
2
|
+
import { type CacheForInput } from 'void/pages-prefetch';
|
|
3
|
+
export type HonoJsxOptions = {
|
|
4
|
+
viewTransitions?: boolean;
|
|
5
|
+
prefetch?: {
|
|
6
|
+
hoverDelay?: number;
|
|
7
|
+
cacheFor?: CacheForInput;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
/** Experimental Pages contract verified against Void 0.26.1 and 0.27.0. */
|
|
11
|
+
export declare function voidHonoJsx(options?: HonoJsxOptions): Plugin[];
|
|
4
12
|
//# sourceMappingURL=hono-pages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono-pages.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-pages.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hono-pages.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-pages.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAexE,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC;CAC9D,CAAC;AAcF,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,EAAE,CA2IlE"}
|
|
@@ -1,28 +1,54 @@
|
|
|
1
1
|
import { realpathSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
2
3
|
import { normalizePath } from 'vite';
|
|
3
|
-
import { pagesRuntimePath, clientRuntimePath, publicRuntimeModules } from './runtime-paths.js';
|
|
4
|
+
import { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.js';
|
|
4
5
|
import { generateComponentManifest, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages } from 'void/pages';
|
|
6
|
+
import { parseCacheFor } from 'void/pages-prefetch';
|
|
5
7
|
import { honoJsx } from './hono-jsx.js';
|
|
6
8
|
import { honoIslands } from './hono-islands.js';
|
|
9
|
+
import { markdownApi, markdownDiagnostic } from './markdown-api.js';
|
|
7
10
|
import { assertSupportedFrameworks } from './compatibility.js';
|
|
8
11
|
const rendererId = 'virtual:void-pages-renderer';
|
|
9
12
|
const clientId = 'virtual:void-pages-client';
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
function assertComponentFile(file, kind, markdown = false) {
|
|
14
|
+
if (/\.md$/.test(file)) {
|
|
15
|
+
if (markdown && kind === 'page')
|
|
16
|
+
return;
|
|
17
|
+
if (markdown)
|
|
18
|
+
throw new Error('Hono Markdown: layouts must remain TSX/JSX: ' + file);
|
|
19
|
+
throw new Error(`${markdownDiagnostic} ${kind}: ${file}`);
|
|
20
|
+
}
|
|
21
|
+
if (!/\.[jt]sx$/.test(file))
|
|
22
|
+
throw new Error(`Hono Pages: only standard TSX/JSX ${kind}s are supported: ${file}.`);
|
|
23
|
+
}
|
|
24
|
+
function clientOptions(options) {
|
|
25
|
+
const viewTransitions = options.viewTransitions ?? false;
|
|
26
|
+
const prefetchHoverDelay = options.prefetch?.hoverDelay ?? 75;
|
|
27
|
+
if (typeof viewTransitions !== 'boolean')
|
|
28
|
+
throw new Error('Hono Pages: viewTransitions must be a boolean.');
|
|
29
|
+
if (!Number.isFinite(prefetchHoverDelay) || prefetchHoverDelay < 0)
|
|
30
|
+
throw new Error('Hono Pages: prefetch.hoverDelay must be a finite non-negative number.');
|
|
31
|
+
const prefetchDefaultCacheFor = parseCacheFor(options.prefetch?.cacheFor ?? '30s');
|
|
32
|
+
if (![prefetchDefaultCacheFor.stale, prefetchDefaultCacheFor.expires].every(value => Number.isFinite(value) && value >= 0) || prefetchDefaultCacheFor.stale > prefetchDefaultCacheFor.expires) {
|
|
33
|
+
throw new Error('Hono Pages: prefetch.cacheFor must have finite non-negative durations, with stale <= expires.');
|
|
34
|
+
}
|
|
35
|
+
return { viewTransitions, prefetchHoverDelay, prefetchDefaultCacheFor };
|
|
36
|
+
}
|
|
37
|
+
/** Experimental Pages contract verified against Void 0.26.1 and 0.27.0. */
|
|
38
|
+
export function voidHonoJsx(options = {}) {
|
|
39
|
+
const navigationOptions = clientOptions(options);
|
|
12
40
|
const root = process.cwd();
|
|
13
41
|
const pagesDir = resolvePagesDir(root);
|
|
14
42
|
const staticData = resolveStaticPageDataBuildOptions(root);
|
|
15
43
|
let scan;
|
|
44
|
+
let markdown;
|
|
16
45
|
async function rescan() {
|
|
17
46
|
scan = await scanPages(root, { pagesDir });
|
|
18
47
|
for (const layout of [...scan.layouts, ...scan.namedLayouts]) {
|
|
19
|
-
|
|
20
|
-
throw new Error('Hono Pages: only standard TSX/JSX layouts are supported.');
|
|
48
|
+
assertComponentFile(layout.filePath, 'layout');
|
|
21
49
|
}
|
|
22
50
|
for (const page of scan.pages) {
|
|
23
|
-
|
|
24
|
-
throw new Error(`Hono Pages: only standard TSX/JSX pages are supported: ${page.componentPath}.`);
|
|
25
|
-
}
|
|
51
|
+
assertComponentFile(page.componentPath, 'page', Boolean(markdown));
|
|
26
52
|
if (staticData.enabled && page.methods.some((method) => method === 'action' || method === 'actions')) {
|
|
27
53
|
throw new Error(`Hono Pages: actions require a server and cannot be used with static output: ${page.componentPath}.`);
|
|
28
54
|
}
|
|
@@ -32,13 +58,19 @@ export function voidHonoPages() {
|
|
|
32
58
|
return [honoIslands(), honoJsx(), {
|
|
33
59
|
name: 'void-hono:pages',
|
|
34
60
|
enforce: 'pre',
|
|
35
|
-
config() {
|
|
36
|
-
assertSupportedFrameworks();
|
|
61
|
+
config(config) {
|
|
62
|
+
assertSupportedFrameworks({ root: resolve(config.root ?? root), viteVersion: this?.meta?.viteVersion });
|
|
37
63
|
return {
|
|
38
64
|
resolve: { dedupe: ['hono'] },
|
|
39
65
|
build: { manifest: true, rollupOptions: { input: { 'pages-client': clientId } } },
|
|
40
66
|
};
|
|
41
67
|
},
|
|
68
|
+
configResolved: {
|
|
69
|
+
order: 'pre',
|
|
70
|
+
handler(config) {
|
|
71
|
+
markdown = markdownApi(config.plugins);
|
|
72
|
+
},
|
|
73
|
+
},
|
|
42
74
|
configEnvironment() {
|
|
43
75
|
const modules = Object.keys(publicRuntimeModules);
|
|
44
76
|
const packages = [...new Set(modules.map((id) => id.slice(0, id.lastIndexOf('/'))))];
|
|
@@ -76,7 +108,7 @@ export function voidHonoPages() {
|
|
|
76
108
|
resolveId(id) {
|
|
77
109
|
if (id === rendererId || id === clientId)
|
|
78
110
|
return `\0${id}`;
|
|
79
|
-
if (id === pagesRuntimePath || id === clientRuntimePath)
|
|
111
|
+
if (id === pagesRuntimePath || id === clientRuntimePath || id === markdownRuntimePath)
|
|
80
112
|
return { id: realpathSync(id), external: false };
|
|
81
113
|
const runtime = publicRuntimeModules[id];
|
|
82
114
|
if (runtime)
|
|
@@ -88,7 +120,7 @@ export function voidHonoPages() {
|
|
|
88
120
|
const currentScan = scan ?? await rescan();
|
|
89
121
|
const serverSnapshot = id === `\0${rendererId}` && this.environment.mode === 'dev';
|
|
90
122
|
const manifestScan = id === `\0${clientId}`
|
|
91
|
-
? { ...currentScan, pages: currentScan.pages.filter((page) => !page.island) }
|
|
123
|
+
? { ...currentScan, pages: currentScan.pages.filter((page) => !page.island), layouts: currentScan.layouts.filter((layout) => !layout.island), namedLayouts: currentScan.namedLayouts.filter((layout) => !layout.island) }
|
|
92
124
|
: serverSnapshot ? { ...currentScan, pages: currentScan.pages.filter((page) => page.renderMode !== 'client') } : currentScan;
|
|
93
125
|
let manifest = generateComponentManifest(manifestScan, pagesDir);
|
|
94
126
|
if (serverSnapshot) {
|
|
@@ -107,10 +139,13 @@ export function voidHonoPages() {
|
|
|
107
139
|
if (id === `\0${clientId}` && !currentScan.pages.some((page) => !page.island))
|
|
108
140
|
return 'export {};';
|
|
109
141
|
if (id === `\0${rendererId}`) {
|
|
142
|
+
const markdownScriptIds = [...(markdown?.getClientScripts().keys() ?? [])];
|
|
110
143
|
return `
|
|
111
144
|
import { jsx } from 'hono/jsx';
|
|
112
|
-
import {
|
|
113
|
-
|
|
145
|
+
${markdown ? `import { MarkdownContext } from ${JSON.stringify(markdownRuntimePath)};` : ''}
|
|
146
|
+
const markdownScriptIds = new Set(${JSON.stringify(markdownScriptIds)});
|
|
147
|
+
import { createSsrRouter, idleNavigationState } from 'void/pages-client';
|
|
148
|
+
import { PageContext, RouterContext, NavigationContext } from ${JSON.stringify(pagesRuntimePath)};
|
|
114
149
|
import { serializePageData } from 'void/pages-server';
|
|
115
150
|
import { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from 'void/pages-head';
|
|
116
151
|
${manifest}
|
|
@@ -118,7 +153,7 @@ export async function renderPage(pageObj, assetTags) {
|
|
|
118
153
|
if (${JSON.stringify(staticData.enabled)} && pageObj.deferredKeys) throw new Error('Hono Pages: deferred props cannot be statically prerendered; remove defer().');
|
|
119
154
|
const load = components[pageObj.component];
|
|
120
155
|
if (!load) throw new Error('Hono Pages: unknown page component ' + pageObj.component);
|
|
121
|
-
const { default: Page } = await load();
|
|
156
|
+
const { default: Page, frontmatter = {}, headings = [] } = await load();
|
|
122
157
|
if (typeof Page !== 'function') throw new Error('Hono Pages: a page must export a component function.');
|
|
123
158
|
let content = jsx(Page, pageObj.props);
|
|
124
159
|
const ids = layoutTree[pageObj.component] ?? [];
|
|
@@ -127,21 +162,23 @@ export async function renderPage(pageObj, assetTags) {
|
|
|
127
162
|
if (typeof Layout !== 'function') throw new Error('Hono Pages: a layout must export a component function.');
|
|
128
163
|
content = jsx(Layout, { children: content });
|
|
129
164
|
}
|
|
130
|
-
|
|
165
|
+
${markdown ? 'content = jsx(MarkdownContext.Provider, { value: { frontmatter, headings, props: pageObj.props }, children: content });' : ''}
|
|
166
|
+
const markup = await jsx(RouterContext.Provider, { value: createSsrRouter(pageObj.url, pageObj.params), children: jsx(PageContext.Provider, { value: pageObj, children: jsx(NavigationContext.Provider, { value: idleNavigationState(), children: content }) }) }).toString();
|
|
167
|
+
const appHtml = await jsx('div', { id: 'app', 'data-md-script': markdownScriptIds.has(pageObj.component) ? pageObj.component : undefined, ${markdown ? "'data-hono-markdown': JSON.stringify({ frontmatter, headings })," : ''} dangerouslySetInnerHTML: { __html: markup } }).toString();
|
|
131
168
|
const head = pageObj.head;
|
|
132
169
|
const body = pageObj.deferredKeys ? assetTags.body.replaceAll('<script type="module"', '<script async type="module"') : assetTags.body;
|
|
133
170
|
return '<!doctype html><html' + (head ? renderHtmlAttrs(head) : '') + '><head>'
|
|
134
171
|
+ (head ? renderHeadToString(head) : '') + assetTags.css + assetTags.preloads
|
|
135
172
|
+ '</head><body' + (head ? renderBodyAttrs(head) : '') + '>'
|
|
136
173
|
+ '<script id="__VOID_PAGE_DATA__" type="application/json">' + serializePageData(pageObj) + '</script>'
|
|
137
|
-
+
|
|
174
|
+
+ appHtml + body + '</body></html>';
|
|
138
175
|
}
|
|
139
176
|
`;
|
|
140
177
|
}
|
|
141
178
|
return `
|
|
142
179
|
import { startHonoPages } from ${JSON.stringify(clientRuntimePath)};
|
|
143
180
|
${manifest}
|
|
144
|
-
await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} });
|
|
181
|
+
await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, ${JSON.stringify(navigationOptions)});
|
|
145
182
|
`;
|
|
146
183
|
},
|
|
147
184
|
}];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono-pages.js","sourceRoot":"","sources":["../../src/plugins/hono-pages.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpathSync } from 'node:fs';\nimport { normalizePath } from 'vite';\nimport { pagesRuntimePath, clientRuntimePath, publicRuntimeModules } from './runtime-paths.ts';\nimport { generateComponentManifest, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages, type PageScanResult } from 'void/pages';\nimport type { Plugin } from 'vite';\nimport { honoJsx } from './hono-jsx.ts';\nimport { honoIslands } from './hono-islands.ts';\nimport { assertSupportedFrameworks } from './compatibility.ts';\n\nconst rendererId = 'virtual:void-pages-renderer';\nconst clientId = 'virtual:void-pages-client';\n\n/** Experimental Pages contract verified against Void 0.26.1. */\nexport function voidHonoPages(): Plugin[] {\n const root = process.cwd();\n const pagesDir = resolvePagesDir(root);\n const staticData = resolveStaticPageDataBuildOptions(root);\n let scan: PageScanResult | undefined;\n\n async function rescan() {\n scan = await scanPages(root, { pagesDir });\n for (const layout of [...scan.layouts, ...scan.namedLayouts]) {\n if (layout.island || !/\\.[jt]sx$/.test(layout.filePath)) throw new Error('Hono Pages: only standard TSX/JSX layouts are supported.');\n }\n for (const page of scan.pages) {\n if (!/\\.[jt]sx$/.test(page.componentPath)) {\n throw new Error(`Hono Pages: only standard TSX/JSX pages are supported: ${page.componentPath}.`);\n }\n if (staticData.enabled && page.methods.some((method) => method === 'action' || method === 'actions')) {\n throw new Error(`Hono Pages: actions require a server and cannot be used with static output: ${page.componentPath}.`);\n }\n }\n return scan;\n }\n\n return [honoIslands(), honoJsx(), {\n name: 'void-hono:pages',\n enforce: 'pre',\n config() {\n assertSupportedFrameworks();\n return {\n resolve: { dedupe: ['hono'] },\n build: { manifest: true, rollupOptions: { input: { 'pages-client': clientId } } },\n };\n },\n configEnvironment() {\n const modules = Object.keys(publicRuntimeModules);\n const packages = [...new Set(modules.map((id) => id.slice(0, id.lastIndexOf('/'))))];\n return { optimizeDeps: { exclude: ['hono', ...modules] }, resolve: { noExternal: ['hono', ...packages] } };\n },\n async buildStart() {\n await rescan();\n },\n configureServer(server) {\n const clear = (file: string) => {\n if (normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) scan = undefined;\n };\n server.watcher.on('add', clear);\n server.watcher.on('unlink', clear);\n server.httpServer?.once('close', () => { server.watcher.off('add', clear); server.watcher.off('unlink', clear); });\n },\n async hotUpdate({ file, type, modules, timestamp }) {\n if (!normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;\n await rescan();\n if (type !== 'update') return [];\n const invalidated = new Set<(typeof modules)[number]>();\n for (const module of modules) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n for (const id of [rendererId, clientId]) {\n const module = this.environment.moduleGraph.getModuleById(`\\0${id}`);\n if (module) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n }\n this.environment.hot.send({ type: 'full-reload' });\n return [];\n },\n resolveId(id) {\n if (id === rendererId || id === clientId) return `\\0${id}`;\n if (id === pagesRuntimePath || id === clientRuntimePath) return { id: realpathSync(id), external: false };\n const runtime = publicRuntimeModules[id];\n if (runtime) return { id: realpathSync(this.environment.config.consumer === 'client' ? runtime.client : runtime.server), external: false };\n },\n async load(id) {\n if (id !== `\\0${rendererId}` && id !== `\\0${clientId}`) return;\n const currentScan = scan ?? await rescan();\n const serverSnapshot = id === `\\0${rendererId}` && this.environment.mode === 'dev';\n const manifestScan = id === `\\0${clientId}`\n ? { ...currentScan, pages: currentScan.pages.filter((page) => !page.island) }\n : serverSnapshot ? { ...currentScan, pages: currentScan.pages.filter((page) => page.renderMode !== 'client') } : currentScan;\n let manifest = generateComponentManifest(manifestScan, pagesDir);\n if (serverSnapshot) {\n // A request can retain the old renderer while the worker module runner\n // reloads. Capture components with its providers instead of importing\n // a new generation into an in-flight render. Browser-only pages remain\n // absent from this server graph; production keeps lazy imports.\n const imports: string[] = [];\n manifest = manifest.replace(/\\(\\) => import\\((\"(?:[^\"\\\\]|\\\\.)*\")\\)/g, (_, path: string) => {\n const name = `__honoPageSnapshot${imports.length}`;\n imports.push(`import * as ${name} from ${path};`);\n return `() => ${name}`;\n });\n manifest = imports.join('\\n') + '\\n' + manifest;\n }\n if (id === `\\0${clientId}` && !currentScan.pages.some((page) => !page.island)) return 'export {};';\n if (id === `\\0${rendererId}`) {\n return `\nimport { jsx } from 'hono/jsx';\nimport { createSsrRouter } from 'void/pages-client';\nimport { PageContext, RouterContext } from ${JSON.stringify(pagesRuntimePath)};\nimport { serializePageData } from 'void/pages-server';\nimport { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from 'void/pages-head';\n${manifest}\nexport async function renderPage(pageObj, assetTags) {\n if (${JSON.stringify(staticData.enabled)} && pageObj.deferredKeys) throw new Error('Hono Pages: deferred props cannot be statically prerendered; remove defer().');\n const load = components[pageObj.component];\n if (!load) throw new Error('Hono Pages: unknown page component ' + pageObj.component);\n const { default: Page } = await load();\n if (typeof Page !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n let content = jsx(Page, pageObj.props);\n const ids = layoutTree[pageObj.component] ?? [];\n const layouts = await Promise.all(ids.map(async (id) => (await components[id]()).default));\n for (const Layout of layouts.reverse()) {\n if (typeof Layout !== 'function') throw new Error('Hono Pages: a layout must export a component function.');\n content = jsx(Layout, { children: content });\n }\n const markup = await jsx(RouterContext.Provider, { value: createSsrRouter(pageObj.url, pageObj.params), children: jsx(PageContext.Provider, { value: pageObj, children: content }) }).toString();\n const head = pageObj.head;\n const body = pageObj.deferredKeys ? assetTags.body.replaceAll('<script type=\"module\"', '<script async type=\"module\"') : assetTags.body;\n return '<!doctype html><html' + (head ? renderHtmlAttrs(head) : '') + '><head>'\n + (head ? renderHeadToString(head) : '') + assetTags.css + assetTags.preloads\n + '</head><body' + (head ? renderBodyAttrs(head) : '') + '>'\n + '<script id=\"__VOID_PAGE_DATA__\" type=\"application/json\">' + serializePageData(pageObj) + '</script>'\n + '<div id=\"app\">' + markup + '</div>' + body + '</body></html>';\n}\n`;\n }\n return `\nimport { startHonoPages } from ${JSON.stringify(clientRuntimePath)};\n${manifest}\nawait startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} });\n`;\n },\n }];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hono-pages.js","sourceRoot":"","sources":["../../src/plugins/hono-pages.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpathSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { normalizePath } from 'vite';\nimport { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.ts';\nimport { generateComponentManifest, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages, type PageScanResult } from 'void/pages';\nimport type { Plugin } from 'vite';\nimport { parseCacheFor, type CacheForInput } from 'void/pages-prefetch';\nimport { honoJsx } from './hono-jsx.ts';\nimport { honoIslands } from './hono-islands.ts';\nimport { markdownApi, markdownDiagnostic, type HonoMarkdownApi } from './markdown-api.ts';\nimport { assertSupportedFrameworks } from './compatibility.ts';\n\nconst rendererId = 'virtual:void-pages-renderer';\nconst clientId = 'virtual:void-pages-client';\n\nfunction assertComponentFile(file: string, kind: 'page' | 'layout', markdown = false) {\n if (/\\.md$/.test(file)) { if (markdown && kind === 'page') return; if (markdown) throw new Error('Hono Markdown: layouts must remain TSX/JSX: ' + file); throw new Error(`${markdownDiagnostic} ${kind}: ${file}`); }\n if (!/\\.[jt]sx$/.test(file)) throw new Error(`Hono Pages: only standard TSX/JSX ${kind}s are supported: ${file}.`);\n}\n\n\nexport type HonoJsxOptions = {\n viewTransitions?: boolean;\n prefetch?: { hoverDelay?: number; cacheFor?: CacheForInput };\n};\n\nfunction clientOptions(options: HonoJsxOptions) {\n const viewTransitions = options.viewTransitions ?? false;\n const prefetchHoverDelay = options.prefetch?.hoverDelay ?? 75;\n if (typeof viewTransitions !== 'boolean') throw new Error('Hono Pages: viewTransitions must be a boolean.');\n if (!Number.isFinite(prefetchHoverDelay) || prefetchHoverDelay < 0) throw new Error('Hono Pages: prefetch.hoverDelay must be a finite non-negative number.');\n const prefetchDefaultCacheFor = parseCacheFor(options.prefetch?.cacheFor ?? '30s');\n if (![prefetchDefaultCacheFor.stale, prefetchDefaultCacheFor.expires].every(value => Number.isFinite(value) && value >= 0) || prefetchDefaultCacheFor.stale > prefetchDefaultCacheFor.expires) {\n throw new Error('Hono Pages: prefetch.cacheFor must have finite non-negative durations, with stale <= expires.');\n }\n return { viewTransitions, prefetchHoverDelay, prefetchDefaultCacheFor };\n}\n\n/** Experimental Pages contract verified against Void 0.26.1 and 0.27.0. */\nexport function voidHonoJsx(options: HonoJsxOptions = {}): Plugin[] {\n const navigationOptions = clientOptions(options);\n const root = process.cwd();\n const pagesDir = resolvePagesDir(root);\n const staticData = resolveStaticPageDataBuildOptions(root);\n let scan: PageScanResult | undefined;\n let markdown: HonoMarkdownApi | undefined;\n\n async function rescan() {\n scan = await scanPages(root, { pagesDir });\n for (const layout of [...scan.layouts, ...scan.namedLayouts]) {\n assertComponentFile(layout.filePath, 'layout');\n }\n for (const page of scan.pages) {\n assertComponentFile(page.componentPath, 'page', Boolean(markdown));\n if (staticData.enabled && page.methods.some((method) => method === 'action' || method === 'actions')) {\n throw new Error(`Hono Pages: actions require a server and cannot be used with static output: ${page.componentPath}.`);\n }\n }\n return scan;\n }\n\n return [honoIslands(), honoJsx(), {\n name: 'void-hono:pages',\n enforce: 'pre',\n config(config) {\n assertSupportedFrameworks({ root: resolve(config.root ?? root), viteVersion: this?.meta?.viteVersion });\n return {\n resolve: { dedupe: ['hono'] },\n build: { manifest: true, rollupOptions: { input: { 'pages-client': clientId } } },\n };\n },\n configResolved: {\n order: 'pre',\n handler(config) {\n markdown = markdownApi(config.plugins);\n },\n },\n configEnvironment() {\n const modules = Object.keys(publicRuntimeModules);\n const packages = [...new Set(modules.map((id) => id.slice(0, id.lastIndexOf('/'))))];\n return { optimizeDeps: { exclude: ['hono', ...modules] }, resolve: { noExternal: ['hono', ...packages] } };\n },\n async buildStart() {\n await rescan();\n },\n configureServer(server) {\n const clear = (file: string) => {\n if (normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) scan = undefined;\n };\n server.watcher.on('add', clear);\n server.watcher.on('unlink', clear);\n server.httpServer?.once('close', () => { server.watcher.off('add', clear); server.watcher.off('unlink', clear); });\n },\n async hotUpdate({ file, type, modules, timestamp }) {\n if (!normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;\n await rescan();\n if (type !== 'update') return [];\n const invalidated = new Set<(typeof modules)[number]>();\n for (const module of modules) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n for (const id of [rendererId, clientId]) {\n const module = this.environment.moduleGraph.getModuleById(`\\0${id}`);\n if (module) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n }\n this.environment.hot.send({ type: 'full-reload' });\n return [];\n },\n resolveId(id) {\n if (id === rendererId || id === clientId) return `\\0${id}`;\n if (id === pagesRuntimePath || id === clientRuntimePath || id === markdownRuntimePath) return { id: realpathSync(id), external: false };\n const runtime = publicRuntimeModules[id];\n if (runtime) return { id: realpathSync(this.environment.config.consumer === 'client' ? runtime.client : runtime.server), external: false };\n },\n async load(id) {\n if (id !== `\\0${rendererId}` && id !== `\\0${clientId}`) return;\n const currentScan = scan ?? await rescan();\n const serverSnapshot = id === `\\0${rendererId}` && this.environment.mode === 'dev';\n const manifestScan = id === `\\0${clientId}`\n ? { ...currentScan, pages: currentScan.pages.filter((page) => !page.island), layouts: currentScan.layouts.filter((layout) => !layout.island), namedLayouts: currentScan.namedLayouts.filter((layout) => !layout.island) }\n : serverSnapshot ? { ...currentScan, pages: currentScan.pages.filter((page) => page.renderMode !== 'client') } : currentScan;\n let manifest = generateComponentManifest(manifestScan, pagesDir);\n if (serverSnapshot) {\n // A request can retain the old renderer while the worker module runner\n // reloads. Capture components with its providers instead of importing\n // a new generation into an in-flight render. Browser-only pages remain\n // absent from this server graph; production keeps lazy imports.\n const imports: string[] = [];\n manifest = manifest.replace(/\\(\\) => import\\((\"(?:[^\"\\\\]|\\\\.)*\")\\)/g, (_, path: string) => {\n const name = `__honoPageSnapshot${imports.length}`;\n imports.push(`import * as ${name} from ${path};`);\n return `() => ${name}`;\n });\n manifest = imports.join('\\n') + '\\n' + manifest;\n }\n if (id === `\\0${clientId}` && !currentScan.pages.some((page) => !page.island)) return 'export {};';\n if (id === `\\0${rendererId}`) {\n const markdownScriptIds = [...(markdown?.getClientScripts().keys() ?? [])];\n return `\nimport { jsx } from 'hono/jsx';\n${markdown ? `import { MarkdownContext } from ${JSON.stringify(markdownRuntimePath)};` : ''}\nconst markdownScriptIds = new Set(${JSON.stringify(markdownScriptIds)});\nimport { createSsrRouter, idleNavigationState } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext } from ${JSON.stringify(pagesRuntimePath)};\nimport { serializePageData } from 'void/pages-server';\nimport { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from 'void/pages-head';\n${manifest}\nexport async function renderPage(pageObj, assetTags) {\n if (${JSON.stringify(staticData.enabled)} && pageObj.deferredKeys) throw new Error('Hono Pages: deferred props cannot be statically prerendered; remove defer().');\n const load = components[pageObj.component];\n if (!load) throw new Error('Hono Pages: unknown page component ' + pageObj.component);\n const { default: Page, frontmatter = {}, headings = [] } = await load();\n if (typeof Page !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n let content = jsx(Page, pageObj.props);\n const ids = layoutTree[pageObj.component] ?? [];\n const layouts = await Promise.all(ids.map(async (id) => (await components[id]()).default));\n for (const Layout of layouts.reverse()) {\n if (typeof Layout !== 'function') throw new Error('Hono Pages: a layout must export a component function.');\n content = jsx(Layout, { children: content });\n }\n ${markdown ? 'content = jsx(MarkdownContext.Provider, { value: { frontmatter, headings, props: pageObj.props }, children: content });' : ''}\n const markup = await jsx(RouterContext.Provider, { value: createSsrRouter(pageObj.url, pageObj.params), children: jsx(PageContext.Provider, { value: pageObj, children: jsx(NavigationContext.Provider, { value: idleNavigationState(), children: content }) }) }).toString();\n const appHtml = await jsx('div', { id: 'app', 'data-md-script': markdownScriptIds.has(pageObj.component) ? pageObj.component : undefined, ${markdown ? \"'data-hono-markdown': JSON.stringify({ frontmatter, headings }),\" : ''} dangerouslySetInnerHTML: { __html: markup } }).toString();\n const head = pageObj.head;\n const body = pageObj.deferredKeys ? assetTags.body.replaceAll('<script type=\"module\"', '<script async type=\"module\"') : assetTags.body;\n return '<!doctype html><html' + (head ? renderHtmlAttrs(head) : '') + '><head>'\n + (head ? renderHeadToString(head) : '') + assetTags.css + assetTags.preloads\n + '</head><body' + (head ? renderBodyAttrs(head) : '') + '>'\n + '<script id=\"__VOID_PAGE_DATA__\" type=\"application/json\">' + serializePageData(pageObj) + '</script>'\n + appHtml + body + '</body></html>';\n}\n`;\n }\n return `\nimport { startHonoPages } from ${JSON.stringify(clientRuntimePath)};\n${manifest}\nawait startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, ${JSON.stringify(navigationOptions)});\n`;\n },\n }];\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
export declare const markdownDiagnostic = "Hono Pages: Markdown requires voidHonoMarkdown() from void-plugin-hono-jsx/markdown/plugin and its optional parser dependencies. See docs/markdown.md.";
|
|
3
|
+
export type HonoMarkdownApi = {
|
|
4
|
+
adapter: 'hono';
|
|
5
|
+
clientEntryId: string;
|
|
6
|
+
getClientScripts(): Map<string, string>;
|
|
7
|
+
getGraphSource(file: string): string;
|
|
8
|
+
};
|
|
9
|
+
export declare function markdownApi(plugins: readonly Plugin[]): HonoMarkdownApi | undefined;
|
|
10
|
+
//# sourceMappingURL=markdown-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-api.d.ts","sourceRoot":"","sources":["../../src/plugins/markdown-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,eAAO,MAAM,kBAAkB,2JAA2J,CAAC;AAC3L,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACtC,CAAC;AACF,wBAAgB,WAAW,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,GAAG,SAAS,CAOnF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const markdownDiagnostic = 'Hono Pages: Markdown requires voidHonoMarkdown() from void-plugin-hono-jsx/markdown/plugin and its optional parser dependencies. See docs/markdown.md.';
|
|
2
|
+
export function markdownApi(plugins) {
|
|
3
|
+
const markdown = plugins.filter(plugin => plugin.name === 'void-md');
|
|
4
|
+
if (markdown.length > 1)
|
|
5
|
+
throw new Error('Hono Pages: configure only one Markdown compiler.');
|
|
6
|
+
const plugin = markdown[0];
|
|
7
|
+
if (!plugin)
|
|
8
|
+
return;
|
|
9
|
+
if (plugin.api?.adapter !== 'hono')
|
|
10
|
+
throw new Error('Hono Pages: use voidHonoMarkdown(), not @void/md/plugin; the official compiler does not emit Hono components.');
|
|
11
|
+
return plugin.api;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=markdown-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-api.js","sourceRoot":"","sources":["../../src/plugins/markdown-api.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAG,wJAAwJ,CAAC;AAO3L,MAAM,UAAU,WAAW,CAAC,OAA0B;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IACrE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IAC9F,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,IAAI,MAAM,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,+GAA+G,CAAC,CAAC;IACrK,OAAO,MAAM,CAAC,GAAsB,CAAC;AACvC,CAAC","sourcesContent":["import type { Plugin } from 'vite';\n\nexport const markdownDiagnostic = 'Hono Pages: Markdown requires voidHonoMarkdown() from void-plugin-hono-jsx/markdown/plugin and its optional parser dependencies. See docs/markdown.md.';\nexport type HonoMarkdownApi = {\n adapter: 'hono';\n clientEntryId: string;\n getClientScripts(): Map<string, string>;\n getGraphSource(file: string): string;\n};\nexport function markdownApi(plugins: readonly Plugin[]): HonoMarkdownApi | undefined {\n const markdown = plugins.filter(plugin => plugin.name === 'void-md');\n if (markdown.length > 1) throw new Error('Hono Pages: configure only one Markdown compiler.');\n const plugin = markdown[0];\n if (!plugin) return;\n if (plugin.api?.adapter !== 'hono') throw new Error('Hono Pages: use voidHonoMarkdown(), not @void/md/plugin; the official compiler does not emit Hono components.');\n return plugin.api as HonoMarkdownApi;\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type Heading = {
|
|
2
|
+
depth: number;
|
|
3
|
+
slug: string;
|
|
4
|
+
text: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function extractMarkdown(source: string): {
|
|
7
|
+
body: string;
|
|
8
|
+
script: string;
|
|
9
|
+
imports: {
|
|
10
|
+
start: number;
|
|
11
|
+
end: number;
|
|
12
|
+
importName: string;
|
|
13
|
+
specifierRaw: string;
|
|
14
|
+
specifier: string;
|
|
15
|
+
hydrate: string;
|
|
16
|
+
}[];
|
|
17
|
+
graphSource: string;
|
|
18
|
+
clientCode: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function compileMarkdown(source: string): {
|
|
21
|
+
body: string;
|
|
22
|
+
script: string;
|
|
23
|
+
imports: {
|
|
24
|
+
start: number;
|
|
25
|
+
end: number;
|
|
26
|
+
importName: string;
|
|
27
|
+
specifierRaw: string;
|
|
28
|
+
specifier: string;
|
|
29
|
+
hydrate: string;
|
|
30
|
+
}[];
|
|
31
|
+
graphSource: string;
|
|
32
|
+
clientCode: string;
|
|
33
|
+
frontmatter: Record<string, unknown>;
|
|
34
|
+
headings: Heading[];
|
|
35
|
+
html: string;
|
|
36
|
+
};
|
|
37
|
+
export declare function renderChunks(html: string, names: Set<string>): ({
|
|
38
|
+
html: string;
|
|
39
|
+
} | {
|
|
40
|
+
name: string;
|
|
41
|
+
props: Record<string, string | boolean>;
|
|
42
|
+
})[];
|
|
43
|
+
//# sourceMappingURL=markdown-compiler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-compiler.d.ts","sourceRoot":"","sources":["../../src/plugins/markdown-compiler.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,OAAO,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACpE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;EAU7C;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;EAgC7C;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC;UAE/B,MAAM;;UAAa,MAAM;WAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;KAkB/F"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import MarkdownExit from 'markdown-exit';
|
|
2
|
+
import { parseSync } from 'vite';
|
|
3
|
+
import { parseDocument } from 'yaml';
|
|
4
|
+
import { findIslandImports, editIslandSource } from 'void/pages-islands-plugin';
|
|
5
|
+
const unescapeAttribute = new MarkdownExit().utils.unescapeAll;
|
|
6
|
+
export function extractMarkdown(source) {
|
|
7
|
+
const match = source.match(/^<script\b[^>]*>([\s\S]*?)<\/script>\s*\n?/);
|
|
8
|
+
const script = match?.[1] ?? '';
|
|
9
|
+
const body = match ? source.slice(match[0].length) : source;
|
|
10
|
+
const imports = findIslandImports(script, 'markdown-script.ts');
|
|
11
|
+
const attributed = parseSync('markdown-script.ts', script).program.body.filter(node => node.type === 'ImportDeclaration' && node.attributes?.some(({ key }) => ('name' in key && key.name === 'island') || ('value' in key && key.value === 'island')));
|
|
12
|
+
if (attributed.length !== imports.length)
|
|
13
|
+
throw new Error('Hono Markdown: use one default component import with exactly one island attribute.');
|
|
14
|
+
const graphSource = imports.map(entry => script.slice(entry.start, entry.end)).join('\n');
|
|
15
|
+
const clientCode = editIslandSource(script, imports.map(entry => ({ start: entry.start, end: entry.end, text: '' }))).code.trim();
|
|
16
|
+
return { body, script, imports, graphSource, clientCode };
|
|
17
|
+
}
|
|
18
|
+
export function compileMarkdown(source) {
|
|
19
|
+
const extracted = extractMarkdown(source);
|
|
20
|
+
const match = extracted.body.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
21
|
+
let frontmatter = {};
|
|
22
|
+
if (match) {
|
|
23
|
+
const yaml = parseDocument(match[1], { uniqueKeys: true });
|
|
24
|
+
if (yaml.errors.length)
|
|
25
|
+
throw new Error('Hono Markdown: invalid frontmatter: ' + yaml.errors.map(error => error.message).join('; '));
|
|
26
|
+
const value = yaml.toJS({ maxAliasCount: 50 });
|
|
27
|
+
if (value !== null && (typeof value !== 'object' || Array.isArray(value)))
|
|
28
|
+
throw new Error('Hono Markdown: frontmatter must be a mapping.');
|
|
29
|
+
frontmatter = (value ?? {});
|
|
30
|
+
try {
|
|
31
|
+
JSON.stringify(frontmatter);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new Error('Hono Markdown: frontmatter must be JSON serializable.');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const content = match ? extracted.body.slice(match[0].length) : extracted.body;
|
|
38
|
+
const compiler = new MarkdownExit({ html: true, linkify: true });
|
|
39
|
+
const tokens = compiler.parse(content, {});
|
|
40
|
+
const headings = [];
|
|
41
|
+
const slugs = new Map();
|
|
42
|
+
const authoredHtml = tokens.flatMap(token => token.type === 'html_block' || token.type === 'html_inline' ? [token.content] : (token.children ?? []).filter(child => child.type === 'html_inline').map(child => child.content)).join('\n');
|
|
43
|
+
const usedIds = new Set([...authoredHtml.matchAll(/\bid\s*=\s*(?:"([^"]*)"|'([^']*)')/g)].map(match => match[1] ?? match[2]));
|
|
44
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
45
|
+
if (tokens[index].type !== 'heading_open')
|
|
46
|
+
continue;
|
|
47
|
+
const inline = tokens[index + 1];
|
|
48
|
+
const text = inline.children?.map(token => token.type === 'text' || token.type === 'code_inline' ? token.content : token.type === 'image' ? token.content : '').join('') ?? inline.content;
|
|
49
|
+
const base = text.toLowerCase().replace(/[^\p{L}\p{N} _-]/gu, '').trim().replace(/\s+/g, '-') || 'heading';
|
|
50
|
+
let count = slugs.get(base) ?? 0;
|
|
51
|
+
let slug = count ? `${base}-${count}` : base;
|
|
52
|
+
while (usedIds.has(slug)) {
|
|
53
|
+
count++;
|
|
54
|
+
slug = `${base}-${count}`;
|
|
55
|
+
}
|
|
56
|
+
slugs.set(base, count + 1);
|
|
57
|
+
usedIds.add(slug);
|
|
58
|
+
tokens[index].attrSet('id', slug);
|
|
59
|
+
headings.push({ depth: Number(tokens[index].tag.slice(1)), slug, text });
|
|
60
|
+
}
|
|
61
|
+
return { ...extracted, frontmatter, headings, html: compiler.renderer.render(tokens, compiler.options, {}) };
|
|
62
|
+
}
|
|
63
|
+
// Component tag splitting follows @void/md 0.27.0's emit-shared convention.
|
|
64
|
+
// Hono raw fragments preserve enclosing HTML across the component boundaries.
|
|
65
|
+
export function renderChunks(html, names) {
|
|
66
|
+
const tags = /<([A-Z]\w*)\s*((?:[^>/"']|"[^"]*"|'[^']*')*)\/\s*>|<([A-Z]\w*)\s*((?:[^>/"']|"[^"]*"|'[^']*')*)>([\s\S]*?)<\/\3\s*>/g;
|
|
67
|
+
const chunks = [];
|
|
68
|
+
let cursor = 0;
|
|
69
|
+
for (const match of html.matchAll(tags)) {
|
|
70
|
+
const name = match[1] ?? match[3];
|
|
71
|
+
if (!names.has(name))
|
|
72
|
+
continue;
|
|
73
|
+
if (match[5]?.trim())
|
|
74
|
+
throw new Error('Hono Markdown: island tag children are unsupported; pass literal attributes to a self-closing tag.');
|
|
75
|
+
if (match.index > cursor)
|
|
76
|
+
chunks.push({ html: html.slice(cursor, match.index) });
|
|
77
|
+
const props = Object.create(null);
|
|
78
|
+
const attrs = match[2] ?? match[4] ?? '';
|
|
79
|
+
const attrRe = /(\w[\w-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s]+)))?/g;
|
|
80
|
+
for (const attr of attrs.matchAll(attrRe)) {
|
|
81
|
+
const value = attr[2] ?? attr[3] ?? attr[4];
|
|
82
|
+
props[attr[1]] = value === undefined ? true : unescapeAttribute(value);
|
|
83
|
+
}
|
|
84
|
+
chunks.push({ name, props });
|
|
85
|
+
cursor = match.index + match[0].length;
|
|
86
|
+
}
|
|
87
|
+
if (cursor < html.length)
|
|
88
|
+
chunks.push({ html: html.slice(cursor) });
|
|
89
|
+
return chunks;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=markdown-compiler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-compiler.js","sourceRoot":"","sources":["../../src/plugins/markdown-compiler.ts"],"names":[],"mappings":"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","sourcesContent":["import MarkdownExit from 'markdown-exit';\nimport { parseSync } from 'vite';\nimport { parseDocument } from 'yaml';\nimport { findIslandImports, editIslandSource } from 'void/pages-islands-plugin';\n\nconst unescapeAttribute = new MarkdownExit().utils.unescapeAll;\n\nexport type Heading = { depth: number; slug: string; text: string };\nexport function extractMarkdown(source: string) {\n const match = source.match(/^<script\\b[^>]*>([\\s\\S]*?)<\\/script>\\s*\\n?/);\n const script = match?.[1] ?? '';\n const body = match ? source.slice(match[0].length) : source;\n const imports = findIslandImports(script, 'markdown-script.ts');\n const attributed = parseSync('markdown-script.ts', script).program.body.filter(node => node.type === 'ImportDeclaration' && node.attributes?.some(({ key }) => ('name' in key && key.name === 'island') || ('value' in key && key.value === 'island')));\n if (attributed.length !== imports.length) throw new Error('Hono Markdown: use one default component import with exactly one island attribute.');\n const graphSource = imports.map(entry => script.slice(entry.start, entry.end)).join('\\n');\n const clientCode = editIslandSource(script, imports.map(entry => ({ start: entry.start, end: entry.end, text: '' }))).code.trim();\n return { body, script, imports, graphSource, clientCode };\n}\n\nexport function compileMarkdown(source: string) {\n const extracted = extractMarkdown(source);\n const match = extracted.body.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---(?:\\r?\\n|$)/);\n let frontmatter: Record<string, unknown> = {};\n if (match) {\n const yaml = parseDocument(match[1], { uniqueKeys: true });\n if (yaml.errors.length) throw new Error('Hono Markdown: invalid frontmatter: ' + yaml.errors.map(error => error.message).join('; '));\n const value: unknown = yaml.toJS({ maxAliasCount: 50 });\n if (value !== null && (typeof value !== 'object' || Array.isArray(value))) throw new Error('Hono Markdown: frontmatter must be a mapping.');\n frontmatter = (value ?? {}) as Record<string, unknown>;\n try { JSON.stringify(frontmatter); } catch { throw new Error('Hono Markdown: frontmatter must be JSON serializable.'); }\n }\n const content = match ? extracted.body.slice(match[0].length) : extracted.body;\n const compiler = new MarkdownExit({ html: true, linkify: true });\n const tokens = compiler.parse(content, {});\n const headings: Heading[] = [];\n const slugs = new Map<string, number>();\n const authoredHtml = tokens.flatMap(token => token.type === 'html_block' || token.type === 'html_inline' ? [token.content] : (token.children ?? []).filter(child => child.type === 'html_inline').map(child => child.content)).join('\\n');\n const usedIds = new Set([...authoredHtml.matchAll(/\\bid\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/g)].map(match => match[1] ?? match[2]));\n for (let index = 0; index < tokens.length; index++) {\n if (tokens[index].type !== 'heading_open') continue;\n const inline = tokens[index + 1];\n const text = inline.children?.map(token => token.type === 'text' || token.type === 'code_inline' ? token.content : token.type === 'image' ? token.content : '').join('') ?? inline.content;\n const base = text.toLowerCase().replace(/[^\\p{L}\\p{N} _-]/gu, '').trim().replace(/\\s+/g, '-') || 'heading';\n let count = slugs.get(base) ?? 0;\n let slug = count ? `${base}-${count}` : base;\n while (usedIds.has(slug)) { count++; slug = `${base}-${count}`; }\n slugs.set(base, count + 1); usedIds.add(slug);\n tokens[index].attrSet('id', slug);\n headings.push({ depth: Number(tokens[index].tag.slice(1)), slug, text });\n }\n return { ...extracted, frontmatter, headings, html: compiler.renderer.render(tokens, compiler.options, {}) };\n}\n\n// Component tag splitting follows @void/md 0.27.0's emit-shared convention.\n// Hono raw fragments preserve enclosing HTML across the component boundaries.\nexport function renderChunks(html: string, names: Set<string>) {\n const tags = /<([A-Z]\\w*)\\s*((?:[^>/\"']|\"[^\"]*\"|'[^']*')*)\\/\\s*>|<([A-Z]\\w*)\\s*((?:[^>/\"']|\"[^\"]*\"|'[^']*')*)>([\\s\\S]*?)<\\/\\3\\s*>/g;\n const chunks: Array<{ html: string } | { name: string; props: Record<string, string | boolean> }> = [];\n let cursor = 0;\n for (const match of html.matchAll(tags)) {\n const name = match[1] ?? match[3];\n if (!names.has(name)) continue;\n if (match[5]?.trim()) throw new Error('Hono Markdown: island tag children are unsupported; pass literal attributes to a self-closing tag.');\n if (match.index > cursor) chunks.push({ html: html.slice(cursor, match.index) });\n const props: Record<string, string | boolean> = Object.create(null);\n const attrs = match[2] ?? match[4] ?? '';\n const attrRe = /(\\w[\\w-]*)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s]+)))?/g;\n for (const attr of attrs.matchAll(attrRe)) {\n const value = attr[2] ?? attr[3] ?? attr[4];\n props[attr[1]] = value === undefined ? true : unescapeAttribute(value);\n }\n chunks.push({ name, props }); cursor = match.index + match[0].length;\n }\n if (cursor < html.length) chunks.push({ html: html.slice(cursor) });\n return chunks;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-component.d.ts","sourceRoot":"","sources":["../../src/plugins/resolve-component.ts"],"names":[],"mappings":"AAGA,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,iBAO5F"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { statSync } from 'node:fs';
|
|
2
|
+
import { resolveSpecifier } from 'void/pages-islands-plugin';
|
|
3
|
+
/** Relative component imports also use Vite's directory/index convention. */
|
|
4
|
+
export function resolveComponent(specifier, importerDir, extensions) {
|
|
5
|
+
const target = resolveSpecifier(specifier, importerDir, extensions);
|
|
6
|
+
if (!target)
|
|
7
|
+
return null;
|
|
8
|
+
if (statSync(target).isFile())
|
|
9
|
+
return target;
|
|
10
|
+
if (!statSync(target).isDirectory())
|
|
11
|
+
return null;
|
|
12
|
+
const index = resolveSpecifier('./index', target, extensions);
|
|
13
|
+
return index && statSync(index).isFile() ? index : null;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=resolve-component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-component.js","sourceRoot":"","sources":["../../src/plugins/resolve-component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,6EAA6E;AAC7E,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,WAAmB,EAAE,UAAoB;IAC3F,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE;QAAE,OAAO,MAAM,CAAC;IAC7C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;QAAE,OAAO,IAAI,CAAC;IACjD,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9D,OAAO,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1D,CAAC","sourcesContent":["import { statSync } from 'node:fs';\nimport { resolveSpecifier } from 'void/pages-islands-plugin';\n\n/** Relative component imports also use Vite's directory/index convention. */\nexport function resolveComponent(specifier: string, importerDir: string, extensions: string[]) {\n const target = resolveSpecifier(specifier, importerDir, extensions);\n if (!target) return null;\n if (statSync(target).isFile()) return target;\n if (!statSync(target).isDirectory()) return null;\n const index = resolveSpecifier('./index', target, extensions);\n return index && statSync(index).isFile() ? index : null;\n}\n"]}
|