@blinkk/root 1.0.0-alpha.4 → 1.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/root.js +19 -15
- package/dist/{chunk-CDPH3RKE.js → chunk-5FQTLGCQ.js} +22 -5
- package/dist/{chunk-CDPH3RKE.js.map → chunk-5FQTLGCQ.js.map} +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +206 -101
- package/dist/cli.js.map +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/render.d.ts +1 -1
- package/dist/render.js +89 -62
- package/dist/render.js.map +1 -1
- package/dist/{types-07f4e3d2.d.ts → types-27ca8c1c.d.ts} +4 -0
- package/package.json +2 -2
package/bin/root.js
CHANGED
|
@@ -10,20 +10,24 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
10
10
|
const require = createRequire(import.meta.url);
|
|
11
11
|
const packageJson = require(path.join(__dirname, '../package.json'));
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
program
|
|
13
|
+
async function main() {
|
|
14
|
+
const program = new Command('root');
|
|
15
|
+
program.version(packageJson.version);
|
|
15
16
|
|
|
16
|
-
program
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
program
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
program
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
program
|
|
18
|
+
.command('build [path]')
|
|
19
|
+
.description('generates a static build')
|
|
20
|
+
.action(build);
|
|
21
|
+
program
|
|
22
|
+
.command('dev [path]')
|
|
23
|
+
.description('starts the server in development mode')
|
|
24
|
+
.action(dev);
|
|
25
|
+
program
|
|
26
|
+
.command('start [path]')
|
|
27
|
+
.description('starts the server in production mode')
|
|
28
|
+
.action(start);
|
|
28
29
|
|
|
29
|
-
program.
|
|
30
|
+
await program.parseAsync(process.argv);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
main();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/core/components/error-page.tsx
|
|
2
|
-
import {
|
|
2
|
+
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
3
3
|
function ErrorPage(props) {
|
|
4
4
|
const error = props.error;
|
|
5
5
|
let message = void 0;
|
|
@@ -10,7 +10,18 @@ function ErrorPage(props) {
|
|
|
10
10
|
message = String(error);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
return /* @__PURE__ */
|
|
13
|
+
return /* @__PURE__ */ jsx("div", {
|
|
14
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
15
|
+
children: [
|
|
16
|
+
/* @__PURE__ */ jsx("p", {
|
|
17
|
+
children: "An error occured during route handling or page rendering."
|
|
18
|
+
}),
|
|
19
|
+
message && /* @__PURE__ */ jsx("pre", {
|
|
20
|
+
children: message
|
|
21
|
+
})
|
|
22
|
+
]
|
|
23
|
+
})
|
|
24
|
+
});
|
|
14
25
|
}
|
|
15
26
|
|
|
16
27
|
// src/core/components/head.ts
|
|
@@ -23,7 +34,10 @@ function Head(props) {
|
|
|
23
34
|
context = useContext(HEAD_CONTEXT);
|
|
24
35
|
} catch (err) {
|
|
25
36
|
console.log(err);
|
|
26
|
-
throw new Error(
|
|
37
|
+
throw new Error(
|
|
38
|
+
"<Head> component is not supported in the browser, or during suspense renders.",
|
|
39
|
+
{ cause: err }
|
|
40
|
+
);
|
|
27
41
|
}
|
|
28
42
|
context.push(props.children);
|
|
29
43
|
return null;
|
|
@@ -38,7 +52,10 @@ function Script(props) {
|
|
|
38
52
|
try {
|
|
39
53
|
context = useContext2(SCRIPT_CONTEXT);
|
|
40
54
|
} catch (err) {
|
|
41
|
-
throw new Error(
|
|
55
|
+
throw new Error(
|
|
56
|
+
"<Script> component is not supported in the browser, or during suspense renders.",
|
|
57
|
+
{ cause: err }
|
|
58
|
+
);
|
|
42
59
|
}
|
|
43
60
|
context.push(props);
|
|
44
61
|
return null;
|
|
@@ -93,4 +110,4 @@ export {
|
|
|
93
110
|
getTranslations,
|
|
94
111
|
useTranslations
|
|
95
112
|
};
|
|
96
|
-
//# sourceMappingURL=chunk-
|
|
113
|
+
//# sourceMappingURL=chunk-5FQTLGCQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/components/error-page.tsx","../src/core/components/head.ts","../src/core/components/script.ts","../src/core/i18n.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {h} from 'preact';\n\nexport interface ErrorPageProps {\n error: unknown;\n}\n\nexport function ErrorPage(props: ErrorPageProps) {\n const error = props.error;\n\n let message = undefined;\n if (import.meta.env.DEV) {\n if (error instanceof Error) {\n message = error.stack;\n } else {\n message = String(error);\n }\n }\n\n return (\n <div>\n <div>\n <p>An error occured during route handling or page rendering.</p>\n {message && <pre>{message}</pre>}\n </div>\n </div>\n );\n}\n","import {ComponentChildren, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const HEAD_CONTEXT = createContext<ComponentChildren[]>([]);\n\nexport interface HeadProps {\n children?: ComponentChildren;\n}\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page.\n */\nexport function Head(props: HeadProps) {\n let context: ComponentChildren[];\n try {\n context = useContext(HEAD_CONTEXT);\n } catch (err) {\n console.log(err);\n throw new Error(\n '<Head> component is not supported in the browser, or during suspense renders.',\n {cause: err}\n );\n }\n context.push(props.children);\n return null;\n}\n","import {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const SCRIPT_CONTEXT = createContext<ScriptProps[]>([]);\n\nexport interface ScriptProps {\n src: string;\n type?: string;\n}\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `src/bundles` folder at the root of the project.\n */\nexport function Script(props: ScriptProps) {\n let context: ScriptProps[];\n try {\n context = useContext(SCRIPT_CONTEXT);\n } catch (err) {\n throw new Error(\n '<Script> component is not supported in the browser, or during suspense renders.',\n {cause: err}\n );\n }\n context.push(props);\n return null;\n}\n","import path from 'node:path';\nimport {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const I18N_CONTEXT = createContext<I18nContext | null>(null);\n\nexport interface I18nContext {\n locale: string;\n translations: Record<string, string>;\n}\n\nexport function getTranslations(locale: string): Record<string, string> {\n const translations: Record<string, Record<string, string>> = {};\n const translationsFiles = import.meta.glob(['/translations/*.json'], {\n eager: true,\n }) as Record<string, {default?: Record<string, string>}>;\n Object.keys(translationsFiles).forEach((translationPath) => {\n const parts = path.parse(translationPath);\n const locale = parts.name;\n const module = translationsFiles[translationPath];\n if (module && module.default) {\n translations[locale] = module.default;\n }\n });\n return translations[locale] || {};\n}\n\nexport function useTranslations() {\n const context = useContext(I18N_CONTEXT);\n if (!context) {\n throw new Error('could not find i18n context');\n }\n const translations = context?.translations || {};\n const t = (str: string, params?: Record<string, string>) => {\n let translation = translations[str] || str || '';\n if (params) {\n for (const key of Object.keys(params)) {\n const val = String(params[key] || '');\n translation = translation.replaceAll(`{${key}}`, val);\n }\n }\n return translation;\n };\n return t;\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../src/core/components/error-page.tsx","../src/core/components/head.ts","../src/core/components/script.ts","../src/core/i18n.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {h} from 'preact';\n\nexport interface ErrorPageProps {\n error: unknown;\n}\n\nexport function ErrorPage(props: ErrorPageProps) {\n const error = props.error;\n\n let message = undefined;\n if (import.meta.env.DEV) {\n if (error instanceof Error) {\n message = error.stack;\n } else {\n message = String(error);\n }\n }\n\n return (\n <div>\n <div>\n <p>An error occured during route handling or page rendering.</p>\n {message && <pre>{message}</pre>}\n </div>\n </div>\n );\n}\n","import {ComponentChildren, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const HEAD_CONTEXT = createContext<ComponentChildren[]>([]);\n\nexport interface HeadProps {\n children?: ComponentChildren;\n}\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page.\n */\nexport function Head(props: HeadProps) {\n let context: ComponentChildren[];\n try {\n context = useContext(HEAD_CONTEXT);\n } catch (err) {\n console.log(err);\n throw new Error(\n '<Head> component is not supported in the browser, or during suspense renders.',\n {cause: err}\n );\n }\n context.push(props.children);\n return null;\n}\n","import {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const SCRIPT_CONTEXT = createContext<ScriptProps[]>([]);\n\nexport interface ScriptProps {\n src: string;\n type?: string;\n}\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `src/bundles` folder at the root of the project.\n */\nexport function Script(props: ScriptProps) {\n let context: ScriptProps[];\n try {\n context = useContext(SCRIPT_CONTEXT);\n } catch (err) {\n throw new Error(\n '<Script> component is not supported in the browser, or during suspense renders.',\n {cause: err}\n );\n }\n context.push(props);\n return null;\n}\n","import path from 'node:path';\nimport {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const I18N_CONTEXT = createContext<I18nContext | null>(null);\n\nexport interface I18nContext {\n locale: string;\n translations: Record<string, string>;\n}\n\nexport function getTranslations(locale: string): Record<string, string> {\n const translations: Record<string, Record<string, string>> = {};\n const translationsFiles = import.meta.glob(['/translations/*.json'], {\n eager: true,\n }) as Record<string, {default?: Record<string, string>}>;\n Object.keys(translationsFiles).forEach((translationPath) => {\n const parts = path.parse(translationPath);\n const locale = parts.name;\n const module = translationsFiles[translationPath];\n if (module && module.default) {\n translations[locale] = module.default;\n }\n });\n return translations[locale] || {};\n}\n\nexport function useTranslations() {\n const context = useContext(I18N_CONTEXT);\n if (!context) {\n throw new Error('could not find i18n context');\n }\n const translations = context?.translations || {};\n const t = (str: string, params?: Record<string, string>) => {\n let translation = translations[str] || str || '';\n if (params) {\n for (const key of Object.keys(params)) {\n const val = String(params[key] || '');\n translation = translation.replaceAll(`{${key}}`, val);\n }\n }\n return translation;\n };\n return t;\n}\n"],"mappings":";AAqBM,SACE,KADF;AAdC,SAAS,UAAU,OAAuB;AAC/C,QAAM,QAAQ,MAAM;AAEpB,MAAI,UAAU;AACd,MAAI,YAAY,IAAI,KAAK;AACvB,QAAI,iBAAiB,OAAO;AAC1B,gBAAU,MAAM;AAAA,IAClB,OAAO;AACL,gBAAU,OAAO,KAAK;AAAA,IACxB;AAAA,EACF;AAEA,SACE,oBAAC;AAAA,IACC,+BAAC;AAAA,MACC;AAAA,4BAAC;AAAA,UAAE;AAAA,SAAyD;AAAA,QAC3D,WAAW,oBAAC;AAAA,UAAK;AAAA,SAAQ;AAAA;AAAA,KAC5B;AAAA,GACF;AAEJ;;;AC3BA,SAA2B,qBAAoB;AAC/C,SAAQ,kBAAiB;AAElB,IAAM,eAAe,cAAmC,CAAC,CAAC;AAU1D,SAAS,KAAK,OAAkB;AACrC,MAAI;AACJ,MAAI;AACF,cAAU,WAAW,YAAY;AAAA,EACnC,SAAS,KAAP;AACA,YAAQ,IAAI,GAAG;AACf,UAAM,IAAI;AAAA,MACR;AAAA,MACA,EAAC,OAAO,IAAG;AAAA,IACb;AAAA,EACF;AACA,UAAQ,KAAK,MAAM,QAAQ;AAC3B,SAAO;AACT;;;AC1BA,SAAQ,iBAAAA,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;AAElB,IAAM,iBAAiBD,eAA6B,CAAC,CAAC;AAYtD,SAAS,OAAO,OAAoB;AACzC,MAAI;AACJ,MAAI;AACF,cAAUC,YAAW,cAAc;AAAA,EACrC,SAAS,KAAP;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA,EAAC,OAAO,IAAG;AAAA,IACb;AAAA,EACF;AACA,UAAQ,KAAK,KAAK;AAClB,SAAO;AACT;;;AC3BA,OAAO,UAAU;AACjB,SAAQ,iBAAAC,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;AAElB,IAAM,eAAeD,eAAkC,IAAI;AAO3D,SAAS,gBAAgB,QAAwC;AACtE,QAAM,eAAuD,CAAC;AAC9D,QAAM,oBAAoB,YAAY,KAAK,CAAC,sBAAsB,GAAG;AAAA,IACnE,OAAO;AAAA,EACT,CAAC;AACD,SAAO,KAAK,iBAAiB,EAAE,QAAQ,CAAC,oBAAoB;AAC1D,UAAM,QAAQ,KAAK,MAAM,eAAe;AACxC,UAAME,UAAS,MAAM;AACrB,UAAM,SAAS,kBAAkB;AACjC,QAAI,UAAU,OAAO,SAAS;AAC5B,mBAAaA,WAAU,OAAO;AAAA,IAChC;AAAA,EACF,CAAC;AACD,SAAO,aAAa,WAAW,CAAC;AAClC;AAEO,SAAS,kBAAkB;AAChC,QAAM,UAAUD,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,QAAM,gBAAe,mCAAS,iBAAgB,CAAC;AAC/C,QAAM,IAAI,CAAC,KAAa,WAAoC;AAC1D,QAAI,cAAc,aAAa,QAAQ,OAAO;AAC9C,QAAI,QAAQ;AACV,iBAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,cAAM,MAAM,OAAO,OAAO,QAAQ,EAAE;AACpC,sBAAc,YAAY,WAAW,IAAI,QAAQ,GAAG;AAAA,MACtD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":["createContext","useContext","createContext","useContext","locale"]}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
declare function dev(rootDir?: string): void
|
|
1
|
+
declare function dev(rootDir?: string): Promise<void>;
|
|
2
2
|
|
|
3
3
|
declare function build(rootProjectDir?: string): Promise<void>;
|
|
4
4
|
|
|
5
|
-
declare function start(): Promise<void>;
|
|
5
|
+
declare function start(rootProjectDir?: string): Promise<void>;
|
|
6
6
|
|
|
7
7
|
export { build, dev, start };
|
package/dist/cli.js
CHANGED
|
@@ -50,6 +50,9 @@ async function isDirectory(dirpath) {
|
|
|
50
50
|
throw err;
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
+
function fileExists(filepath) {
|
|
54
|
+
return fs.access(filepath).then(() => true).catch(() => false);
|
|
55
|
+
}
|
|
53
56
|
|
|
54
57
|
// src/render/vite-plugin-root.ts
|
|
55
58
|
var JSX_ELEMENTS_REGEX = /jsxs?\("(\w[\w-]+\w)"/g;
|
|
@@ -65,28 +68,32 @@ function pluginRoot(options) {
|
|
|
65
68
|
includeDirs.forEach((dirPath) => {
|
|
66
69
|
const elementsDir = path2.resolve(rootDir, dirPath);
|
|
67
70
|
if (!elementsDir.startsWith(rootDir)) {
|
|
68
|
-
throw new Error(
|
|
71
|
+
throw new Error(
|
|
72
|
+
`the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`
|
|
73
|
+
);
|
|
69
74
|
}
|
|
70
75
|
elementsDirs.push(elementsDir);
|
|
71
76
|
});
|
|
72
77
|
let elementMap;
|
|
73
78
|
async function updateElementMap() {
|
|
74
79
|
elementMap = {};
|
|
75
|
-
await Promise.all(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const files = await glob("**/*", { cwd: dirPath });
|
|
81
|
-
files.forEach((file) => {
|
|
82
|
-
const parts = path2.parse(file);
|
|
83
|
-
if (isJsFile(parts.base)) {
|
|
84
|
-
const fullPath = path2.join(dirPath, file);
|
|
85
|
-
const moduleId = fullPath.slice(rootDir.length);
|
|
86
|
-
elementMap[parts.name] = moduleId;
|
|
80
|
+
await Promise.all(
|
|
81
|
+
elementsDirs.map(async (dirPath) => {
|
|
82
|
+
const dirExists = await isDirectory(dirPath);
|
|
83
|
+
if (!dirExists) {
|
|
84
|
+
return;
|
|
87
85
|
}
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
const files = await glob("**/*", { cwd: dirPath });
|
|
87
|
+
files.forEach((file) => {
|
|
88
|
+
const parts = path2.parse(file);
|
|
89
|
+
if (isJsFile(parts.base)) {
|
|
90
|
+
const fullPath = path2.join(dirPath, file);
|
|
91
|
+
const moduleId = fullPath.slice(rootDir.length);
|
|
92
|
+
elementMap[parts.name] = moduleId;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
})
|
|
96
|
+
);
|
|
90
97
|
}
|
|
91
98
|
async function getElementImport(tagname) {
|
|
92
99
|
if (!elementMap) {
|
|
@@ -139,12 +146,14 @@ function pluginRoot(options) {
|
|
|
139
146
|
deps.add(tagname);
|
|
140
147
|
}
|
|
141
148
|
const importUrls = [];
|
|
142
|
-
await Promise.all(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
await Promise.all(
|
|
150
|
+
Array.from(deps).map(async (tagname) => {
|
|
151
|
+
const importUrl = await getElementImport(tagname);
|
|
152
|
+
if (importUrl) {
|
|
153
|
+
importUrls.push(importUrl);
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
);
|
|
148
157
|
if (importUrls.length > 0) {
|
|
149
158
|
const importLines = importUrls.map((url) => `import '${url}';`).join("\n");
|
|
150
159
|
const code = `${src}
|
|
@@ -276,7 +285,7 @@ async function htmlMinify(html) {
|
|
|
276
285
|
|
|
277
286
|
// src/cli/commands/dev.ts
|
|
278
287
|
import glob2 from "tiny-glob";
|
|
279
|
-
var
|
|
288
|
+
var __dirname = path4.dirname(fileURLToPath(import.meta.url));
|
|
280
289
|
async function createServer(options) {
|
|
281
290
|
const app = express();
|
|
282
291
|
app.use(express.static("public"));
|
|
@@ -285,14 +294,14 @@ async function createServer(options) {
|
|
|
285
294
|
const port = parseInt(process.env.PORT || "4007");
|
|
286
295
|
console.log("\u{1F333} Root.js");
|
|
287
296
|
console.log();
|
|
288
|
-
console.log(`Started server: http://localhost:${port}`);
|
|
297
|
+
console.log(`Started dev server: http://localhost:${port}`);
|
|
289
298
|
app.listen(port);
|
|
290
299
|
}
|
|
291
300
|
async function getMiddlewares(options) {
|
|
292
301
|
const rootDir = (options == null ? void 0 : options.rootDir) || process.cwd();
|
|
293
302
|
const rootConfig = await loadRootConfig(rootDir);
|
|
294
303
|
const viteConfig = rootConfig.vite || {};
|
|
295
|
-
const renderModulePath = path4.resolve(
|
|
304
|
+
const renderModulePath = path4.resolve(__dirname, "./render.js");
|
|
296
305
|
const pages = [];
|
|
297
306
|
if (await isDirectory(path4.join(rootDir, "routes"))) {
|
|
298
307
|
const pageFiles = await glob2(path4.join(rootDir, "routes/**/*"));
|
|
@@ -325,6 +334,7 @@ async function getMiddlewares(options) {
|
|
|
325
334
|
}
|
|
326
335
|
const viteServer = await createViteServer({
|
|
327
336
|
...viteConfig,
|
|
337
|
+
mode: "development",
|
|
328
338
|
server: { middlewareMode: true },
|
|
329
339
|
appType: "custom",
|
|
330
340
|
optimizeDeps: {
|
|
@@ -341,20 +351,28 @@ async function getMiddlewares(options) {
|
|
|
341
351
|
});
|
|
342
352
|
const rootMiddleware = async (req, res, next) => {
|
|
343
353
|
const url = req.originalUrl;
|
|
344
|
-
|
|
345
|
-
const renderer = new render.Renderer(rootConfig);
|
|
354
|
+
let renderer = null;
|
|
346
355
|
try {
|
|
356
|
+
const render = await viteServer.ssrLoadModule(renderModulePath);
|
|
357
|
+
renderer = new render.Renderer(rootConfig);
|
|
347
358
|
const assetMap = new DevServerAssetMap(viteServer.moduleGraph);
|
|
348
359
|
const data = await renderer.render(url, {
|
|
349
360
|
assetMap
|
|
350
361
|
});
|
|
351
|
-
|
|
362
|
+
let html = await viteServer.transformIndexHtml(url, data.html || "");
|
|
363
|
+
if (rootConfig.minifyHtml !== false) {
|
|
364
|
+
html = await htmlMinify(html);
|
|
365
|
+
}
|
|
352
366
|
res.status(200).set({ "Content-Type": "text/html" }).end(html);
|
|
353
367
|
} catch (e) {
|
|
354
368
|
viteServer.ssrFixStacktrace(e);
|
|
355
369
|
try {
|
|
356
|
-
|
|
357
|
-
|
|
370
|
+
if (renderer) {
|
|
371
|
+
const { html } = await renderer.renderError(e);
|
|
372
|
+
res.status(500).set({ "Content-Type": "text/html" }).end(html);
|
|
373
|
+
} else {
|
|
374
|
+
next(e);
|
|
375
|
+
}
|
|
358
376
|
} catch (e2) {
|
|
359
377
|
console.error("failed to render custom error");
|
|
360
378
|
console.error(e2);
|
|
@@ -364,34 +382,32 @@ async function getMiddlewares(options) {
|
|
|
364
382
|
};
|
|
365
383
|
return [viteServer.middlewares, rootMiddleware];
|
|
366
384
|
}
|
|
367
|
-
function dev(rootDir) {
|
|
368
|
-
|
|
385
|
+
async function dev(rootDir) {
|
|
386
|
+
process.env.NODE_ENV = "development";
|
|
387
|
+
try {
|
|
388
|
+
await createServer({ rootDir });
|
|
389
|
+
} catch (err) {
|
|
390
|
+
console.error("an error occurred");
|
|
391
|
+
}
|
|
369
392
|
}
|
|
370
393
|
|
|
371
394
|
// src/cli/commands/build.ts
|
|
372
|
-
import
|
|
395
|
+
import path5 from "node:path";
|
|
373
396
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
374
397
|
import fsExtra2 from "fs-extra";
|
|
375
398
|
import glob3 from "tiny-glob";
|
|
376
399
|
import { build as viteBuild } from "vite";
|
|
377
400
|
|
|
378
401
|
// src/render/asset-map/build-asset-map.ts
|
|
379
|
-
import path5 from "path";
|
|
380
402
|
var BuildAssetMap = class {
|
|
381
|
-
constructor(
|
|
382
|
-
this.manifest = manifest;
|
|
383
|
-
this.elementMap = options.elementMap;
|
|
403
|
+
constructor() {
|
|
384
404
|
this.moduleIdToAsset = /* @__PURE__ */ new Map();
|
|
385
|
-
Object.keys(this.manifest).forEach((manifestKey) => {
|
|
386
|
-
const moduleId = `/${manifestKey}`;
|
|
387
|
-
this.moduleIdToAsset.set(moduleId, new BuildAsset(this, moduleId, this.manifest[manifestKey]));
|
|
388
|
-
});
|
|
389
405
|
}
|
|
390
406
|
async get(moduleId) {
|
|
391
407
|
return this.moduleIdToAsset.get(moduleId) || null;
|
|
392
408
|
}
|
|
393
|
-
|
|
394
|
-
|
|
409
|
+
add(asset) {
|
|
410
|
+
this.moduleIdToAsset.set(asset.moduleId, asset);
|
|
395
411
|
}
|
|
396
412
|
toJson() {
|
|
397
413
|
const result = {};
|
|
@@ -400,15 +416,46 @@ var BuildAssetMap = class {
|
|
|
400
416
|
}
|
|
401
417
|
return result;
|
|
402
418
|
}
|
|
419
|
+
static fromViteManifest(viteManifest, elementMap) {
|
|
420
|
+
const assetMap = new BuildAssetMap();
|
|
421
|
+
const elementModuleIds = /* @__PURE__ */ new Set();
|
|
422
|
+
Object.values(elementMap).forEach(
|
|
423
|
+
(moduleId) => elementModuleIds.add(moduleId)
|
|
424
|
+
);
|
|
425
|
+
Object.keys(viteManifest).forEach((manifestKey) => {
|
|
426
|
+
const moduleId = `/${manifestKey}`;
|
|
427
|
+
const manifestChunk = viteManifest[manifestKey];
|
|
428
|
+
const isElement = elementModuleIds.has(moduleId);
|
|
429
|
+
const assetData = {
|
|
430
|
+
moduleId,
|
|
431
|
+
assetUrl: `/${manifestChunk.file}`,
|
|
432
|
+
importedModules: (manifestChunk.imports || []).map(
|
|
433
|
+
(relPath) => `/${relPath}`
|
|
434
|
+
),
|
|
435
|
+
importedCss: (manifestChunk.css || []).map((relPath) => `/${relPath}`),
|
|
436
|
+
isElement
|
|
437
|
+
};
|
|
438
|
+
assetMap.add(new BuildAsset(assetMap, assetData));
|
|
439
|
+
});
|
|
440
|
+
return assetMap;
|
|
441
|
+
}
|
|
442
|
+
static fromRootManifest(rootManifest) {
|
|
443
|
+
const assetMap = new BuildAssetMap();
|
|
444
|
+
Object.keys(rootManifest).forEach((moduleId) => {
|
|
445
|
+
const assetData = rootManifest[moduleId];
|
|
446
|
+
assetMap.add(new BuildAsset(assetMap, assetData));
|
|
447
|
+
});
|
|
448
|
+
return assetMap;
|
|
449
|
+
}
|
|
403
450
|
};
|
|
404
451
|
var BuildAsset = class {
|
|
405
|
-
constructor(assetMap,
|
|
452
|
+
constructor(assetMap, assetData) {
|
|
406
453
|
this.assetMap = assetMap;
|
|
407
|
-
this.moduleId = moduleId;
|
|
408
|
-
this.
|
|
409
|
-
this.
|
|
410
|
-
this.
|
|
411
|
-
this.
|
|
454
|
+
this.moduleId = assetData.moduleId;
|
|
455
|
+
this.assetUrl = assetData.assetUrl;
|
|
456
|
+
this.importedModules = assetData.importedModules;
|
|
457
|
+
this.importedCss = assetData.importedCss;
|
|
458
|
+
this.isElement = assetData.isElement;
|
|
412
459
|
}
|
|
413
460
|
async getCssDeps() {
|
|
414
461
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -433,14 +480,15 @@ var BuildAsset = class {
|
|
|
433
480
|
return;
|
|
434
481
|
}
|
|
435
482
|
visited.add(asset.moduleId);
|
|
436
|
-
|
|
437
|
-
if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && this.assetMap.isElement(asset.moduleId)) {
|
|
483
|
+
if (asset.isElement) {
|
|
438
484
|
urls.add(asset.assetUrl);
|
|
439
485
|
}
|
|
440
|
-
await Promise.all(
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
486
|
+
await Promise.all(
|
|
487
|
+
asset.importedModules.map(async (moduleId) => {
|
|
488
|
+
const importedAsset = await this.assetMap.get(moduleId);
|
|
489
|
+
this.collectJs(importedAsset, urls, visited);
|
|
490
|
+
})
|
|
491
|
+
);
|
|
444
492
|
}
|
|
445
493
|
async collectCss(asset, urls, visited) {
|
|
446
494
|
if (!asset) {
|
|
@@ -456,47 +504,52 @@ var BuildAsset = class {
|
|
|
456
504
|
if (asset.importedCss) {
|
|
457
505
|
asset.importedCss.forEach((cssUrl) => urls.add(cssUrl));
|
|
458
506
|
}
|
|
459
|
-
await Promise.all(
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
507
|
+
await Promise.all(
|
|
508
|
+
asset.importedModules.map(async (moduleId) => {
|
|
509
|
+
const importedAsset = await this.assetMap.get(moduleId);
|
|
510
|
+
this.collectCss(importedAsset, urls, visited);
|
|
511
|
+
})
|
|
512
|
+
);
|
|
463
513
|
}
|
|
464
514
|
toJson() {
|
|
465
515
|
return {
|
|
466
516
|
moduleId: this.moduleId,
|
|
467
517
|
assetUrl: this.assetUrl,
|
|
468
518
|
importedModules: this.importedModules,
|
|
469
|
-
importedCss: this.importedCss
|
|
519
|
+
importedCss: this.importedCss,
|
|
520
|
+
isElement: this.isElement
|
|
470
521
|
};
|
|
471
522
|
}
|
|
472
523
|
};
|
|
473
524
|
|
|
474
525
|
// src/cli/commands/build.ts
|
|
475
|
-
var
|
|
526
|
+
var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
|
|
476
527
|
async function build(rootProjectDir) {
|
|
477
528
|
var _a;
|
|
478
529
|
console.log("\u{1F333} Root.js");
|
|
479
530
|
const rootDir = rootProjectDir || process.cwd();
|
|
480
531
|
const rootConfig = await loadRootConfig(rootDir);
|
|
481
|
-
const distDir =
|
|
532
|
+
const distDir = path5.join(rootDir, "dist");
|
|
482
533
|
await rmDir(distDir);
|
|
483
534
|
await makeDir(distDir);
|
|
484
535
|
const pages = [];
|
|
485
|
-
if (await isDirectory(
|
|
486
|
-
const pageFiles = await glob3(
|
|
536
|
+
if (await isDirectory(path5.join(rootDir, "routes"))) {
|
|
537
|
+
const pageFiles = await glob3(path5.join(rootDir, "routes/**/*"));
|
|
487
538
|
pageFiles.forEach((file) => {
|
|
488
|
-
const parts =
|
|
539
|
+
const parts = path5.parse(file);
|
|
489
540
|
if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
|
|
490
541
|
pages.push(file);
|
|
491
542
|
}
|
|
492
543
|
});
|
|
493
544
|
}
|
|
494
|
-
const elementsDirs = [
|
|
545
|
+
const elementsDirs = [path5.join(rootDir, "elements")];
|
|
495
546
|
const elementsInclude = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
|
|
496
547
|
for (const dirPath of elementsInclude) {
|
|
497
|
-
const elementsDir =
|
|
548
|
+
const elementsDir = path5.resolve(rootDir, dirPath);
|
|
498
549
|
if (!elementsDir.startsWith(rootDir)) {
|
|
499
|
-
throw new Error(
|
|
550
|
+
throw new Error(
|
|
551
|
+
`the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`
|
|
552
|
+
);
|
|
500
553
|
}
|
|
501
554
|
elementsDirs.push(elementsDir);
|
|
502
555
|
}
|
|
@@ -506,9 +559,9 @@ async function build(rootProjectDir) {
|
|
|
506
559
|
if (await isDirectory(dirPath)) {
|
|
507
560
|
const elementFiles = await glob3("**/*", { cwd: dirPath });
|
|
508
561
|
elementFiles.forEach((file) => {
|
|
509
|
-
const parts =
|
|
562
|
+
const parts = path5.parse(file);
|
|
510
563
|
if (isJsFile(parts.base)) {
|
|
511
|
-
const fullPath =
|
|
564
|
+
const fullPath = path5.join(dirPath, file);
|
|
512
565
|
const moduleId = fullPath.slice(rootDir.length);
|
|
513
566
|
elements.push(fullPath);
|
|
514
567
|
elementMap[parts.name] = moduleId;
|
|
@@ -517,10 +570,10 @@ async function build(rootProjectDir) {
|
|
|
517
570
|
}
|
|
518
571
|
}
|
|
519
572
|
const bundleScripts = [];
|
|
520
|
-
if (await isDirectory(
|
|
521
|
-
const bundleFiles = await glob3(
|
|
573
|
+
if (await isDirectory(path5.join(rootDir, "bundles"))) {
|
|
574
|
+
const bundleFiles = await glob3(path5.join(rootDir, "bundles/*"));
|
|
522
575
|
bundleFiles.forEach((file) => {
|
|
523
|
-
const parts =
|
|
576
|
+
const parts = path5.parse(file);
|
|
524
577
|
if (isJsFile(parts.base)) {
|
|
525
578
|
bundleScripts.push(file);
|
|
526
579
|
}
|
|
@@ -543,14 +596,14 @@ async function build(rootProjectDir) {
|
|
|
543
596
|
publicDir: false,
|
|
544
597
|
build: {
|
|
545
598
|
rollupOptions: {
|
|
546
|
-
input: [
|
|
599
|
+
input: [path5.resolve(__dirname2, "./render.js")],
|
|
547
600
|
output: {
|
|
548
601
|
format: "esm",
|
|
549
602
|
chunkFileNames: "chunks/[name].[hash].js",
|
|
550
603
|
assetFileNames: "assets/[name].[hash][extname]"
|
|
551
604
|
}
|
|
552
605
|
},
|
|
553
|
-
outDir:
|
|
606
|
+
outDir: path5.join(distDir, "server"),
|
|
554
607
|
ssr: true,
|
|
555
608
|
ssrManifest: false,
|
|
556
609
|
cssCodeSplit: true,
|
|
@@ -576,7 +629,7 @@ async function build(rootProjectDir) {
|
|
|
576
629
|
assetFileNames: "assets/[name].[hash][extname]"
|
|
577
630
|
}
|
|
578
631
|
},
|
|
579
|
-
outDir:
|
|
632
|
+
outDir: path5.join(distDir, "client"),
|
|
580
633
|
ssr: false,
|
|
581
634
|
ssrManifest: false,
|
|
582
635
|
manifest: true,
|
|
@@ -587,41 +640,93 @@ async function build(rootProjectDir) {
|
|
|
587
640
|
reportCompressedSize: false
|
|
588
641
|
}
|
|
589
642
|
});
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
|
|
643
|
+
const viteManifest = await loadJson(
|
|
644
|
+
path5.join(distDir, "client/manifest.json")
|
|
645
|
+
);
|
|
646
|
+
const assetMap = BuildAssetMap.fromViteManifest(viteManifest, elementMap);
|
|
647
|
+
writeFile(
|
|
648
|
+
path5.join(distDir, "client/root-manifest.json"),
|
|
649
|
+
JSON.stringify(assetMap.toJson(), null, 2)
|
|
650
|
+
);
|
|
651
|
+
const buildDir = path5.join(distDir, "html");
|
|
652
|
+
const publicDir = path5.join(rootDir, "public");
|
|
653
|
+
if (fsExtra2.existsSync(path5.join(rootDir, "public"))) {
|
|
596
654
|
fsExtra2.copySync(publicDir, buildDir);
|
|
597
655
|
} else {
|
|
598
656
|
makeDir(buildDir);
|
|
599
657
|
}
|
|
600
|
-
copyDir(
|
|
601
|
-
copyDir(
|
|
602
|
-
const render = await import(
|
|
658
|
+
copyDir(path5.join(distDir, "client/assets"), path5.join(buildDir, "assets"));
|
|
659
|
+
copyDir(path5.join(distDir, "client/chunks"), path5.join(buildDir, "chunks"));
|
|
660
|
+
const render = await import(path5.join(distDir, "server/render.js"));
|
|
603
661
|
const renderer = new render.Renderer(rootConfig);
|
|
604
662
|
const sitemap = await renderer.getSitemap();
|
|
605
|
-
await Promise.all(
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
663
|
+
await Promise.all(
|
|
664
|
+
Object.keys(sitemap).map(async (urlPath) => {
|
|
665
|
+
const { route, params } = sitemap[urlPath];
|
|
666
|
+
const data = await renderer.renderRoute(route, {
|
|
667
|
+
assetMap,
|
|
668
|
+
routeParams: params
|
|
669
|
+
});
|
|
670
|
+
let outPath = path5.join(distDir, `html${urlPath}`, "index.html");
|
|
671
|
+
if (outPath.endsWith("404/index.html")) {
|
|
672
|
+
outPath = outPath.replace("404/index.html", "404.html");
|
|
673
|
+
}
|
|
674
|
+
const html = await htmlMinify(data.html || "");
|
|
675
|
+
await writeFile(outPath, html);
|
|
676
|
+
const relPath = outPath.slice(path5.dirname(distDir).length + 1);
|
|
677
|
+
console.log(`saved ${relPath}`);
|
|
678
|
+
})
|
|
679
|
+
);
|
|
620
680
|
}
|
|
621
681
|
|
|
622
682
|
// src/cli/commands/start.ts
|
|
623
|
-
|
|
624
|
-
|
|
683
|
+
import path6 from "node:path";
|
|
684
|
+
import { default as express2 } from "express";
|
|
685
|
+
async function start(rootProjectDir) {
|
|
686
|
+
console.log("\u{1F333} Root.js");
|
|
687
|
+
process.env.NODE_ENV = "production";
|
|
688
|
+
const rootDir = rootProjectDir || process.cwd();
|
|
689
|
+
const rootConfig = await loadRootConfig(rootDir);
|
|
690
|
+
const distDir = path6.join(rootDir, "dist");
|
|
691
|
+
const render = await import(path6.join(distDir, "server/render.js"));
|
|
692
|
+
const renderer = new render.Renderer(rootConfig);
|
|
693
|
+
const manifestPath = path6.join(distDir, "client/root-manifest.json");
|
|
694
|
+
if (!await fileExists(manifestPath)) {
|
|
695
|
+
throw new Error(
|
|
696
|
+
`could not find ${manifestPath}. run \`root build\` before \`root start\`.`
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
const rootManifest = await loadJson(manifestPath);
|
|
700
|
+
const assetMap = BuildAssetMap.fromRootManifest(rootManifest);
|
|
701
|
+
const app = express2();
|
|
702
|
+
const publicDir = path6.join(distDir, "html");
|
|
703
|
+
app.use(express2.static(publicDir));
|
|
704
|
+
app.use(async (req, res, next) => {
|
|
705
|
+
try {
|
|
706
|
+
const url = req.originalUrl;
|
|
707
|
+
const data = await renderer.render(url, {
|
|
708
|
+
assetMap
|
|
709
|
+
});
|
|
710
|
+
let html = data.html || "";
|
|
711
|
+
if (rootConfig.minifyHtml !== false) {
|
|
712
|
+
html = await htmlMinify(html);
|
|
713
|
+
}
|
|
714
|
+
res.status(200).set({ "Content-Type": "text/html" }).end(html);
|
|
715
|
+
} catch (e) {
|
|
716
|
+
try {
|
|
717
|
+
const { html } = await renderer.renderError(e);
|
|
718
|
+
res.status(500).set({ "Content-Type": "text/html" }).end(html);
|
|
719
|
+
} catch (e2) {
|
|
720
|
+
console.error("failed to render custom error");
|
|
721
|
+
console.error(e2);
|
|
722
|
+
next(e);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
const port = parseInt(process.env.PORT || "4007");
|
|
727
|
+
console.log(`
|
|
728
|
+
Started prod server: http://localhost:${port}`);
|
|
729
|
+
app.listen(port);
|
|
625
730
|
}
|
|
626
731
|
export {
|
|
627
732
|
build,
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/dev.ts","../src/render/vite-plugin-root.ts","../src/core/fsutils.ts","../src/render/asset-map/dev-asset-map.ts","../src/cli/load-config.ts","../src/render/html-minify.ts","../src/cli/commands/build.ts","../src/render/asset-map/build-asset-map.ts","../src/cli/commands/start.ts"],"sourcesContent":["import path from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport {default as express, Request, Response, NextFunction} from 'express';\nimport {createServer as createViteServer} from 'vite';\nimport {pluginRoot} from '../../render/vite-plugin-root.js';\nimport {DevServerAssetMap} from '../../render/asset-map/dev-asset-map.js';\nimport {loadRootConfig} from '../load-config.js';\nimport {htmlMinify} from '../../render/html-minify.js';\nimport {Renderer} from '../../render/render.js';\nimport {isDirectory, isJsFile} from '../../core/fsutils.js';\nimport glob from 'tiny-glob';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport async function createServer(options?: {rootDir?: string}) {\n const app = express();\n\n app.use(express.static('public'));\n const middlewares = await getMiddlewares({rootDir: options?.rootDir});\n middlewares.forEach((middleware) => app.use(middleware));\n\n const port = parseInt(process.env.PORT || '4007');\n console.log('🌳 Root.js');\n console.log();\n console.log(`Started server: http://localhost:${port}`);\n app.listen(port);\n}\n\nexport async function getMiddlewares(options?: {rootDir?: string}) {\n const rootDir = options?.rootDir || process.cwd();\n const rootConfig = await loadRootConfig(rootDir);\n const viteConfig = rootConfig.vite || {};\n const renderModulePath = path.resolve(__dirname, './render.js');\n\n const pages: string[] = [];\n if (await isDirectory(path.join(rootDir, 'routes'))) {\n const pageFiles = await glob(path.join(rootDir, 'routes/**/*'));\n pageFiles.forEach((file) => {\n const parts = path.parse(file);\n if (!parts.name.startsWith('_') && isJsFile(parts.base)) {\n pages.push(file);\n }\n });\n }\n\n const elements: string[] = [];\n if (await isDirectory(path.join(rootDir, 'elements'))) {\n const elementFiles = await glob(path.join(rootDir, 'elements/**/*'));\n elementFiles.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n elements.push(file);\n }\n });\n }\n\n const bundleScripts: string[] = [];\n if (await isDirectory(path.join(rootDir, 'bundles'))) {\n const bundleFiles = await glob(path.join(rootDir, 'bundles/*'));\n bundleFiles.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n bundleScripts.push(file);\n }\n });\n }\n\n const viteServer = await createViteServer({\n ...viteConfig,\n server: {middlewareMode: true},\n appType: 'custom',\n optimizeDeps: {\n include: [...pages, ...elements, ...bundleScripts],\n },\n ssr: {\n noExternal: ['@blinkk/root'],\n },\n esbuild: {\n jsx: 'automatic',\n jsxImportSource: 'preact',\n },\n plugins: [...(viteConfig.plugins || []), pluginRoot({rootDir, rootConfig})],\n });\n\n const rootMiddleware = async (\n req: Request,\n res: Response,\n next: NextFunction\n ) => {\n const url = req.originalUrl;\n const render = await viteServer.ssrLoadModule(renderModulePath);\n const renderer = new render.Renderer(rootConfig) as Renderer;\n try {\n // Create a dev asset map using Vite dev server's module graph.\n const assetMap = new DevServerAssetMap(viteServer.moduleGraph);\n const data = await renderer.render(url, {\n assetMap: assetMap,\n });\n // Inject the Vite HMR client.\n const html = await htmlMinify(\n await viteServer.transformIndexHtml(url, data.html || '')\n );\n\n res.status(200).set({'Content-Type': 'text/html'}).end(html);\n } catch (e) {\n // If an error is caught, let Vite fix the stack trace so it maps back to\n // your actual source code.\n viteServer.ssrFixStacktrace(e);\n try {\n const {html} = await renderer.renderError(e);\n res.status(500).set({'Content-Type': 'text/html'}).end(html);\n } catch (e2) {\n console.error('failed to render custom error');\n console.error(e2);\n next(e);\n }\n }\n };\n\n return [viteServer.middlewares, rootMiddleware];\n}\n\nexport function dev(rootDir?: string) {\n createServer({rootDir});\n}\n","import path from 'path';\nimport glob from 'tiny-glob';\nimport {RootConfig} from '../core/config';\nimport {isDirectory, isJsFile} from '../core/fsutils';\n\nconst JSX_ELEMENTS_REGEX = /jsxs?\\(\"(\\w[\\w-]+\\w)\"/g;\nconst HTML_ELEMENTS_REGEX = /<(\\w[\\w-]+\\w)/g;\n\nexport interface RootPluginOptions {\n rootDir: string;\n rootConfig: RootConfig;\n}\n\nexport function pluginRoot(options?: RootPluginOptions) {\n const elementsVirtualId = 'virtual:root-elements';\n const resolvedElementsVirtualId = '\\0' + elementsVirtualId;\n\n const rootDir = options?.rootDir || process.cwd();\n const rootConfig = options?.rootConfig || {};\n const elementsDirs = [path.join(rootDir, 'elements')];\n const includeDirs = rootConfig.elements?.include || [];\n includeDirs.forEach((dirPath) => {\n const elementsDir = path.resolve(rootDir, dirPath);\n if (!elementsDir.startsWith(rootDir)) {\n throw new Error(\n `the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`\n );\n }\n elementsDirs.push(elementsDir);\n });\n\n let elementMap: Record<string, string>;\n async function updateElementMap() {\n elementMap = {};\n await Promise.all(\n elementsDirs.map(async (dirPath: string) => {\n const dirExists = await isDirectory(dirPath);\n if (!dirExists) {\n return;\n }\n const files = await glob('**/*', {cwd: dirPath});\n files.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n const fullPath = path.join(dirPath, file);\n const moduleId = fullPath.slice(rootDir.length);\n elementMap[parts.name] = moduleId;\n }\n });\n })\n );\n }\n\n async function getElementImport(tagname: string): Promise<string | null> {\n if (!elementMap) {\n await updateElementMap();\n }\n if (tagname in elementMap) {\n return elementMap[tagname];\n }\n return null;\n }\n\n function isCustomElement(id: string) {\n if (!isJsFile(id)) {\n return false;\n }\n return elementsDirs.some((elementsDir) => {\n return id.startsWith(elementsDir);\n });\n }\n\n return {\n name: 'vite-plugin-root',\n\n resolveId(id: string) {\n if (id === elementsVirtualId) {\n return resolvedElementsVirtualId;\n }\n return null;\n },\n\n async load(id: string) {\n if (id === resolvedElementsVirtualId) {\n await updateElementMap();\n return `export const elementsMap = ${JSON.stringify(elementMap)}`;\n }\n return null;\n },\n\n async transform(src: string, id: string): Promise<any> {\n if (isCustomElement(id)) {\n const idParts = path.parse(id);\n const deps = new Set<string>();\n const tagnames = [\n ...src.matchAll(JSX_ELEMENTS_REGEX),\n ...src.matchAll(HTML_ELEMENTS_REGEX),\n ];\n for (const match of tagnames) {\n const tagname = match[1];\n // All custom elements should contain a dash.\n if (!tagname.includes('-')) {\n continue;\n }\n // Avoid circular deps.\n if (tagname === idParts.name) {\n continue;\n }\n deps.add(tagname);\n }\n const importUrls: string[] = [];\n await Promise.all(\n Array.from(deps).map(async (tagname) => {\n const importUrl = await getElementImport(tagname);\n if (importUrl) {\n importUrls.push(importUrl);\n }\n })\n );\n if (importUrls.length > 0) {\n const importLines = importUrls\n .map((url) => `import '${url}';`)\n .join('\\n');\n const code = `${src}\n\n// autogenerated by root:\n${importLines}\n`;\n return {code};\n }\n return null;\n }\n return null;\n },\n };\n}\n","import {promises as fs} from 'node:fs';\nimport path from 'node:path';\nimport fsExtra from 'fs-extra';\n\nexport function isJsFile(filename: string) {\n return !!filename.match(/\\.(j|t)sx?$/);\n}\n\nexport async function writeFile(filepath: string, content: string) {\n const dirPath = path.dirname(filepath);\n await makeDir(dirPath);\n await fs.writeFile(filepath, content);\n}\n\nexport async function makeDir(dirpath: string) {\n try {\n await fs.access(dirpath);\n } catch (e) {\n await fs.mkdir(dirpath, {recursive: true});\n }\n}\n\nexport async function copyDir(srcdir: string, dstdir: string) {\n if (!fsExtra.existsSync(srcdir)) {\n return;\n }\n fsExtra.copySync(srcdir, dstdir, {recursive: true, overwrite: true});\n}\n\nexport async function rmDir(dirpath: string) {\n await fs.rm(dirpath, {recursive: true, force: true});\n}\n\nexport async function loadJson<T = unknown>(filepath: string): Promise<T> {\n const content = await fs.readFile(filepath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport async function isDirectory(dirpath: string) {\n return fs\n .stat(dirpath)\n .then((fsStat) => {\n return fsStat.isDirectory();\n })\n .catch((err) => {\n if (err.code === 'ENOENT') {\n return false;\n }\n throw err;\n });\n}\n\nexport function fileExists(filepath: string): Promise<boolean> {\n return fs\n .access(filepath)\n .then(() => true)\n .catch(() => false);\n}\n","import path from 'node:path';\nimport {ModuleGraph, ModuleNode} from 'vite';\nimport {Asset, AssetMap} from './asset-map';\n\nexport class DevServerAssetMap implements AssetMap {\n private moduleGraph: ModuleGraph;\n\n constructor(moduleGraph: ModuleGraph) {\n this.moduleGraph = moduleGraph;\n }\n\n async get(moduleId: string): Promise<Asset | null> {\n const viteModule = await this.moduleGraph.getModuleByUrl(moduleId);\n if (!viteModule || !viteModule.id) {\n return null;\n }\n return new DevServerAsset(this, viteModule);\n }\n}\n\nexport class DevServerAsset implements Asset {\n moduleId: string;\n assetUrl: string;\n private assetMap: AssetMap;\n private viteModule: ModuleNode;\n\n constructor(assetMap: AssetMap, viteModule: ModuleNode) {\n this.assetMap = assetMap;\n this.viteModule = viteModule;\n this.moduleId = this.viteModule.id!;\n this.assetUrl = this.viteModule.url;\n }\n\n async getCssDeps(): Promise<string[]> {\n const visited = new Set<string>();\n const deps = new Set<string>();\n this.collectCss(this, deps, visited);\n return Array.from(deps);\n }\n\n async getJsDeps(): Promise<string[]> {\n const visited = new Set<string>();\n const deps = new Set<string>();\n this.collectJs(this, deps, visited);\n return Array.from(deps);\n }\n\n getImportedModules() {\n return this.viteModule.importedModules;\n }\n\n private collectJs(\n asset: DevServerAsset | null,\n urls: Set<string>,\n visited: Set<string>\n ) {\n if (!asset) {\n return;\n }\n if (!asset.moduleId) {\n return;\n }\n if (visited.has(asset.moduleId)) {\n return;\n }\n visited.add(asset.moduleId);\n const parts = path.parse(asset.assetUrl);\n if (\n ['.js', '.jsx', '.ts', '.tsx'].includes(parts.ext) &&\n asset.moduleId.includes('/elements/')\n ) {\n urls.add(asset.assetUrl);\n }\n asset.getImportedModules().forEach((viteModule) => {\n if (viteModule.id) {\n const importedAsset = new DevServerAsset(this.assetMap, viteModule);\n this.collectJs(importedAsset, urls, visited);\n }\n });\n }\n\n private collectCss(\n asset: DevServerAsset | null,\n urls: Set<string>,\n visited: Set<string>\n ) {\n if (!asset) {\n return;\n }\n if (!asset.assetUrl) {\n return;\n }\n if (visited.has(asset.assetUrl)) {\n return;\n }\n visited.add(asset.assetUrl);\n if (asset.moduleId.endsWith('.scss')) {\n const parts = path.parse(asset.assetUrl);\n if (!parts.name.startsWith('_')) {\n urls.add(asset.assetUrl);\n }\n }\n asset.getImportedModules().forEach((viteModule) => {\n if (viteModule.id) {\n const importedAsset = new DevServerAsset(this.assetMap, viteModule);\n this.collectCss(importedAsset, urls, visited);\n }\n });\n }\n}\n","import {bundleRequire} from 'bundle-require';\nimport JoyCon from 'joycon';\nimport {RootConfig} from '../core/config';\n\nexport async function loadRootConfig(rootDir: string): Promise<RootConfig> {\n const joycon = new JoyCon();\n const configPath = await joycon.resolve({\n cwd: rootDir,\n files: ['root.config.ts'],\n });\n if (configPath) {\n const configBundle = await bundleRequire({\n filepath: configPath,\n });\n return configBundle.mod.default || {};\n }\n return {};\n}\n","import {minify} from 'html-minifier-terser';\n\nexport async function htmlMinify(html: string): Promise<string> {\n const min = await minify(html, {\n collapseWhitespace: true,\n removeComments: true,\n preserveLineBreaks: true,\n });\n return min.trimStart();\n}\n","import path from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport fsExtra from 'fs-extra';\nimport glob from 'tiny-glob';\nimport {build as viteBuild, Manifest, UserConfig} from 'vite';\nimport {pluginRoot} from '../../render/vite-plugin-root.js';\nimport {BuildAssetMap} from '../../render/asset-map/build-asset-map.js';\nimport {loadRootConfig} from '../load-config.js';\nimport {\n copyDir,\n isDirectory,\n isJsFile,\n loadJson,\n makeDir,\n rmDir,\n writeFile,\n} from '../../core/fsutils.js';\nimport {Renderer} from '../../render/render.js';\nimport {htmlMinify} from '../../render/html-minify.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport async function build(rootProjectDir?: string) {\n console.log('🌳 Root.js');\n\n const rootDir = rootProjectDir || process.cwd();\n const rootConfig = await loadRootConfig(rootDir);\n const distDir = path.join(rootDir, 'dist');\n await rmDir(distDir);\n await makeDir(distDir);\n\n const pages: string[] = [];\n if (await isDirectory(path.join(rootDir, 'routes'))) {\n const pageFiles = await glob(path.join(rootDir, 'routes/**/*'));\n pageFiles.forEach((file) => {\n const parts = path.parse(file);\n if (!parts.name.startsWith('_') && isJsFile(parts.base)) {\n pages.push(file);\n }\n });\n }\n\n const elementsDirs = [path.join(rootDir, 'elements')];\n const elementsInclude = rootConfig.elements?.include || [];\n for (const dirPath of elementsInclude) {\n const elementsDir = path.resolve(rootDir, dirPath);\n if (!elementsDir.startsWith(rootDir)) {\n throw new Error(\n `the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`\n );\n }\n elementsDirs.push(elementsDir);\n }\n const elements: string[] = [];\n const elementMap: Record<string, string> = {};\n for (const dirPath of elementsDirs) {\n if (await isDirectory(dirPath)) {\n const elementFiles = await glob('**/*', {cwd: dirPath});\n elementFiles.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n const fullPath = path.join(dirPath, file);\n const moduleId = fullPath.slice(rootDir.length);\n elements.push(fullPath);\n elementMap[parts.name] = moduleId;\n }\n });\n }\n }\n\n const bundleScripts: string[] = [];\n if (await isDirectory(path.join(rootDir, 'bundles'))) {\n const bundleFiles = await glob(path.join(rootDir, 'bundles/*'));\n bundleFiles.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n bundleScripts.push(file);\n }\n });\n }\n\n const viteConfig = rootConfig.vite || {};\n const baseConfig: UserConfig = {\n ...viteConfig,\n root: rootDir,\n esbuild: {\n jsx: 'automatic',\n jsxImportSource: 'preact',\n treeShaking: true,\n },\n plugins: [...(viteConfig.plugins || []), pluginRoot({rootDir, rootConfig})],\n };\n\n // Bundle the render.js file with vite, which is pre-optimized for rendering\n // HTML routes.\n await viteBuild({\n ...baseConfig,\n mode: 'production',\n publicDir: false,\n build: {\n rollupOptions: {\n input: [path.resolve(__dirname, './render.js')],\n output: {\n format: 'esm',\n chunkFileNames: 'chunks/[name].[hash].js',\n assetFileNames: 'assets/[name].[hash][extname]',\n },\n },\n outDir: path.join(distDir, 'server'),\n ssr: true,\n ssrManifest: false,\n cssCodeSplit: true,\n target: 'esnext',\n minify: false,\n polyfillModulePreload: false,\n reportCompressedSize: false,\n },\n ssr: {\n noExternal: ['@blinkk/root'],\n },\n });\n\n // Pre-render any client scripts and CSS deps.\n await viteBuild({\n ...baseConfig,\n mode: 'production',\n publicDir: false,\n build: {\n rollupOptions: {\n input: [...pages, ...elements, ...bundleScripts],\n output: {\n format: 'esm',\n chunkFileNames: 'chunks/[name].[hash].js',\n assetFileNames: 'assets/[name].[hash][extname]',\n },\n },\n outDir: path.join(distDir, 'client'),\n ssr: false,\n ssrManifest: false,\n manifest: true,\n cssCodeSplit: true,\n target: 'esnext',\n minify: true,\n polyfillModulePreload: false,\n reportCompressedSize: false,\n },\n });\n\n const manifest = await loadJson<Manifest>(\n path.join(distDir, 'client/manifest.json')\n );\n\n // Use the output of the client build to generate an asset map, which is used\n // by the renderer for automatically injecting dependencies for a page.\n const assetMap = new BuildAssetMap(manifest, {elementMap});\n\n // Save the asset map to `dist/client` for use by the prod SSR server.\n writeFile(\n path.join(distDir, 'client/root-manifest.json'),\n JSON.stringify(assetMap.toJson(), null, 2)\n );\n\n // Write SSG output to `dist/html`.\n const buildDir = path.join(distDir, 'html');\n\n // Recursively copy files from `public` to `dist/html`.\n const publicDir = path.join(rootDir, 'public');\n if (fsExtra.existsSync(path.join(rootDir, 'public'))) {\n fsExtra.copySync(publicDir, buildDir);\n } else {\n makeDir(buildDir);\n }\n\n // Copy files from `dist/client/{assets,chunks}` to `dist/html`.\n copyDir(path.join(distDir, 'client/assets'), path.join(buildDir, 'assets'));\n copyDir(path.join(distDir, 'client/chunks'), path.join(buildDir, 'chunks'));\n\n // Render HTML pages.\n const render = await import(path.join(distDir, 'server/render.js'));\n const renderer = new render.Renderer(rootConfig) as Renderer;\n const sitemap = await renderer.getSitemap();\n\n await Promise.all(\n Object.keys(sitemap).map(async (urlPath) => {\n const {route, params} = sitemap[urlPath];\n const data = await renderer.renderRoute(route, {\n assetMap,\n routeParams: params,\n });\n\n // The renderer currently assumes that all paths serve HTML.\n // TODO(stevenle): support non-HTML routes using `routes/[name].[ext].ts`.\n let outPath = path.join(distDir, `html${urlPath}`, 'index.html');\n\n if (outPath.endsWith('404/index.html')) {\n outPath = outPath.replace('404/index.html', '404.html');\n }\n\n const html = await htmlMinify(data.html || '');\n await writeFile(outPath, html);\n\n const relPath = outPath.slice(path.dirname(distDir).length + 1);\n console.log(`saved ${relPath}`);\n })\n );\n}\n","import path from 'path';\nimport {Manifest, ManifestChunk} from 'vite';\nimport {Asset, AssetMap} from './asset-map';\n\ntype BuildAssetManifest = Record<\n string,\n {\n moduleId: string;\n assetUrl: string;\n importedModules: string[];\n importedCss: string[];\n }\n>;\n\nexport class BuildAssetMap implements AssetMap {\n private manifest: Manifest;\n private moduleIdToAsset: Map<string, BuildAsset>;\n private elementMap: Record<string, string>;\n\n constructor(\n manifest: Manifest,\n options: {elementMap: Record<string, string>}\n ) {\n this.manifest = manifest;\n this.elementMap = options.elementMap;\n this.moduleIdToAsset = new Map();\n Object.keys(this.manifest).forEach((manifestKey) => {\n const moduleId = `/${manifestKey}`;\n this.moduleIdToAsset.set(\n moduleId,\n new BuildAsset(this, moduleId, this.manifest[manifestKey])\n );\n });\n }\n\n async get(moduleId: string): Promise<Asset | null> {\n return this.moduleIdToAsset.get(moduleId) || null;\n }\n\n isElement(moduleId: string): boolean {\n return Object.values(this.elementMap).includes(moduleId);\n }\n\n toJson(): BuildAssetManifest {\n const result: BuildAssetManifest = {};\n for (const moduleId of this.moduleIdToAsset.keys()) {\n result[moduleId] = this.moduleIdToAsset.get(moduleId)!.toJson();\n }\n return result;\n }\n}\n\nexport class BuildAsset {\n moduleId: string;\n assetUrl: string;\n private assetMap: BuildAssetMap;\n private manifestData: ManifestChunk;\n private importedModules: string[];\n private importedCss: string[];\n\n constructor(\n assetMap: BuildAssetMap,\n moduleId: string,\n manifestData: ManifestChunk\n ) {\n this.assetMap = assetMap;\n this.moduleId = moduleId;\n this.manifestData = manifestData;\n this.assetUrl = `/${manifestData.file}`;\n this.importedModules = (this.manifestData.imports || []).map(\n (relPath) => `/${relPath}`\n );\n this.importedCss = (this.manifestData.css || []).map(\n (relPath) => `/${relPath}`\n );\n }\n\n async getCssDeps(): Promise<string[]> {\n const visited = new Set<string>();\n const deps = new Set<string>();\n await this.collectCss(this, deps, visited);\n return Array.from(deps);\n }\n\n async getJsDeps(): Promise<string[]> {\n const visited = new Set<string>();\n const deps = new Set<string>();\n await this.collectJs(this, deps, visited);\n return Array.from(deps);\n }\n\n private async collectJs(\n asset: BuildAsset | null,\n urls: Set<string>,\n visited: Set<string>\n ) {\n if (!asset) {\n return;\n }\n if (!asset.moduleId) {\n return;\n }\n if (visited.has(asset.moduleId)) {\n return;\n }\n visited.add(asset.moduleId);\n const parts = path.parse(asset.assetUrl);\n if (\n ['.js', '.jsx', '.ts', '.tsx'].includes(parts.ext) &&\n this.assetMap.isElement(asset.moduleId)\n ) {\n urls.add(asset.assetUrl);\n }\n await Promise.all(\n asset.importedModules.map(async (moduleId) => {\n const importedAsset = (await this.assetMap.get(moduleId)) as BuildAsset;\n this.collectJs(importedAsset, urls, visited);\n })\n );\n }\n\n private async collectCss(\n asset: BuildAsset | null,\n urls: Set<string>,\n visited: Set<string>\n ) {\n if (!asset) {\n return;\n }\n if (!asset.assetUrl) {\n return;\n }\n if (visited.has(asset.moduleId)) {\n return;\n }\n visited.add(asset.moduleId);\n if (asset.importedCss) {\n asset.importedCss.forEach((cssUrl) => urls.add(cssUrl));\n }\n await Promise.all(\n asset.importedModules.map(async (moduleId) => {\n const importedAsset = (await this.assetMap.get(moduleId)) as BuildAsset;\n this.collectCss(importedAsset, urls, visited);\n })\n );\n }\n\n toJson() {\n return {\n moduleId: this.moduleId,\n assetUrl: this.assetUrl,\n importedModules: this.importedModules,\n importedCss: this.importedCss,\n };\n }\n}\n","export async function start() {\n console.log('SSR production server is coming soon');\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/dev.ts","../src/render/vite-plugin-root.ts","../src/core/fsutils.ts","../src/render/asset-map/dev-asset-map.ts","../src/cli/load-config.ts","../src/render/html-minify.ts","../src/cli/commands/build.ts","../src/render/asset-map/build-asset-map.ts","../src/cli/commands/start.ts"],"sourcesContent":["import path from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport {default as express, Request, Response, NextFunction} from 'express';\nimport {createServer as createViteServer} from 'vite';\nimport {pluginRoot} from '../../render/vite-plugin-root.js';\nimport {DevServerAssetMap} from '../../render/asset-map/dev-asset-map.js';\nimport {loadRootConfig} from '../load-config.js';\nimport {htmlMinify} from '../../render/html-minify.js';\nimport {Renderer} from '../../render/render.js';\nimport {isDirectory, isJsFile} from '../../core/fsutils.js';\nimport glob from 'tiny-glob';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport async function createServer(options?: {rootDir?: string}) {\n const app = express();\n\n app.use(express.static('public'));\n const middlewares = await getMiddlewares({rootDir: options?.rootDir});\n middlewares.forEach((middleware) => app.use(middleware));\n\n const port = parseInt(process.env.PORT || '4007');\n console.log('🌳 Root.js');\n console.log();\n console.log(`Started dev server: http://localhost:${port}`);\n app.listen(port);\n}\n\nexport async function getMiddlewares(options?: {rootDir?: string}) {\n const rootDir = options?.rootDir || process.cwd();\n const rootConfig = await loadRootConfig(rootDir);\n const viteConfig = rootConfig.vite || {};\n const renderModulePath = path.resolve(__dirname, './render.js');\n\n const pages: string[] = [];\n if (await isDirectory(path.join(rootDir, 'routes'))) {\n const pageFiles = await glob(path.join(rootDir, 'routes/**/*'));\n pageFiles.forEach((file) => {\n const parts = path.parse(file);\n if (!parts.name.startsWith('_') && isJsFile(parts.base)) {\n pages.push(file);\n }\n });\n }\n\n const elements: string[] = [];\n if (await isDirectory(path.join(rootDir, 'elements'))) {\n const elementFiles = await glob(path.join(rootDir, 'elements/**/*'));\n elementFiles.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n elements.push(file);\n }\n });\n }\n\n const bundleScripts: string[] = [];\n if (await isDirectory(path.join(rootDir, 'bundles'))) {\n const bundleFiles = await glob(path.join(rootDir, 'bundles/*'));\n bundleFiles.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n bundleScripts.push(file);\n }\n });\n }\n\n const viteServer = await createViteServer({\n ...viteConfig,\n mode: 'development',\n server: {middlewareMode: true},\n appType: 'custom',\n optimizeDeps: {\n include: [...pages, ...elements, ...bundleScripts],\n },\n ssr: {\n noExternal: ['@blinkk/root'],\n },\n esbuild: {\n jsx: 'automatic',\n jsxImportSource: 'preact',\n },\n plugins: [...(viteConfig.plugins || []), pluginRoot({rootDir, rootConfig})],\n });\n\n const rootMiddleware = async (\n req: Request,\n res: Response,\n next: NextFunction\n ) => {\n const url = req.originalUrl;\n let renderer: Renderer | null = null;\n try {\n const render = await viteServer.ssrLoadModule(renderModulePath);\n renderer = new render.Renderer(rootConfig) as Renderer;\n // Create a dev asset map using Vite dev server's module graph.\n const assetMap = new DevServerAssetMap(viteServer.moduleGraph);\n const data = await renderer.render(url, {\n assetMap: assetMap,\n });\n // Inject the Vite HMR client.\n let html = await viteServer.transformIndexHtml(url, data.html || '');\n if (rootConfig.minifyHtml !== false) {\n html = await htmlMinify(html);\n }\n res.status(200).set({'Content-Type': 'text/html'}).end(html);\n } catch (e) {\n // If an error is caught, let Vite fix the stack trace so it maps back to\n // your actual source code.\n viteServer.ssrFixStacktrace(e);\n try {\n if (renderer) {\n const {html} = await renderer.renderError(e);\n res.status(500).set({'Content-Type': 'text/html'}).end(html);\n } else {\n next(e);\n }\n } catch (e2) {\n console.error('failed to render custom error');\n console.error(e2);\n next(e);\n }\n }\n };\n\n return [viteServer.middlewares, rootMiddleware];\n}\n\nexport async function dev(rootDir?: string) {\n process.env.NODE_ENV = 'development';\n try {\n await createServer({rootDir});\n } catch (err) {\n console.error('an error occurred');\n }\n}\n","import path from 'path';\nimport glob from 'tiny-glob';\nimport {RootConfig} from '../core/config';\nimport {isDirectory, isJsFile} from '../core/fsutils';\n\nconst JSX_ELEMENTS_REGEX = /jsxs?\\(\"(\\w[\\w-]+\\w)\"/g;\nconst HTML_ELEMENTS_REGEX = /<(\\w[\\w-]+\\w)/g;\n\nexport interface RootPluginOptions {\n rootDir: string;\n rootConfig: RootConfig;\n}\n\nexport function pluginRoot(options?: RootPluginOptions) {\n const elementsVirtualId = 'virtual:root-elements';\n const resolvedElementsVirtualId = '\\0' + elementsVirtualId;\n\n const rootDir = options?.rootDir || process.cwd();\n const rootConfig = options?.rootConfig || {};\n const elementsDirs = [path.join(rootDir, 'elements')];\n const includeDirs = rootConfig.elements?.include || [];\n includeDirs.forEach((dirPath) => {\n const elementsDir = path.resolve(rootDir, dirPath);\n if (!elementsDir.startsWith(rootDir)) {\n throw new Error(\n `the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`\n );\n }\n elementsDirs.push(elementsDir);\n });\n\n let elementMap: Record<string, string>;\n async function updateElementMap() {\n elementMap = {};\n await Promise.all(\n elementsDirs.map(async (dirPath: string) => {\n const dirExists = await isDirectory(dirPath);\n if (!dirExists) {\n return;\n }\n const files = await glob('**/*', {cwd: dirPath});\n files.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n const fullPath = path.join(dirPath, file);\n const moduleId = fullPath.slice(rootDir.length);\n elementMap[parts.name] = moduleId;\n }\n });\n })\n );\n }\n\n async function getElementImport(tagname: string): Promise<string | null> {\n if (!elementMap) {\n await updateElementMap();\n }\n if (tagname in elementMap) {\n return elementMap[tagname];\n }\n return null;\n }\n\n function isCustomElement(id: string) {\n if (!isJsFile(id)) {\n return false;\n }\n return elementsDirs.some((elementsDir) => {\n return id.startsWith(elementsDir);\n });\n }\n\n return {\n name: 'vite-plugin-root',\n\n resolveId(id: string) {\n if (id === elementsVirtualId) {\n return resolvedElementsVirtualId;\n }\n return null;\n },\n\n async load(id: string) {\n if (id === resolvedElementsVirtualId) {\n await updateElementMap();\n return `export const elementsMap = ${JSON.stringify(elementMap)}`;\n }\n return null;\n },\n\n async transform(src: string, id: string): Promise<any> {\n if (isCustomElement(id)) {\n const idParts = path.parse(id);\n const deps = new Set<string>();\n const tagnames = [\n ...src.matchAll(JSX_ELEMENTS_REGEX),\n ...src.matchAll(HTML_ELEMENTS_REGEX),\n ];\n for (const match of tagnames) {\n const tagname = match[1];\n // All custom elements should contain a dash.\n if (!tagname.includes('-')) {\n continue;\n }\n // Avoid circular deps.\n if (tagname === idParts.name) {\n continue;\n }\n deps.add(tagname);\n }\n const importUrls: string[] = [];\n await Promise.all(\n Array.from(deps).map(async (tagname) => {\n const importUrl = await getElementImport(tagname);\n if (importUrl) {\n importUrls.push(importUrl);\n }\n })\n );\n if (importUrls.length > 0) {\n const importLines = importUrls\n .map((url) => `import '${url}';`)\n .join('\\n');\n const code = `${src}\n\n// autogenerated by root:\n${importLines}\n`;\n return {code};\n }\n return null;\n }\n return null;\n },\n };\n}\n","import {promises as fs} from 'node:fs';\nimport path from 'node:path';\nimport fsExtra from 'fs-extra';\n\nexport function isJsFile(filename: string) {\n return !!filename.match(/\\.(j|t)sx?$/);\n}\n\nexport async function writeFile(filepath: string, content: string) {\n const dirPath = path.dirname(filepath);\n await makeDir(dirPath);\n await fs.writeFile(filepath, content);\n}\n\nexport async function makeDir(dirpath: string) {\n try {\n await fs.access(dirpath);\n } catch (e) {\n await fs.mkdir(dirpath, {recursive: true});\n }\n}\n\nexport async function copyDir(srcdir: string, dstdir: string) {\n if (!fsExtra.existsSync(srcdir)) {\n return;\n }\n fsExtra.copySync(srcdir, dstdir, {recursive: true, overwrite: true});\n}\n\nexport async function rmDir(dirpath: string) {\n await fs.rm(dirpath, {recursive: true, force: true});\n}\n\nexport async function loadJson<T = unknown>(filepath: string): Promise<T> {\n const content = await fs.readFile(filepath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport async function isDirectory(dirpath: string) {\n return fs\n .stat(dirpath)\n .then((fsStat) => {\n return fsStat.isDirectory();\n })\n .catch((err) => {\n if (err.code === 'ENOENT') {\n return false;\n }\n throw err;\n });\n}\n\nexport function fileExists(filepath: string): Promise<boolean> {\n return fs\n .access(filepath)\n .then(() => true)\n .catch(() => false);\n}\n","import path from 'node:path';\nimport {ModuleGraph, ModuleNode} from 'vite';\nimport {Asset, AssetMap} from './asset-map';\n\nexport class DevServerAssetMap implements AssetMap {\n private moduleGraph: ModuleGraph;\n\n constructor(moduleGraph: ModuleGraph) {\n this.moduleGraph = moduleGraph;\n }\n\n async get(moduleId: string): Promise<Asset | null> {\n const viteModule = await this.moduleGraph.getModuleByUrl(moduleId);\n if (!viteModule || !viteModule.id) {\n return null;\n }\n return new DevServerAsset(this, viteModule);\n }\n}\n\nexport class DevServerAsset implements Asset {\n moduleId: string;\n assetUrl: string;\n private assetMap: AssetMap;\n private viteModule: ModuleNode;\n\n constructor(assetMap: AssetMap, viteModule: ModuleNode) {\n this.assetMap = assetMap;\n this.viteModule = viteModule;\n this.moduleId = this.viteModule.id!;\n this.assetUrl = this.viteModule.url;\n }\n\n async getCssDeps(): Promise<string[]> {\n const visited = new Set<string>();\n const deps = new Set<string>();\n this.collectCss(this, deps, visited);\n return Array.from(deps);\n }\n\n async getJsDeps(): Promise<string[]> {\n const visited = new Set<string>();\n const deps = new Set<string>();\n this.collectJs(this, deps, visited);\n return Array.from(deps);\n }\n\n getImportedModules() {\n return this.viteModule.importedModules;\n }\n\n private collectJs(\n asset: DevServerAsset | null,\n urls: Set<string>,\n visited: Set<string>\n ) {\n if (!asset) {\n return;\n }\n if (!asset.moduleId) {\n return;\n }\n if (visited.has(asset.moduleId)) {\n return;\n }\n visited.add(asset.moduleId);\n const parts = path.parse(asset.assetUrl);\n if (\n ['.js', '.jsx', '.ts', '.tsx'].includes(parts.ext) &&\n asset.moduleId.includes('/elements/')\n ) {\n urls.add(asset.assetUrl);\n }\n asset.getImportedModules().forEach((viteModule) => {\n if (viteModule.id) {\n const importedAsset = new DevServerAsset(this.assetMap, viteModule);\n this.collectJs(importedAsset, urls, visited);\n }\n });\n }\n\n private collectCss(\n asset: DevServerAsset | null,\n urls: Set<string>,\n visited: Set<string>\n ) {\n if (!asset) {\n return;\n }\n if (!asset.assetUrl) {\n return;\n }\n if (visited.has(asset.assetUrl)) {\n return;\n }\n visited.add(asset.assetUrl);\n if (asset.moduleId.endsWith('.scss')) {\n const parts = path.parse(asset.assetUrl);\n if (!parts.name.startsWith('_')) {\n urls.add(asset.assetUrl);\n }\n }\n asset.getImportedModules().forEach((viteModule) => {\n if (viteModule.id) {\n const importedAsset = new DevServerAsset(this.assetMap, viteModule);\n this.collectCss(importedAsset, urls, visited);\n }\n });\n }\n}\n","import {bundleRequire} from 'bundle-require';\nimport JoyCon from 'joycon';\nimport {RootConfig} from '../core/config';\n\nexport async function loadRootConfig(rootDir: string): Promise<RootConfig> {\n const joycon = new JoyCon();\n const configPath = await joycon.resolve({\n cwd: rootDir,\n files: ['root.config.ts'],\n });\n if (configPath) {\n const configBundle = await bundleRequire({\n filepath: configPath,\n });\n return configBundle.mod.default || {};\n }\n return {};\n}\n","import {minify} from 'html-minifier-terser';\n\nexport async function htmlMinify(html: string): Promise<string> {\n const min = await minify(html, {\n collapseWhitespace: true,\n removeComments: true,\n preserveLineBreaks: true,\n });\n return min.trimStart();\n}\n","import path from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport fsExtra from 'fs-extra';\nimport glob from 'tiny-glob';\nimport {build as viteBuild, Manifest, UserConfig} from 'vite';\nimport {pluginRoot} from '../../render/vite-plugin-root.js';\nimport {BuildAssetManifest, BuildAssetMap} from '../../render/asset-map/build-asset-map.js';\nimport {loadRootConfig} from '../load-config.js';\nimport {\n copyDir,\n isDirectory,\n isJsFile,\n loadJson,\n makeDir,\n rmDir,\n writeFile,\n} from '../../core/fsutils.js';\nimport {Renderer} from '../../render/render.js';\nimport {htmlMinify} from '../../render/html-minify.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport async function build(rootProjectDir?: string) {\n console.log('🌳 Root.js');\n\n const rootDir = rootProjectDir || process.cwd();\n const rootConfig = await loadRootConfig(rootDir);\n const distDir = path.join(rootDir, 'dist');\n await rmDir(distDir);\n await makeDir(distDir);\n\n const pages: string[] = [];\n if (await isDirectory(path.join(rootDir, 'routes'))) {\n const pageFiles = await glob(path.join(rootDir, 'routes/**/*'));\n pageFiles.forEach((file) => {\n const parts = path.parse(file);\n if (!parts.name.startsWith('_') && isJsFile(parts.base)) {\n pages.push(file);\n }\n });\n }\n\n const elementsDirs = [path.join(rootDir, 'elements')];\n const elementsInclude = rootConfig.elements?.include || [];\n for (const dirPath of elementsInclude) {\n const elementsDir = path.resolve(rootDir, dirPath);\n if (!elementsDir.startsWith(rootDir)) {\n throw new Error(\n `the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`\n );\n }\n elementsDirs.push(elementsDir);\n }\n const elements: string[] = [];\n const elementMap: Record<string, string> = {};\n for (const dirPath of elementsDirs) {\n if (await isDirectory(dirPath)) {\n const elementFiles = await glob('**/*', {cwd: dirPath});\n elementFiles.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n const fullPath = path.join(dirPath, file);\n const moduleId = fullPath.slice(rootDir.length);\n elements.push(fullPath);\n elementMap[parts.name] = moduleId;\n }\n });\n }\n }\n\n const bundleScripts: string[] = [];\n if (await isDirectory(path.join(rootDir, 'bundles'))) {\n const bundleFiles = await glob(path.join(rootDir, 'bundles/*'));\n bundleFiles.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n bundleScripts.push(file);\n }\n });\n }\n\n const viteConfig = rootConfig.vite || {};\n const baseConfig: UserConfig = {\n ...viteConfig,\n root: rootDir,\n esbuild: {\n jsx: 'automatic',\n jsxImportSource: 'preact',\n treeShaking: true,\n },\n plugins: [...(viteConfig.plugins || []), pluginRoot({rootDir, rootConfig})],\n };\n\n // Bundle the render.js file with vite, which is pre-optimized for rendering\n // HTML routes.\n await viteBuild({\n ...baseConfig,\n mode: 'production',\n publicDir: false,\n build: {\n rollupOptions: {\n input: [path.resolve(__dirname, './render.js')],\n output: {\n format: 'esm',\n chunkFileNames: 'chunks/[name].[hash].js',\n assetFileNames: 'assets/[name].[hash][extname]',\n },\n },\n outDir: path.join(distDir, 'server'),\n ssr: true,\n ssrManifest: false,\n cssCodeSplit: true,\n target: 'esnext',\n minify: false,\n polyfillModulePreload: false,\n reportCompressedSize: false,\n },\n ssr: {\n noExternal: ['@blinkk/root'],\n },\n });\n\n // Pre-render any client scripts and CSS deps.\n await viteBuild({\n ...baseConfig,\n mode: 'production',\n publicDir: false,\n build: {\n rollupOptions: {\n input: [...pages, ...elements, ...bundleScripts],\n output: {\n format: 'esm',\n chunkFileNames: 'chunks/[name].[hash].js',\n assetFileNames: 'assets/[name].[hash][extname]',\n },\n },\n outDir: path.join(distDir, 'client'),\n ssr: false,\n ssrManifest: false,\n manifest: true,\n cssCodeSplit: true,\n target: 'esnext',\n minify: true,\n polyfillModulePreload: false,\n reportCompressedSize: false,\n },\n });\n\n const viteManifest = await loadJson<Manifest>(\n path.join(distDir, 'client/manifest.json')\n );\n\n // Use the output of the client build to generate an asset map, which is used\n // by the renderer for automatically injecting dependencies for a page.\n const assetMap = BuildAssetMap.fromViteManifest(viteManifest, elementMap);\n\n // Save the asset map to `dist/client` for use by the prod SSR server.\n writeFile(\n path.join(distDir, 'client/root-manifest.json'),\n JSON.stringify(assetMap.toJson(), null, 2)\n );\n\n // Write SSG output to `dist/html`.\n const buildDir = path.join(distDir, 'html');\n\n // Recursively copy files from `public` to `dist/html`.\n const publicDir = path.join(rootDir, 'public');\n if (fsExtra.existsSync(path.join(rootDir, 'public'))) {\n fsExtra.copySync(publicDir, buildDir);\n } else {\n makeDir(buildDir);\n }\n\n // Copy files from `dist/client/{assets,chunks}` to `dist/html`.\n copyDir(path.join(distDir, 'client/assets'), path.join(buildDir, 'assets'));\n copyDir(path.join(distDir, 'client/chunks'), path.join(buildDir, 'chunks'));\n\n // Render HTML pages.\n const render = await import(path.join(distDir, 'server/render.js'));\n const renderer = new render.Renderer(rootConfig) as Renderer;\n const sitemap = await renderer.getSitemap();\n\n await Promise.all(\n Object.keys(sitemap).map(async (urlPath) => {\n const {route, params} = sitemap[urlPath];\n const data = await renderer.renderRoute(route, {\n assetMap,\n routeParams: params,\n });\n\n // The renderer currently assumes that all paths serve HTML.\n // TODO(stevenle): support non-HTML routes using `routes/[name].[ext].ts`.\n let outPath = path.join(distDir, `html${urlPath}`, 'index.html');\n\n if (outPath.endsWith('404/index.html')) {\n outPath = outPath.replace('404/index.html', '404.html');\n }\n\n const html = await htmlMinify(data.html || '');\n await writeFile(outPath, html);\n\n const relPath = outPath.slice(path.dirname(distDir).length + 1);\n console.log(`saved ${relPath}`);\n })\n );\n}\n","import {Manifest} from 'vite';\nimport {Asset, AssetMap} from './asset-map';\n\nexport type BuildAssetManifest = Record<\n string,\n {\n moduleId: string;\n assetUrl: string;\n importedModules: string[];\n importedCss: string[];\n isElement: boolean;\n }\n>;\n\nexport class BuildAssetMap implements AssetMap {\n private moduleIdToAsset: Map<string, BuildAsset>;\n\n constructor() {\n this.moduleIdToAsset = new Map();\n }\n\n async get(moduleId: string): Promise<Asset | null> {\n return this.moduleIdToAsset.get(moduleId) || null;\n }\n\n private add(asset: BuildAsset) {\n this.moduleIdToAsset.set(asset.moduleId, asset);\n }\n\n toJson(): BuildAssetManifest {\n const result: BuildAssetManifest = {};\n for (const moduleId of this.moduleIdToAsset.keys()) {\n result[moduleId] = this.moduleIdToAsset.get(moduleId)!.toJson();\n }\n return result;\n }\n\n static fromViteManifest(\n viteManifest: Manifest,\n elementMap: Record<string, string>\n ) {\n const assetMap = new BuildAssetMap();\n\n const elementModuleIds = new Set();\n Object.values(elementMap).forEach((moduleId) =>\n elementModuleIds.add(moduleId)\n );\n\n Object.keys(viteManifest).forEach((manifestKey) => {\n const moduleId = `/${manifestKey}`;\n const manifestChunk = viteManifest[manifestKey];\n const isElement = elementModuleIds.has(moduleId);\n const assetData = {\n moduleId,\n assetUrl: `/${manifestChunk.file}`,\n importedModules: (manifestChunk.imports || []).map(\n (relPath) => `/${relPath}`\n ),\n importedCss: (manifestChunk.css || []).map((relPath) => `/${relPath}`),\n isElement: isElement,\n };\n assetMap.add(new BuildAsset(assetMap, assetData));\n });\n return assetMap;\n }\n\n static fromRootManifest(rootManifest: BuildAssetManifest) {\n const assetMap = new BuildAssetMap();\n Object.keys(rootManifest).forEach((moduleId) => {\n const assetData = rootManifest[moduleId];\n assetMap.add(new BuildAsset(assetMap, assetData));\n });\n return assetMap;\n }\n}\n\nexport class BuildAsset {\n moduleId: string;\n assetUrl: string;\n private assetMap: BuildAssetMap;\n private importedModules: string[];\n private importedCss: string[];\n isElement: boolean;\n\n constructor(\n assetMap: BuildAssetMap,\n assetData: {\n moduleId: string;\n assetUrl: string;\n importedModules: string[];\n importedCss: string[];\n isElement: boolean;\n }\n ) {\n this.assetMap = assetMap;\n this.moduleId = assetData.moduleId;\n this.assetUrl = assetData.assetUrl;\n this.importedModules = assetData.importedModules;\n this.importedCss = assetData.importedCss;\n this.isElement = assetData.isElement;\n }\n\n async getCssDeps(): Promise<string[]> {\n const visited = new Set<string>();\n const deps = new Set<string>();\n await this.collectCss(this, deps, visited);\n return Array.from(deps);\n }\n\n async getJsDeps(): Promise<string[]> {\n const visited = new Set<string>();\n const deps = new Set<string>();\n await this.collectJs(this, deps, visited);\n return Array.from(deps);\n }\n\n private async collectJs(\n asset: BuildAsset | null,\n urls: Set<string>,\n visited: Set<string>\n ) {\n if (!asset) {\n return;\n }\n if (!asset.moduleId) {\n return;\n }\n if (visited.has(asset.moduleId)) {\n return;\n }\n visited.add(asset.moduleId);\n if (asset.isElement) {\n urls.add(asset.assetUrl);\n }\n await Promise.all(\n asset.importedModules.map(async (moduleId) => {\n const importedAsset = (await this.assetMap.get(moduleId)) as BuildAsset;\n this.collectJs(importedAsset, urls, visited);\n })\n );\n }\n\n private async collectCss(\n asset: BuildAsset | null,\n urls: Set<string>,\n visited: Set<string>\n ) {\n if (!asset) {\n return;\n }\n if (!asset.assetUrl) {\n return;\n }\n if (visited.has(asset.moduleId)) {\n return;\n }\n visited.add(asset.moduleId);\n if (asset.importedCss) {\n asset.importedCss.forEach((cssUrl) => urls.add(cssUrl));\n }\n await Promise.all(\n asset.importedModules.map(async (moduleId) => {\n const importedAsset = (await this.assetMap.get(moduleId)) as BuildAsset;\n this.collectCss(importedAsset, urls, visited);\n })\n );\n }\n\n toJson() {\n return {\n moduleId: this.moduleId,\n assetUrl: this.assetUrl,\n importedModules: this.importedModules,\n importedCss: this.importedCss,\n isElement: this.isElement,\n };\n }\n}\n","import path from 'node:path';\nimport {default as express, Request, Response, NextFunction} from 'express';\nimport {loadRootConfig} from '../load-config';\nimport {Renderer} from '../../render/render.js';\nimport {fileExists, loadJson} from '../../core/fsutils';\nimport {\n BuildAssetManifest,\n BuildAssetMap,\n} from '../../render/asset-map/build-asset-map';\nimport {htmlMinify} from '../../render/html-minify';\n\nexport async function start(rootProjectDir?: string) {\n console.log('🌳 Root.js');\n process.env.NODE_ENV = 'production';\n\n const rootDir = rootProjectDir || process.cwd();\n const rootConfig = await loadRootConfig(rootDir);\n const distDir = path.join(rootDir, 'dist');\n\n const render = await import(path.join(distDir, 'server/render.js'));\n const renderer = new render.Renderer(rootConfig) as Renderer;\n\n const manifestPath = path.join(distDir, 'client/root-manifest.json');\n if (!(await fileExists(manifestPath))) {\n throw new Error(\n `could not find ${manifestPath}. run \\`root build\\` before \\`root start\\`.`\n );\n }\n const rootManifest = await loadJson<BuildAssetManifest>(manifestPath);\n const assetMap = BuildAssetMap.fromRootManifest(rootManifest);\n\n const app = express();\n\n const publicDir = path.join(distDir, 'html');\n app.use(express.static(publicDir));\n // TODO(stevenle): add middleware that checks for pre-built HTML in dist/.\n\n app.use(async (req: Request, res: Response, next: NextFunction) => {\n try {\n const url = req.originalUrl;\n const data = await renderer.render(url, {\n assetMap: assetMap,\n });\n let html = data.html || '';\n if (rootConfig.minifyHtml !== false) {\n html = await htmlMinify(html);\n }\n res.status(200).set({'Content-Type': 'text/html'}).end(html);\n } catch (e) {\n try {\n const {html} = await renderer.renderError(e);\n res.status(500).set({'Content-Type': 'text/html'}).end(html);\n } catch (e2) {\n console.error('failed to render custom error');\n console.error(e2);\n next(e);\n }\n }\n });\n\n const port = parseInt(process.env.PORT || '4007');\n console.log(`\\nStarted prod server: http://localhost:${port}`);\n app.listen(port);\n}\n"],"mappings":"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","names":["path","path","path","path","glob","path","path","fileURLToPath","fsExtra","glob","__dirname","path","fileURLToPath","glob","fsExtra","path","express","path","express"]}
|
package/dist/core.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as preact from 'preact';
|
|
2
2
|
import { h, ComponentChildren } from 'preact';
|
|
3
|
-
export { b as GetStaticPaths, G as GetStaticProps, R as RootConfig, a as RootI18nConfig, d as defineConfig } from './types-
|
|
3
|
+
export { b as GetStaticPaths, G as GetStaticProps, R as RootConfig, a as RootI18nConfig, d as defineConfig } from './types-27ca8c1c.js';
|
|
4
4
|
import 'vite';
|
|
5
5
|
|
|
6
6
|
interface ErrorPageProps {
|
package/dist/core.js
CHANGED
package/dist/core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/config.ts"],"sourcesContent":["import {UserConfig as ViteUserConfig} from 'vite';\n\nexport interface RootConfig {\n /**\n * Configuration for auto-injecting custom element dependencies.\n */\n elements?: {\n /**\n * A list of directories to use to look for custom elements. The dir path\n * should be relative to the project dir, e.g. \"path/to/elements\" or\n * \"node_modules/my-package\".\n */\n include?: string[];\n };\n\n /**\n * Configuration options for localization and internationalization.\n */\n i18n?: RootI18nConfig;\n\n /**\n * Vite configuration.\n * @see {@link https://vitejs.dev/config/} for more information.\n */\n vite?: ViteUserConfig;\n\n /**\n * Whether to include a sitemap.xml file to the build output.\n */\n sitemap?: boolean;\n}\n\nexport interface RootI18nConfig {\n /**\n * Locales enabled for the site.\n */\n locales?: string[];\n\n /**\n * The default locale to use. Defaults is `en`.\n */\n defaultLocale?: string;\n\n /**\n * URL format for localized content. Default is `/{locale}/{path}`.\n */\n urlFormat?: string;\n}\n\nexport function defineConfig(config: RootConfig): RootConfig {\n return config;\n}\n"],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../src/core/config.ts"],"sourcesContent":["import {UserConfig as ViteUserConfig} from 'vite';\n\nexport interface RootConfig {\n /**\n * Configuration for auto-injecting custom element dependencies.\n */\n elements?: {\n /**\n * A list of directories to use to look for custom elements. The dir path\n * should be relative to the project dir, e.g. \"path/to/elements\" or\n * \"node_modules/my-package\".\n */\n include?: string[];\n };\n\n /**\n * Configuration options for localization and internationalization.\n */\n i18n?: RootI18nConfig;\n\n /**\n * Vite configuration.\n * @see {@link https://vitejs.dev/config/} for more information.\n */\n vite?: ViteUserConfig;\n\n /**\n * Whether to automatically minify HTML output.\n */\n minifyHtml?: boolean;\n\n /**\n * Whether to include a sitemap.xml file to the build output.\n */\n sitemap?: boolean;\n}\n\nexport interface RootI18nConfig {\n /**\n * Locales enabled for the site.\n */\n locales?: string[];\n\n /**\n * The default locale to use. Defaults is `en`.\n */\n defaultLocale?: string;\n\n /**\n * URL format for localized content. Default is `/{locale}/{path}`.\n */\n urlFormat?: string;\n}\n\nexport function defineConfig(config: RootConfig): RootConfig {\n return config;\n}\n"],"mappings":";;;;;;;;;;;;AAsDO,SAAS,aAAa,QAAgC;AAC3D,SAAO;AACT;","names":[]}
|
package/dist/render.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComponentType } from 'preact';
|
|
2
|
-
import { b as GetStaticPaths, G as GetStaticProps, R as RootConfig } from './types-
|
|
2
|
+
import { b as GetStaticPaths, G as GetStaticProps, R as RootConfig } from './types-27ca8c1c.js';
|
|
3
3
|
import 'vite';
|
|
4
4
|
|
|
5
5
|
interface RouteModule {
|
package/dist/render.js
CHANGED
|
@@ -4,10 +4,9 @@ import {
|
|
|
4
4
|
I18N_CONTEXT,
|
|
5
5
|
SCRIPT_CONTEXT,
|
|
6
6
|
getTranslations
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5FQTLGCQ.js";
|
|
8
8
|
|
|
9
9
|
// src/render/render.tsx
|
|
10
|
-
import { h } from "preact";
|
|
11
10
|
import renderToString from "preact-render-to-string";
|
|
12
11
|
|
|
13
12
|
// src/render/router.ts
|
|
@@ -143,9 +142,12 @@ function getRoutes(config) {
|
|
|
143
142
|
const locales = ((_a = config.i18n) == null ? void 0 : _a.locales) || [];
|
|
144
143
|
const i18nUrlFormat = ((_b = config.i18n) == null ? void 0 : _b.urlFormat) || "/{locale}/{path}";
|
|
145
144
|
const defaultLocale = ((_c = config.i18n) == null ? void 0 : _c.defaultLocale) || "en";
|
|
146
|
-
const routes = import.meta.glob(
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
const routes = import.meta.glob(
|
|
146
|
+
["/routes/*.ts", "/routes/**/*.ts", "/routes/*.tsx", "/routes/**/*.tsx"],
|
|
147
|
+
{
|
|
148
|
+
eager: true
|
|
149
|
+
}
|
|
150
|
+
);
|
|
149
151
|
const trie = new RouteTrie();
|
|
150
152
|
Object.keys(routes).forEach((filePath) => {
|
|
151
153
|
let routePath = filePath.replace(/^\/routes/, "");
|
|
@@ -181,30 +183,36 @@ async function getAllPathsForRoute(urlPathFormat, route) {
|
|
|
181
183
|
const routeModule = route.module;
|
|
182
184
|
if (routeModule.getStaticPaths) {
|
|
183
185
|
const staticPaths = await routeModule.getStaticPaths();
|
|
184
|
-
staticPaths.paths.forEach(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
staticPaths.paths.forEach(
|
|
187
|
+
(pathParams) => {
|
|
188
|
+
urlPaths.push({
|
|
189
|
+
urlPath: replaceParams(urlPathFormat, pathParams.params),
|
|
190
|
+
params: pathParams.params || {}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
);
|
|
190
194
|
} else {
|
|
191
195
|
urlPaths.push({ urlPath: urlPathFormat, params: {} });
|
|
192
196
|
}
|
|
193
197
|
return urlPaths;
|
|
194
198
|
}
|
|
195
199
|
function replaceParams(urlPathFormat, params) {
|
|
196
|
-
const urlPath = urlPathFormat.replaceAll(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
const urlPath = urlPathFormat.replaceAll(
|
|
201
|
+
/\[(\.\.\.)?([\w\-_]*)\]/g,
|
|
202
|
+
(match, _wildcard, key) => {
|
|
203
|
+
const val = params[key];
|
|
204
|
+
if (!val) {
|
|
205
|
+
throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);
|
|
206
|
+
}
|
|
207
|
+
return val;
|
|
200
208
|
}
|
|
201
|
-
|
|
202
|
-
});
|
|
209
|
+
);
|
|
203
210
|
return urlPath;
|
|
204
211
|
}
|
|
205
212
|
|
|
206
213
|
// src/render/render.tsx
|
|
207
214
|
import { elementsMap } from "virtual:root-elements";
|
|
215
|
+
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
208
216
|
var Renderer = class {
|
|
209
217
|
constructor(config) {
|
|
210
218
|
this.routes = getRoutes(config);
|
|
@@ -222,7 +230,9 @@ var Renderer = class {
|
|
|
222
230
|
const assetMap = options.assetMap;
|
|
223
231
|
const Component = route.module.default;
|
|
224
232
|
if (!Component) {
|
|
225
|
-
throw new Error(
|
|
233
|
+
throw new Error(
|
|
234
|
+
"unable to render route. the route should have a default export that renders a jsx component."
|
|
235
|
+
);
|
|
226
236
|
}
|
|
227
237
|
let props = {};
|
|
228
238
|
if (route.module.getStaticProps) {
|
|
@@ -240,21 +250,24 @@ var Renderer = class {
|
|
|
240
250
|
const translations = getTranslations(locale);
|
|
241
251
|
const headComponents = [];
|
|
242
252
|
const userScripts = [];
|
|
243
|
-
const vdom = /* @__PURE__ */
|
|
244
|
-
value: { locale, translations }
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
253
|
+
const vdom = /* @__PURE__ */ jsx(I18N_CONTEXT.Provider, {
|
|
254
|
+
value: { locale, translations },
|
|
255
|
+
children: /* @__PURE__ */ jsx(SCRIPT_CONTEXT.Provider, {
|
|
256
|
+
value: userScripts,
|
|
257
|
+
children: /* @__PURE__ */ jsx(HEAD_CONTEXT.Provider, {
|
|
258
|
+
value: headComponents,
|
|
259
|
+
children: /* @__PURE__ */ jsx(Component, {
|
|
260
|
+
...props
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
});
|
|
252
265
|
const mainHtml = renderToString(vdom, {}, { pretty: true });
|
|
253
266
|
const pageAsset = await assetMap.get(route.modulePath);
|
|
254
267
|
const cssDeps = await (pageAsset == null ? void 0 : pageAsset.getCssDeps());
|
|
255
268
|
if (cssDeps) {
|
|
256
269
|
cssDeps.forEach((cssUrl) => {
|
|
257
|
-
headComponents.push(/* @__PURE__ */
|
|
270
|
+
headComponents.push(/* @__PURE__ */ jsx("link", {
|
|
258
271
|
rel: "stylesheet",
|
|
259
272
|
href: cssUrl
|
|
260
273
|
}));
|
|
@@ -262,22 +275,23 @@ var Renderer = class {
|
|
|
262
275
|
}
|
|
263
276
|
const scriptDeps = await this.getScriptDeps(mainHtml, { assetMap });
|
|
264
277
|
scriptDeps.forEach((jsUrls) => {
|
|
265
|
-
headComponents.push(/* @__PURE__ */
|
|
278
|
+
headComponents.push(/* @__PURE__ */ jsx("script", {
|
|
266
279
|
type: "module",
|
|
267
280
|
src: jsUrls
|
|
268
281
|
}));
|
|
269
282
|
});
|
|
270
|
-
await Promise.all(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
283
|
+
await Promise.all(
|
|
284
|
+
userScripts.map(async (scriptDep) => {
|
|
285
|
+
const scriptAsset = await assetMap.get(scriptDep.src);
|
|
286
|
+
if (scriptAsset) {
|
|
287
|
+
const scriptUrl = scriptAsset ? scriptAsset.assetUrl : scriptDep.src;
|
|
288
|
+
headComponents.push(/* @__PURE__ */ jsx("script", {
|
|
289
|
+
type: "module",
|
|
290
|
+
src: scriptUrl
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
293
|
+
})
|
|
294
|
+
);
|
|
281
295
|
const html = await this.renderHtml({ mainHtml, locale, headComponents });
|
|
282
296
|
return { html };
|
|
283
297
|
}
|
|
@@ -295,15 +309,28 @@ var Renderer = class {
|
|
|
295
309
|
return sitemap;
|
|
296
310
|
}
|
|
297
311
|
async renderHtml(options) {
|
|
298
|
-
const page = /* @__PURE__ */
|
|
299
|
-
lang: options.locale
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
312
|
+
const page = /* @__PURE__ */ jsxs("html", {
|
|
313
|
+
lang: options.locale,
|
|
314
|
+
children: [
|
|
315
|
+
/* @__PURE__ */ jsxs("head", {
|
|
316
|
+
children: [
|
|
317
|
+
/* @__PURE__ */ jsx("meta", {
|
|
318
|
+
charSet: "utf-8"
|
|
319
|
+
}),
|
|
320
|
+
options.headComponents
|
|
321
|
+
]
|
|
322
|
+
}),
|
|
323
|
+
/* @__PURE__ */ jsx("body", {
|
|
324
|
+
dangerouslySetInnerHTML: { __html: options.mainHtml }
|
|
325
|
+
})
|
|
326
|
+
]
|
|
327
|
+
});
|
|
305
328
|
const html = `<!doctype html>
|
|
306
|
-
${renderToString(
|
|
329
|
+
${renderToString(
|
|
330
|
+
page,
|
|
331
|
+
{},
|
|
332
|
+
{ pretty: true }
|
|
333
|
+
)}
|
|
307
334
|
`;
|
|
308
335
|
return html;
|
|
309
336
|
}
|
|
@@ -314,7 +341,7 @@ ${renderToString(page, {}, { pretty: true })}
|
|
|
314
341
|
};
|
|
315
342
|
}
|
|
316
343
|
async renderError(error) {
|
|
317
|
-
const mainHtml = renderToString(/* @__PURE__ */
|
|
344
|
+
const mainHtml = renderToString(/* @__PURE__ */ jsx(ErrorPage, {
|
|
318
345
|
error
|
|
319
346
|
}));
|
|
320
347
|
const html = await this.renderHtml({ mainHtml, locale: "en" });
|
|
@@ -325,20 +352,20 @@ ${renderToString(page, {}, { pretty: true })}
|
|
|
325
352
|
const deps = /* @__PURE__ */ new Set();
|
|
326
353
|
const re = /<(\w[\w-]+\w)/g;
|
|
327
354
|
const matches = Array.from(html.matchAll(re));
|
|
328
|
-
await Promise.all(
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
355
|
+
await Promise.all(
|
|
356
|
+
matches.map(async (match) => {
|
|
357
|
+
const tagName = match[1];
|
|
358
|
+
if (tagName && tagName.includes("-") && tagName in elementsMap) {
|
|
359
|
+
const modulePath = elementsMap[tagName];
|
|
360
|
+
const asset = await assetMap.get(modulePath);
|
|
361
|
+
if (!asset) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const assetJsDeps = await asset.getJsDeps();
|
|
365
|
+
assetJsDeps.forEach((dep) => deps.add(dep));
|
|
335
366
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
} else {
|
|
339
|
-
console.log(`could not find tag name: ${tagName}`);
|
|
340
|
-
}
|
|
341
|
-
}));
|
|
367
|
+
})
|
|
368
|
+
);
|
|
342
369
|
return Array.from(deps);
|
|
343
370
|
}
|
|
344
371
|
};
|
package/dist/render.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/render/render.tsx","../src/render/router.ts","../src/render/route-trie.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {h, ComponentChildren} from 'preact';\nimport renderToString from 'preact-render-to-string';\nimport {getRoutes, Route, getAllPathsForRoute} from './router';\nimport {HEAD_CONTEXT} from '../core/components/head';\nimport {ErrorPage} from '../core/components/error-page';\nimport {getTranslations, I18N_CONTEXT} from '../core/i18n';\nimport {ScriptProps, SCRIPT_CONTEXT} from '../core/components/script';\nimport {AssetMap} from './asset-map/asset-map';\nimport {RootConfig} from '../core/config';\nimport {RouteTrie} from './route-trie';\nimport {elementsMap} from 'virtual:root-elements';\n\ninterface RenderOptions {\n assetMap: AssetMap;\n}\n\ninterface RenderHtmlOptions {\n mainHtml: string;\n locale: string;\n headComponents?: ComponentChildren[];\n}\n\nexport class Renderer {\n private routes: RouteTrie<Route>;\n\n constructor(config: RootConfig) {\n this.routes = getRoutes(config);\n }\n\n async render(\n url: string,\n options: RenderOptions\n ): Promise<{html: string; notFound?: boolean}> {\n const assetMap = options.assetMap;\n const [route, routeParams] = this.routes.get(url);\n if (route && route.module && route.module.default) {\n return await this.renderRoute(route, {routeParams, assetMap});\n }\n return this.render404();\n }\n\n async renderRoute(\n route: Route,\n options: {routeParams: Record<string, string>; assetMap: AssetMap}\n ): Promise<{html: string; notFound?: boolean}> {\n const routeParams = options.routeParams;\n const assetMap = options.assetMap;\n const Component = route.module.default;\n if (!Component) {\n throw new Error(\n 'unable to render route. the route should have a default export that renders a jsx component.'\n );\n }\n let props = {};\n if (route.module.getStaticProps) {\n const propsData = await route.module.getStaticProps({\n params: routeParams,\n });\n if (propsData.notFound) {\n return this.render404();\n }\n if (propsData.props) {\n props = propsData.props;\n }\n }\n\n const locale = route.locale;\n const translations = getTranslations(locale);\n\n const headComponents: ComponentChildren[] = [];\n const userScripts: ScriptProps[] = [];\n const vdom = (\n <I18N_CONTEXT.Provider value={{locale, translations}}>\n <SCRIPT_CONTEXT.Provider value={userScripts}>\n <HEAD_CONTEXT.Provider value={headComponents}>\n <Component {...props} />\n </HEAD_CONTEXT.Provider>\n </SCRIPT_CONTEXT.Provider>\n </I18N_CONTEXT.Provider>\n );\n const mainHtml = renderToString(vdom, {}, {pretty: true});\n\n // Walk the page's dependency tree for CSS dependencies that are added via\n // `import 'foo.scss'` or `import 'foo.module.scss'`.\n const pageAsset = await assetMap.get(route.modulePath);\n const cssDeps = await pageAsset?.getCssDeps();\n if (cssDeps) {\n cssDeps.forEach((cssUrl) => {\n headComponents.push(<link rel=\"stylesheet\" href={cssUrl} />);\n });\n }\n\n // Parse the HTML for custom elements that are found within the project\n // and automatically inject the script deps for them.\n const scriptDeps = await this.getScriptDeps(mainHtml, {assetMap});\n scriptDeps.forEach((jsUrls) => {\n headComponents.push(<script type=\"module\" src={jsUrls} />);\n });\n\n // Add user defined scripts added via the `<Script>` component.\n await Promise.all(\n userScripts.map(async (scriptDep) => {\n const scriptAsset = await assetMap.get(scriptDep.src);\n if (!scriptAsset && import.meta.env.PROD) {\n console.log(`could not find precompiled asset: ${scriptDep.src}`);\n }\n const scriptUrl = scriptAsset ? scriptAsset.assetUrl : scriptDep.src;\n headComponents.push(<script type=\"module\" src={scriptUrl} />);\n })\n );\n\n const html = await this.renderHtml({mainHtml, locale, headComponents});\n return {html};\n }\n\n async getSitemap(): Promise<\n Record<string, {route: Route; params: Record<string, string>}>\n > {\n const sitemap: Record<\n string,\n {route: Route; params: Record<string, string>}\n > = {};\n await this.routes.walk(async (urlPath: string, route: Route) => {\n const routePaths = await getAllPathsForRoute(urlPath, route);\n routePaths.forEach((routePath) => {\n sitemap[routePath.urlPath] = {\n route,\n params: routePath.params,\n };\n });\n });\n return sitemap;\n }\n\n private async renderHtml(options: RenderHtmlOptions) {\n const page = (\n <html lang={options.locale}>\n <head>\n <meta charSet=\"utf-8\" />\n {options.headComponents}\n </head>\n <body dangerouslySetInnerHTML={{__html: options.mainHtml}} />\n </html>\n );\n const html = `<!doctype html>\\n${renderToString(\n page,\n {},\n {pretty: true}\n )}\\n`;\n return html;\n }\n\n async render404() {\n return {\n html: '<!doctype html><html><title>404 Not Found</title><h1>404 Not Found</h1>',\n notFound: true,\n };\n }\n\n async renderError(error: unknown) {\n const mainHtml = renderToString(<ErrorPage error={error} />);\n const html = await this.renderHtml({mainHtml, locale: 'en'});\n return {html};\n }\n\n private async getScriptDeps(\n html: string,\n options: {assetMap: AssetMap}\n ): Promise<string[]> {\n const assetMap = options.assetMap as AssetMap;\n const deps = new Set<string>();\n\n const re = /<(\\w[\\w-]+\\w)/g;\n const matches = Array.from(html.matchAll(re));\n await Promise.all(\n matches.map(async (match) => {\n const tagName = match[1];\n // Custom elements require a dash.\n if (tagName && tagName.includes('-') && tagName in elementsMap) {\n const modulePath = elementsMap[tagName];\n const asset = await assetMap.get(modulePath);\n if (!asset) {\n return;\n }\n const assetJsDeps = await asset.getJsDeps();\n assetJsDeps.forEach((dep) => deps.add(dep));\n } else {\n console.log(`could not find tag name: ${tagName}`);\n }\n })\n );\n\n return Array.from(deps);\n }\n}\n","import path from 'node:path';\nimport {ComponentType} from 'preact';\nimport {RootConfig} from '../core/config';\nimport {GetStaticPaths, GetStaticProps} from '../core/types';\nimport {RouteTrie} from './route-trie';\n\nexport interface RouteModule {\n default?: ComponentType<unknown>;\n getStaticPaths?: GetStaticPaths;\n getStaticProps?: GetStaticProps;\n}\n\nexport interface Route {\n modulePath: string;\n module: RouteModule;\n locale: string;\n}\n\nexport function getRoutes(config: RootConfig) {\n const locales = config.i18n?.locales || [];\n const i18nUrlFormat = config.i18n?.urlFormat || '/{locale}/{path}';\n const defaultLocale = config.i18n?.defaultLocale || 'en';\n\n const routes = import.meta.glob(\n ['/routes/*.ts', '/routes/**/*.ts', '/routes/*.tsx', '/routes/**/*.tsx'],\n {\n eager: true,\n }\n );\n const trie = new RouteTrie<Route>();\n Object.keys(routes).forEach((filePath) => {\n let routePath = filePath.replace(/^\\/routes/, '');\n const parts = path.parse(routePath);\n if (parts.name.startsWith('_')) {\n return;\n }\n if (parts.name === 'index') {\n routePath = parts.dir;\n } else {\n routePath = path.join(parts.dir, parts.name);\n }\n trie.add(routePath, {\n modulePath: filePath,\n module: routes[filePath] as RouteModule,\n locale: defaultLocale,\n });\n\n // At the moment, all routes are assumed to use the site-wide i18n config.\n // TODO(stevenle): provide routes with a way to override the default\n // i18n serving behavior.\n locales.forEach((locale) => {\n const localeRoutePath = i18nUrlFormat\n .replace('{locale}', locale)\n .replace('{path}', routePath.replace(/^\\/*/, ''));\n if (localeRoutePath !== routePath) {\n trie.add(localeRoutePath, {\n modulePath: filePath,\n module: routes[filePath] as RouteModule,\n locale: locale,\n });\n }\n });\n });\n return trie;\n}\n\nexport async function getAllPathsForRoute(\n urlPathFormat: string,\n route: Route\n): Promise<Array<{urlPath: string; params: Record<string, string>}>> {\n const urlPaths: Array<{urlPath: string; params: Record<string, string>}> = [];\n const routeModule = route.module;\n if (routeModule.getStaticPaths) {\n const staticPaths = await routeModule.getStaticPaths();\n staticPaths.paths.forEach(\n (pathParams: {params: Record<string, string>}) => {\n urlPaths.push({\n urlPath: replaceParams(urlPathFormat, pathParams.params),\n params: pathParams.params || {},\n });\n }\n );\n } else {\n urlPaths.push({urlPath: urlPathFormat, params: {}});\n }\n return urlPaths;\n}\n\nexport function replaceParams(\n urlPathFormat: string,\n params: Record<string, string>\n) {\n const urlPath = urlPathFormat.replaceAll(\n /\\[(\\.\\.\\.)?([\\w\\-_]*)\\]/g,\n (match: string, _wildcard: string, key: string) => {\n const val = params[key];\n if (!val) {\n throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);\n }\n return val;\n }\n );\n return urlPath;\n}\n","/**\n * A trie data structure that stores routes. The trie supports `:param` and\n * `*wildcard` values.\n */\nexport class RouteTrie<T> {\n private children: Record<string, RouteTrie<T>> = {};\n private paramChild?: ParamChild<T>;\n private wildcardChild?: WildcardChild<T>;\n private route?: T;\n\n /**\n * Adds a route to the trie.\n */\n add(path: string, route: T) {\n path = this.normalizePath(path);\n\n // If the end was reached, save the value to the node.\n if (path === '') {\n this.route = route;\n return;\n }\n\n const [head, tail] = this.splitPath(path);\n if (head.startsWith('[...') && head.endsWith(']')) {\n const paramName = head.slice(4, -1);\n this.wildcardChild = new WildcardChild(paramName, route);\n return;\n }\n\n let nextNode: RouteTrie<T>;\n if (head.startsWith('[') && head.endsWith(']')) {\n if (!this.paramChild) {\n const paramName = head.slice(1, -1);\n this.paramChild = new ParamChild(paramName);\n }\n nextNode = this.paramChild.trie;\n } else {\n nextNode = this.children[head];\n if (!nextNode) {\n nextNode = new RouteTrie();\n this.children[head] = nextNode;\n }\n }\n nextNode.add(tail, route);\n }\n\n /**\n * Returns a route mapped to the given path and any parameter values from the\n * URL.\n */\n get(path: string): [T | undefined, Record<string, string>] {\n const params = {};\n const route = this.getRoute(path, params);\n return [route, params];\n }\n\n /**\n * Walks the route trie and calls a callback function for each route.\n */\n walk(cb: (urlPath: string, route: T) => Promise<void> | void): Promise<void> {\n const promises: Array<Promise<void>> = [];\n const addPromise = (promise: Promise<void> | void) => {\n if (promise) {\n promises.push(promise);\n }\n };\n if (this.route) {\n addPromise(cb('/', this.route));\n }\n if (this.paramChild) {\n const param = `[${this.paramChild.name}]`;\n this.paramChild.trie.walk((childPath: string, route: T) => {\n const paramUrlPath = `/${param}${childPath}`;\n addPromise(cb(paramUrlPath, route));\n });\n }\n if (this.wildcardChild) {\n const wildcardUrlPath = `/[...${this.wildcardChild.name}]`;\n addPromise(cb(wildcardUrlPath, this.wildcardChild.route));\n }\n for (const subpath of Object.keys(this.children)) {\n const childTrie = this.children[subpath];\n childTrie.walk((childPath: string, childRoute: T) => {\n addPromise(cb(`/${subpath}${childPath}`, childRoute));\n });\n }\n return Promise.all(promises).then(() => {});\n }\n\n /**\n * Removes all routes from the trie.\n */\n clear() {\n this.children = {};\n this.paramChild = undefined;\n this.wildcardChild = undefined;\n this.route = undefined;\n }\n\n private getRoute(\n urlPath: string,\n params: Record<string, string>\n ): T | undefined {\n urlPath = this.normalizePath(urlPath);\n if (urlPath === '') {\n return this.route;\n }\n\n const [head, tail] = this.splitPath(urlPath);\n\n const child = this.children[head];\n if (child) {\n const route = child.getRoute(tail, params);\n if (route) {\n return route;\n }\n }\n\n if (this.paramChild) {\n const route = this.paramChild.trie.getRoute(tail, params);\n if (route) {\n params[this.paramChild.name] = head;\n return route;\n }\n }\n\n if (this.wildcardChild) {\n params[this.wildcardChild.name] = urlPath;\n return this.wildcardChild.route;\n }\n\n return undefined;\n }\n\n /**\n * Normalizes a path for inclusion into the route trie.\n */\n private normalizePath(path: string) {\n // Remove leading slashes.\n return path.replace(/^\\/+/g, '');\n }\n\n /**\n * Splits the parent directory from its children, e.g.:\n *\n * splitPath(\"foo/bar/baz\") -> [\"foo\", \"bar/baz\"]\n */\n private splitPath(path: string): [string, string] {\n const i = path.indexOf('/');\n if (i === -1) {\n return [path, ''];\n }\n return [path.slice(0, i), path.slice(i + 1)];\n }\n}\n\n/**\n * A node in the RouteTrie for a :param child.\n */\nclass ParamChild<T> {\n readonly name: string;\n readonly trie: RouteTrie<T> = new RouteTrie();\n\n constructor(name: string) {\n this.name = name;\n }\n}\n\n/**\n * A node in the RouteTrie for a *wildcard child.\n */\nclass WildcardChild<T> {\n readonly name: string;\n readonly route: T;\n\n constructor(name: string, route: T) {\n this.name = name;\n this.route = route;\n }\n}\n"],"mappings":";;;;;;;;;AACA;AACA;;;ACFA;;;ACIO,IAAM,YAAN,MAAmB;AAAA,EAAnB;AACL,SAAQ,WAAyC,CAAC;AAAA;AAAA,EAQlD,IAAI,OAAc,OAAU;AAC1B,YAAO,KAAK,cAAc,KAAI;AAG9B,QAAI,UAAS,IAAI;AACf,WAAK,QAAQ;AACb;AAAA,IACF;AAEA,UAAM,CAAC,MAAM,QAAQ,KAAK,UAAU,KAAI;AACxC,QAAI,KAAK,WAAW,MAAM,KAAK,KAAK,SAAS,GAAG,GAAG;AACjD,YAAM,YAAY,KAAK,MAAM,GAAG,EAAE;AAClC,WAAK,gBAAgB,IAAI,cAAc,WAAW,KAAK;AACvD;AAAA,IACF;AAEA,QAAI;AACJ,QAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,GAAG;AAC9C,UAAI,CAAC,KAAK,YAAY;AACpB,cAAM,YAAY,KAAK,MAAM,GAAG,EAAE;AAClC,aAAK,aAAa,IAAI,WAAW,SAAS;AAAA,MAC5C;AACA,iBAAW,KAAK,WAAW;AAAA,IAC7B,OAAO;AACL,iBAAW,KAAK,SAAS;AACzB,UAAI,CAAC,UAAU;AACb,mBAAW,IAAI,UAAU;AACzB,aAAK,SAAS,QAAQ;AAAA,MACxB;AAAA,IACF;AACA,aAAS,IAAI,MAAM,KAAK;AAAA,EAC1B;AAAA,EAMA,IAAI,OAAuD;AACzD,UAAM,SAAS,CAAC;AAChB,UAAM,QAAQ,KAAK,SAAS,OAAM,MAAM;AACxC,WAAO,CAAC,OAAO,MAAM;AAAA,EACvB;AAAA,EAKA,KAAK,IAAwE;AAC3E,UAAM,WAAiC,CAAC;AACxC,UAAM,aAAa,CAAC,YAAkC;AACpD,UAAI,SAAS;AACX,iBAAS,KAAK,OAAO;AAAA,MACvB;AAAA,IACF;AACA,QAAI,KAAK,OAAO;AACd,iBAAW,GAAG,KAAK,KAAK,KAAK,CAAC;AAAA,IAChC;AACA,QAAI,KAAK,YAAY;AACnB,YAAM,QAAQ,IAAI,KAAK,WAAW;AAClC,WAAK,WAAW,KAAK,KAAK,CAAC,WAAmB,UAAa;AACzD,cAAM,eAAe,IAAI,QAAQ;AACjC,mBAAW,GAAG,cAAc,KAAK,CAAC;AAAA,MACpC,CAAC;AAAA,IACH;AACA,QAAI,KAAK,eAAe;AACtB,YAAM,kBAAkB,QAAQ,KAAK,cAAc;AACnD,iBAAW,GAAG,iBAAiB,KAAK,cAAc,KAAK,CAAC;AAAA,IAC1D;AACA,eAAW,WAAW,OAAO,KAAK,KAAK,QAAQ,GAAG;AAChD,YAAM,YAAY,KAAK,SAAS;AAChC,gBAAU,KAAK,CAAC,WAAmB,eAAkB;AACnD,mBAAW,GAAG,IAAI,UAAU,aAAa,UAAU,CAAC;AAAA,MACtD,CAAC;AAAA,IACH;AACA,WAAO,QAAQ,IAAI,QAAQ,EAAE,KAAK,MAAM;AAAA,IAAC,CAAC;AAAA,EAC5C;AAAA,EAKA,QAAQ;AACN,SAAK,WAAW,CAAC;AACjB,SAAK,aAAa;AAClB,SAAK,gBAAgB;AACrB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,AAAQ,SACN,SACA,QACe;AACf,cAAU,KAAK,cAAc,OAAO;AACpC,QAAI,YAAY,IAAI;AAClB,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,CAAC,MAAM,QAAQ,KAAK,UAAU,OAAO;AAE3C,UAAM,QAAQ,KAAK,SAAS;AAC5B,QAAI,OAAO;AACT,YAAM,QAAQ,MAAM,SAAS,MAAM,MAAM;AACzC,UAAI,OAAO;AACT,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,KAAK,YAAY;AACnB,YAAM,QAAQ,KAAK,WAAW,KAAK,SAAS,MAAM,MAAM;AACxD,UAAI,OAAO;AACT,eAAO,KAAK,WAAW,QAAQ;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,KAAK,eAAe;AACtB,aAAO,KAAK,cAAc,QAAQ;AAClC,aAAO,KAAK,cAAc;AAAA,IAC5B;AAEA,WAAO;AAAA,EACT;AAAA,EAKA,AAAQ,cAAc,OAAc;AAElC,WAAO,MAAK,QAAQ,SAAS,EAAE;AAAA,EACjC;AAAA,EAOA,AAAQ,UAAU,OAAgC;AAChD,UAAM,IAAI,MAAK,QAAQ,GAAG;AAC1B,QAAI,MAAM,IAAI;AACZ,aAAO,CAAC,OAAM,EAAE;AAAA,IAClB;AACA,WAAO,CAAC,MAAK,MAAM,GAAG,CAAC,GAAG,MAAK,MAAM,IAAI,CAAC,CAAC;AAAA,EAC7C;AACF;AAKA,IAAM,aAAN,MAAoB;AAAA,EAIlB,YAAY,MAAc;AAF1B,SAAS,OAAqB,IAAI,UAAU;AAG1C,SAAK,OAAO;AAAA,EACd;AACF;AAKA,IAAM,gBAAN,MAAuB;AAAA,EAIrB,YAAY,MAAc,OAAU;AAClC,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACf;AACF;;;ADjKO,mBAAmB,QAAoB;AAlB9C;AAmBE,QAAM,UAAU,cAAO,SAAP,mBAAa,YAAW,CAAC;AACzC,QAAM,gBAAgB,cAAO,SAAP,mBAAa,cAAa;AAChD,QAAM,gBAAgB,cAAO,SAAP,mBAAa,kBAAiB;AAEpD,QAAM,SAAS,YAAY,KACzB,CAAC,gBAAgB,mBAAmB,iBAAiB,kBAAkB,GACvE;AAAA,IACE,OAAO;AAAA,EACT,CACF;AACA,QAAM,OAAO,IAAI,UAAiB;AAClC,SAAO,KAAK,MAAM,EAAE,QAAQ,CAAC,aAAa;AACxC,QAAI,YAAY,SAAS,QAAQ,aAAa,EAAE;AAChD,UAAM,QAAQ,KAAK,MAAM,SAAS;AAClC,QAAI,MAAM,KAAK,WAAW,GAAG,GAAG;AAC9B;AAAA,IACF;AACA,QAAI,MAAM,SAAS,SAAS;AAC1B,kBAAY,MAAM;AAAA,IACpB,OAAO;AACL,kBAAY,KAAK,KAAK,MAAM,KAAK,MAAM,IAAI;AAAA,IAC7C;AACA,SAAK,IAAI,WAAW;AAAA,MAClB,YAAY;AAAA,MACZ,QAAQ,OAAO;AAAA,MACf,QAAQ;AAAA,IACV,CAAC;AAKD,YAAQ,QAAQ,CAAC,WAAW;AAC1B,YAAM,kBAAkB,cACrB,QAAQ,YAAY,MAAM,EAC1B,QAAQ,UAAU,UAAU,QAAQ,QAAQ,EAAE,CAAC;AAClD,UAAI,oBAAoB,WAAW;AACjC,aAAK,IAAI,iBAAiB;AAAA,UACxB,YAAY;AAAA,UACZ,QAAQ,OAAO;AAAA,UACf;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACD,SAAO;AACT;AAEA,mCACE,eACA,OACmE;AACnE,QAAM,WAAqE,CAAC;AAC5E,QAAM,cAAc,MAAM;AAC1B,MAAI,YAAY,gBAAgB;AAC9B,UAAM,cAAc,MAAM,YAAY,eAAe;AACrD,gBAAY,MAAM,QAChB,CAAC,eAAiD;AAChD,eAAS,KAAK;AAAA,QACZ,SAAS,cAAc,eAAe,WAAW,MAAM;AAAA,QACvD,QAAQ,WAAW,UAAU,CAAC;AAAA,MAChC,CAAC;AAAA,IACH,CACF;AAAA,EACF,OAAO;AACL,aAAS,KAAK,EAAC,SAAS,eAAe,QAAQ,CAAC,EAAC,CAAC;AAAA,EACpD;AACA,SAAO;AACT;AAEO,uBACL,eACA,QACA;AACA,QAAM,UAAU,cAAc,WAC5B,4BACA,CAAC,OAAe,WAAmB,QAAgB;AACjD,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,oBAAoB,iBAAiB,eAAe;AAAA,IACtE;AACA,WAAO;AAAA,EACT,CACF;AACA,SAAO;AACT;;;AD5FA;AAYO,IAAM,WAAN,MAAe;AAAA,EAGpB,YAAY,QAAoB;AAC9B,SAAK,SAAS,UAAU,MAAM;AAAA,EAChC;AAAA,EAEA,MAAM,OACJ,KACA,SAC6C;AAC7C,UAAM,WAAW,QAAQ;AACzB,UAAM,CAAC,OAAO,eAAe,KAAK,OAAO,IAAI,GAAG;AAChD,QAAI,SAAS,MAAM,UAAU,MAAM,OAAO,SAAS;AACjD,aAAO,MAAM,KAAK,YAAY,OAAO,EAAC,aAAa,SAAQ,CAAC;AAAA,IAC9D;AACA,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,MAAM,YACJ,OACA,SAC6C;AAC7C,UAAM,cAAc,QAAQ;AAC5B,UAAM,WAAW,QAAQ;AACzB,UAAM,YAAY,MAAM,OAAO;AAC/B,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MACR,8FACF;AAAA,IACF;AACA,QAAI,QAAQ,CAAC;AACb,QAAI,MAAM,OAAO,gBAAgB;AAC/B,YAAM,YAAY,MAAM,MAAM,OAAO,eAAe;AAAA,QAClD,QAAQ;AAAA,MACV,CAAC;AACD,UAAI,UAAU,UAAU;AACtB,eAAO,KAAK,UAAU;AAAA,MACxB;AACA,UAAI,UAAU,OAAO;AACnB,gBAAQ,UAAU;AAAA,MACpB;AAAA,IACF;AAEA,UAAM,SAAS,MAAM;AACrB,UAAM,eAAe,gBAAgB,MAAM;AAE3C,UAAM,iBAAsC,CAAC;AAC7C,UAAM,cAA6B,CAAC;AACpC,UAAM,OACJ,kBAAC,aAAa,UAAb;AAAA,MAAsB,OAAO,EAAC,QAAQ,aAAY;AAAA,OACjD,kBAAC,eAAe,UAAf;AAAA,MAAwB,OAAO;AAAA,OAC9B,kBAAC,aAAa,UAAb;AAAA,MAAsB,OAAO;AAAA,OAC5B,kBAAC;AAAA,MAAW,GAAG;AAAA,KAAO,CACxB,CACF,CACF;AAEF,UAAM,WAAW,eAAe,MAAM,CAAC,GAAG,EAAC,QAAQ,KAAI,CAAC;AAIxD,UAAM,YAAY,MAAM,SAAS,IAAI,MAAM,UAAU;AACrD,UAAM,UAAU,MAAM,wCAAW;AACjC,QAAI,SAAS;AACX,cAAQ,QAAQ,CAAC,WAAW;AAC1B,uBAAe,KAAK,kBAAC;AAAA,UAAK,KAAI;AAAA,UAAa,MAAM;AAAA,SAAQ,CAAE;AAAA,MAC7D,CAAC;AAAA,IACH;AAIA,UAAM,aAAa,MAAM,KAAK,cAAc,UAAU,EAAC,SAAQ,CAAC;AAChE,eAAW,QAAQ,CAAC,WAAW;AAC7B,qBAAe,KAAK,kBAAC;AAAA,QAAO,MAAK;AAAA,QAAS,KAAK;AAAA,OAAQ,CAAE;AAAA,IAC3D,CAAC;AAGD,UAAM,QAAQ,IACZ,YAAY,IAAI,OAAO,cAAc;AACnC,YAAM,cAAc,MAAM,SAAS,IAAI,UAAU,GAAG;AACpD,UAAI,CAAC,eAAe,YAAY,IAAI,MAAM;AACxC,gBAAQ,IAAI,qCAAqC,UAAU,KAAK;AAAA,MAClE;AACA,YAAM,YAAY,cAAc,YAAY,WAAW,UAAU;AACjE,qBAAe,KAAK,kBAAC;AAAA,QAAO,MAAK;AAAA,QAAS,KAAK;AAAA,OAAW,CAAE;AAAA,IAC9D,CAAC,CACH;AAEA,UAAM,OAAO,MAAM,KAAK,WAAW,EAAC,UAAU,QAAQ,eAAc,CAAC;AACrE,WAAO,EAAC,KAAI;AAAA,EACd;AAAA,EAEA,MAAM,aAEJ;AACA,UAAM,UAGF,CAAC;AACL,UAAM,KAAK,OAAO,KAAK,OAAO,SAAiB,UAAiB;AAC9D,YAAM,aAAa,MAAM,oBAAoB,SAAS,KAAK;AAC3D,iBAAW,QAAQ,CAAC,cAAc;AAChC,gBAAQ,UAAU,WAAW;AAAA,UAC3B;AAAA,UACA,QAAQ,UAAU;AAAA,QACpB;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,WAAW,SAA4B;AACnD,UAAM,OACJ,kBAAC;AAAA,MAAK,MAAM,QAAQ;AAAA,OAClB,kBAAC,cACC,kBAAC;AAAA,MAAK,SAAQ;AAAA,KAAQ,GACrB,QAAQ,cACX,GACA,kBAAC;AAAA,MAAK,yBAAyB,EAAC,QAAQ,QAAQ,SAAQ;AAAA,KAAG,CAC7D;AAEF,UAAM,OAAO;AAAA,EAAoB,eAC/B,MACA,CAAC,GACD,EAAC,QAAQ,KAAI,CACf;AAAA;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAY;AAChB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,OAAgB;AAChC,UAAM,WAAW,eAAe,kBAAC;AAAA,MAAU;AAAA,KAAc,CAAE;AAC3D,UAAM,OAAO,MAAM,KAAK,WAAW,EAAC,UAAU,QAAQ,KAAI,CAAC;AAC3D,WAAO,EAAC,KAAI;AAAA,EACd;AAAA,EAEA,MAAc,cACZ,MACA,SACmB;AACnB,UAAM,WAAW,QAAQ;AACzB,UAAM,OAAO,oBAAI,IAAY;AAE7B,UAAM,KAAK;AACX,UAAM,UAAU,MAAM,KAAK,KAAK,SAAS,EAAE,CAAC;AAC5C,UAAM,QAAQ,IACZ,QAAQ,IAAI,OAAO,UAAU;AAC3B,YAAM,UAAU,MAAM;AAEtB,UAAI,WAAW,QAAQ,SAAS,GAAG,KAAK,WAAW,aAAa;AAC9D,cAAM,aAAa,YAAY;AAC/B,cAAM,QAAQ,MAAM,SAAS,IAAI,UAAU;AAC3C,YAAI,CAAC,OAAO;AACV;AAAA,QACF;AACA,cAAM,cAAc,MAAM,MAAM,UAAU;AAC1C,oBAAY,QAAQ,CAAC,QAAQ,KAAK,IAAI,GAAG,CAAC;AAAA,MAC5C,OAAO;AACL,gBAAQ,IAAI,4BAA4B,SAAS;AAAA,MACnD;AAAA,IACF,CAAC,CACH;AAEA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/render/render.tsx","../src/render/router.ts","../src/render/route-trie.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {ComponentChildren} from 'preact';\nimport renderToString from 'preact-render-to-string';\nimport {getRoutes, Route, getAllPathsForRoute} from './router';\nimport {HEAD_CONTEXT} from '../core/components/head';\nimport {ErrorPage} from '../core/components/error-page';\nimport {getTranslations, I18N_CONTEXT} from '../core/i18n';\nimport {ScriptProps, SCRIPT_CONTEXT} from '../core/components/script';\nimport {AssetMap} from './asset-map/asset-map';\nimport {RootConfig} from '../core/config';\nimport {RouteTrie} from './route-trie';\nimport {elementsMap} from 'virtual:root-elements';\n\ninterface RenderOptions {\n assetMap: AssetMap;\n}\n\ninterface RenderHtmlOptions {\n mainHtml: string;\n locale: string;\n headComponents?: ComponentChildren[];\n}\n\nexport class Renderer {\n private routes: RouteTrie<Route>;\n\n constructor(config: RootConfig) {\n this.routes = getRoutes(config);\n }\n\n async render(\n url: string,\n options: RenderOptions\n ): Promise<{html: string; notFound?: boolean}> {\n const assetMap = options.assetMap;\n const [route, routeParams] = this.routes.get(url);\n if (route && route.module && route.module.default) {\n return await this.renderRoute(route, {routeParams, assetMap});\n }\n return this.render404();\n }\n\n async renderRoute(\n route: Route,\n options: {routeParams: Record<string, string>; assetMap: AssetMap}\n ): Promise<{html: string; notFound?: boolean}> {\n const routeParams = options.routeParams;\n const assetMap = options.assetMap;\n const Component = route.module.default;\n if (!Component) {\n throw new Error(\n 'unable to render route. the route should have a default export that renders a jsx component.'\n );\n }\n let props = {};\n if (route.module.getStaticProps) {\n const propsData = await route.module.getStaticProps({\n params: routeParams,\n });\n if (propsData.notFound) {\n return this.render404();\n }\n if (propsData.props) {\n props = propsData.props;\n }\n }\n\n const locale = route.locale;\n const translations = getTranslations(locale);\n\n const headComponents: ComponentChildren[] = [];\n const userScripts: ScriptProps[] = [];\n const vdom = (\n <I18N_CONTEXT.Provider value={{locale, translations}}>\n <SCRIPT_CONTEXT.Provider value={userScripts}>\n <HEAD_CONTEXT.Provider value={headComponents}>\n <Component {...props} />\n </HEAD_CONTEXT.Provider>\n </SCRIPT_CONTEXT.Provider>\n </I18N_CONTEXT.Provider>\n );\n const mainHtml = renderToString(vdom, {}, {pretty: true});\n\n // Walk the page's dependency tree for CSS dependencies that are added via\n // `import 'foo.scss'` or `import 'foo.module.scss'`.\n const pageAsset = await assetMap.get(route.modulePath);\n const cssDeps = await pageAsset?.getCssDeps();\n if (cssDeps) {\n cssDeps.forEach((cssUrl) => {\n headComponents.push(<link rel=\"stylesheet\" href={cssUrl} />);\n });\n }\n\n // Parse the HTML for custom elements that are found within the project\n // and automatically inject the script deps for them.\n const scriptDeps = await this.getScriptDeps(mainHtml, {assetMap});\n scriptDeps.forEach((jsUrls) => {\n headComponents.push(<script type=\"module\" src={jsUrls} />);\n });\n\n // Add user defined scripts added via the `<Script>` component.\n await Promise.all(\n userScripts.map(async (scriptDep) => {\n const scriptAsset = await assetMap.get(scriptDep.src);\n if (scriptAsset) {\n const scriptUrl = scriptAsset ? scriptAsset.assetUrl : scriptDep.src;\n headComponents.push(<script type=\"module\" src={scriptUrl} />);\n }\n })\n );\n\n const html = await this.renderHtml({mainHtml, locale, headComponents});\n return {html};\n }\n\n async getSitemap(): Promise<\n Record<string, {route: Route; params: Record<string, string>}>\n > {\n const sitemap: Record<\n string,\n {route: Route; params: Record<string, string>}\n > = {};\n await this.routes.walk(async (urlPath: string, route: Route) => {\n const routePaths = await getAllPathsForRoute(urlPath, route);\n routePaths.forEach((routePath) => {\n sitemap[routePath.urlPath] = {\n route,\n params: routePath.params,\n };\n });\n });\n return sitemap;\n }\n\n private async renderHtml(options: RenderHtmlOptions) {\n const page = (\n <html lang={options.locale}>\n <head>\n <meta charSet=\"utf-8\" />\n {options.headComponents}\n </head>\n <body dangerouslySetInnerHTML={{__html: options.mainHtml}} />\n </html>\n );\n const html = `<!doctype html>\\n${renderToString(\n page,\n {},\n {pretty: true}\n )}\\n`;\n return html;\n }\n\n async render404() {\n return {\n html: '<!doctype html><html><title>404 Not Found</title><h1>404 Not Found</h1>',\n notFound: true,\n };\n }\n\n async renderError(error: unknown) {\n const mainHtml = renderToString(<ErrorPage error={error} />);\n const html = await this.renderHtml({mainHtml, locale: 'en'});\n return {html};\n }\n\n private async getScriptDeps(\n html: string,\n options: {assetMap: AssetMap}\n ): Promise<string[]> {\n const assetMap = options.assetMap as AssetMap;\n const deps = new Set<string>();\n\n const re = /<(\\w[\\w-]+\\w)/g;\n const matches = Array.from(html.matchAll(re));\n await Promise.all(\n matches.map(async (match) => {\n const tagName = match[1];\n // Custom elements require a dash.\n if (tagName && tagName.includes('-') && tagName in elementsMap) {\n const modulePath = elementsMap[tagName];\n const asset = await assetMap.get(modulePath);\n if (!asset) {\n return;\n }\n const assetJsDeps = await asset.getJsDeps();\n assetJsDeps.forEach((dep) => deps.add(dep));\n }\n })\n );\n\n return Array.from(deps);\n }\n}\n","import path from 'node:path';\nimport {ComponentType} from 'preact';\nimport {RootConfig} from '../core/config';\nimport {GetStaticPaths, GetStaticProps} from '../core/types';\nimport {RouteTrie} from './route-trie';\n\nexport interface RouteModule {\n default?: ComponentType<unknown>;\n getStaticPaths?: GetStaticPaths;\n getStaticProps?: GetStaticProps;\n}\n\nexport interface Route {\n modulePath: string;\n module: RouteModule;\n locale: string;\n}\n\nexport function getRoutes(config: RootConfig) {\n const locales = config.i18n?.locales || [];\n const i18nUrlFormat = config.i18n?.urlFormat || '/{locale}/{path}';\n const defaultLocale = config.i18n?.defaultLocale || 'en';\n\n const routes = import.meta.glob(\n ['/routes/*.ts', '/routes/**/*.ts', '/routes/*.tsx', '/routes/**/*.tsx'],\n {\n eager: true,\n }\n );\n const trie = new RouteTrie<Route>();\n Object.keys(routes).forEach((filePath) => {\n let routePath = filePath.replace(/^\\/routes/, '');\n const parts = path.parse(routePath);\n if (parts.name.startsWith('_')) {\n return;\n }\n if (parts.name === 'index') {\n routePath = parts.dir;\n } else {\n routePath = path.join(parts.dir, parts.name);\n }\n trie.add(routePath, {\n modulePath: filePath,\n module: routes[filePath] as RouteModule,\n locale: defaultLocale,\n });\n\n // At the moment, all routes are assumed to use the site-wide i18n config.\n // TODO(stevenle): provide routes with a way to override the default\n // i18n serving behavior.\n locales.forEach((locale) => {\n const localeRoutePath = i18nUrlFormat\n .replace('{locale}', locale)\n .replace('{path}', routePath.replace(/^\\/*/, ''));\n if (localeRoutePath !== routePath) {\n trie.add(localeRoutePath, {\n modulePath: filePath,\n module: routes[filePath] as RouteModule,\n locale: locale,\n });\n }\n });\n });\n return trie;\n}\n\nexport async function getAllPathsForRoute(\n urlPathFormat: string,\n route: Route\n): Promise<Array<{urlPath: string; params: Record<string, string>}>> {\n const urlPaths: Array<{urlPath: string; params: Record<string, string>}> = [];\n const routeModule = route.module;\n if (routeModule.getStaticPaths) {\n const staticPaths = await routeModule.getStaticPaths();\n staticPaths.paths.forEach(\n (pathParams: {params: Record<string, string>}) => {\n urlPaths.push({\n urlPath: replaceParams(urlPathFormat, pathParams.params),\n params: pathParams.params || {},\n });\n }\n );\n } else {\n urlPaths.push({urlPath: urlPathFormat, params: {}});\n }\n return urlPaths;\n}\n\nexport function replaceParams(\n urlPathFormat: string,\n params: Record<string, string>\n) {\n const urlPath = urlPathFormat.replaceAll(\n /\\[(\\.\\.\\.)?([\\w\\-_]*)\\]/g,\n (match: string, _wildcard: string, key: string) => {\n const val = params[key];\n if (!val) {\n throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);\n }\n return val;\n }\n );\n return urlPath;\n}\n","/**\n * A trie data structure that stores routes. The trie supports `:param` and\n * `*wildcard` values.\n */\nexport class RouteTrie<T> {\n private children: Record<string, RouteTrie<T>> = {};\n private paramChild?: ParamChild<T>;\n private wildcardChild?: WildcardChild<T>;\n private route?: T;\n\n /**\n * Adds a route to the trie.\n */\n add(path: string, route: T) {\n path = this.normalizePath(path);\n\n // If the end was reached, save the value to the node.\n if (path === '') {\n this.route = route;\n return;\n }\n\n const [head, tail] = this.splitPath(path);\n if (head.startsWith('[...') && head.endsWith(']')) {\n const paramName = head.slice(4, -1);\n this.wildcardChild = new WildcardChild(paramName, route);\n return;\n }\n\n let nextNode: RouteTrie<T>;\n if (head.startsWith('[') && head.endsWith(']')) {\n if (!this.paramChild) {\n const paramName = head.slice(1, -1);\n this.paramChild = new ParamChild(paramName);\n }\n nextNode = this.paramChild.trie;\n } else {\n nextNode = this.children[head];\n if (!nextNode) {\n nextNode = new RouteTrie();\n this.children[head] = nextNode;\n }\n }\n nextNode.add(tail, route);\n }\n\n /**\n * Returns a route mapped to the given path and any parameter values from the\n * URL.\n */\n get(path: string): [T | undefined, Record<string, string>] {\n const params = {};\n const route = this.getRoute(path, params);\n return [route, params];\n }\n\n /**\n * Walks the route trie and calls a callback function for each route.\n */\n walk(cb: (urlPath: string, route: T) => Promise<void> | void): Promise<void> {\n const promises: Array<Promise<void>> = [];\n const addPromise = (promise: Promise<void> | void) => {\n if (promise) {\n promises.push(promise);\n }\n };\n if (this.route) {\n addPromise(cb('/', this.route));\n }\n if (this.paramChild) {\n const param = `[${this.paramChild.name}]`;\n this.paramChild.trie.walk((childPath: string, route: T) => {\n const paramUrlPath = `/${param}${childPath}`;\n addPromise(cb(paramUrlPath, route));\n });\n }\n if (this.wildcardChild) {\n const wildcardUrlPath = `/[...${this.wildcardChild.name}]`;\n addPromise(cb(wildcardUrlPath, this.wildcardChild.route));\n }\n for (const subpath of Object.keys(this.children)) {\n const childTrie = this.children[subpath];\n childTrie.walk((childPath: string, childRoute: T) => {\n addPromise(cb(`/${subpath}${childPath}`, childRoute));\n });\n }\n return Promise.all(promises).then(() => {});\n }\n\n /**\n * Removes all routes from the trie.\n */\n clear() {\n this.children = {};\n this.paramChild = undefined;\n this.wildcardChild = undefined;\n this.route = undefined;\n }\n\n private getRoute(\n urlPath: string,\n params: Record<string, string>\n ): T | undefined {\n urlPath = this.normalizePath(urlPath);\n if (urlPath === '') {\n return this.route;\n }\n\n const [head, tail] = this.splitPath(urlPath);\n\n const child = this.children[head];\n if (child) {\n const route = child.getRoute(tail, params);\n if (route) {\n return route;\n }\n }\n\n if (this.paramChild) {\n const route = this.paramChild.trie.getRoute(tail, params);\n if (route) {\n params[this.paramChild.name] = head;\n return route;\n }\n }\n\n if (this.wildcardChild) {\n params[this.wildcardChild.name] = urlPath;\n return this.wildcardChild.route;\n }\n\n return undefined;\n }\n\n /**\n * Normalizes a path for inclusion into the route trie.\n */\n private normalizePath(path: string) {\n // Remove leading slashes.\n return path.replace(/^\\/+/g, '');\n }\n\n /**\n * Splits the parent directory from its children, e.g.:\n *\n * splitPath(\"foo/bar/baz\") -> [\"foo\", \"bar/baz\"]\n */\n private splitPath(path: string): [string, string] {\n const i = path.indexOf('/');\n if (i === -1) {\n return [path, ''];\n }\n return [path.slice(0, i), path.slice(i + 1)];\n }\n}\n\n/**\n * A node in the RouteTrie for a :param child.\n */\nclass ParamChild<T> {\n readonly name: string;\n readonly trie: RouteTrie<T> = new RouteTrie();\n\n constructor(name: string) {\n this.name = name;\n }\n}\n\n/**\n * A node in the RouteTrie for a *wildcard child.\n */\nclass WildcardChild<T> {\n readonly name: string;\n readonly route: T;\n\n constructor(name: string, route: T) {\n this.name = name;\n this.route = route;\n }\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -21,6 +21,10 @@ interface RootConfig {
|
|
|
21
21
|
* @see {@link https://vitejs.dev/config/} for more information.
|
|
22
22
|
*/
|
|
23
23
|
vite?: UserConfig;
|
|
24
|
+
/**
|
|
25
|
+
* Whether to automatically minify HTML output.
|
|
26
|
+
*/
|
|
27
|
+
minifyHtml?: boolean;
|
|
24
28
|
/**
|
|
25
29
|
* Whether to include a sitemap.xml file to the build output.
|
|
26
30
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blinkk/root",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.6",
|
|
4
4
|
"author": "s@blinkk.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"preact-custom-element": "^4.2.1",
|
|
61
61
|
"preact-render-to-string": "^5.2.3",
|
|
62
62
|
"rollup": "^2.79.0",
|
|
63
|
-
"tsup": "^
|
|
63
|
+
"tsup": "^6.2.3",
|
|
64
64
|
"typescript": "^4.7.4",
|
|
65
65
|
"vitest": "^0.18.1"
|
|
66
66
|
},
|