@blinkk/root 1.0.0-alpha.1 → 1.0.0-alpha.3
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 +8 -1
- package/dist/{chunk-4SVK7R4Z.js → chunk-CDPH3RKE.js} +21 -18
- package/dist/chunk-CDPH3RKE.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +134 -106
- package/dist/cli.js.map +1 -1
- package/dist/core.d.ts +3 -3
- package/dist/core.js +3 -3
- package/dist/render.d.ts +3 -14
- package/dist/render.js +6 -5
- package/dist/render.js.map +1 -1
- package/dist/types-d6c0705e.d.ts +27 -0
- package/package.json +5 -2
- package/dist/chunk-4SVK7R4Z.js.map +0 -1
- package/dist/config-5b8f6033.d.ts +0 -15
package/bin/root.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import {createRequire} from 'node:module';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
3
6
|
import {Command} from 'commander';
|
|
4
7
|
import {build, dev, start} from '../dist/cli.js';
|
|
5
8
|
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const packageJson = require(path.join(__dirname, '../package.json'));
|
|
12
|
+
|
|
6
13
|
const program = new Command('root');
|
|
7
|
-
program.version(
|
|
14
|
+
program.version(packageJson.version);
|
|
8
15
|
|
|
9
16
|
program
|
|
10
17
|
.command('build [path]')
|
|
@@ -49,21 +49,6 @@ import path from "node:path";
|
|
|
49
49
|
import { createContext as createContext3 } from "preact";
|
|
50
50
|
import { useContext as useContext3 } from "preact/hooks";
|
|
51
51
|
var I18N_CONTEXT = createContext3(null);
|
|
52
|
-
function t(str, params) {
|
|
53
|
-
const context = useContext3(I18N_CONTEXT);
|
|
54
|
-
if (!context) {
|
|
55
|
-
throw new Error("could not find i18n context");
|
|
56
|
-
}
|
|
57
|
-
const translations = (context == null ? void 0 : context.translations) || {};
|
|
58
|
-
let translation = translations[str] || str;
|
|
59
|
-
if (params) {
|
|
60
|
-
for (const key in params) {
|
|
61
|
-
const val = String(params[key] || "");
|
|
62
|
-
translation = translation.replaceAll(`{${key}}`, val);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return translation;
|
|
66
|
-
}
|
|
67
52
|
function getTranslations(locale) {
|
|
68
53
|
const translations = {};
|
|
69
54
|
const translationsFiles = import.meta.glob(["/translations/*.json"], {
|
|
@@ -79,6 +64,24 @@ function getTranslations(locale) {
|
|
|
79
64
|
});
|
|
80
65
|
return translations[locale] || {};
|
|
81
66
|
}
|
|
67
|
+
function useTranslations() {
|
|
68
|
+
const context = useContext3(I18N_CONTEXT);
|
|
69
|
+
if (!context) {
|
|
70
|
+
throw new Error("could not find i18n context");
|
|
71
|
+
}
|
|
72
|
+
const translations = (context == null ? void 0 : context.translations) || {};
|
|
73
|
+
const t = (str, params) => {
|
|
74
|
+
let translation = translations[str] || str || "";
|
|
75
|
+
if (params) {
|
|
76
|
+
for (const key of Object.keys(params)) {
|
|
77
|
+
const val = String(params[key] || "");
|
|
78
|
+
translation = translation.replaceAll(`{${key}}`, val);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return translation;
|
|
82
|
+
};
|
|
83
|
+
return t;
|
|
84
|
+
}
|
|
82
85
|
|
|
83
86
|
export {
|
|
84
87
|
ErrorPage,
|
|
@@ -87,7 +90,7 @@ export {
|
|
|
87
90
|
SCRIPT_CONTEXT,
|
|
88
91
|
Script,
|
|
89
92
|
I18N_CONTEXT,
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
getTranslations,
|
|
94
|
+
useTranslations
|
|
92
95
|
};
|
|
93
|
-
//# sourceMappingURL=chunk-
|
|
96
|
+
//# sourceMappingURL=chunk-CDPH3RKE.js.map
|
|
@@ -0,0 +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":";AACA;AAMO,mBAAmB,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,kBAAC,aACC,kBAAC,aACC,kBAAC,WAAE,2DAAyD,GAC3D,WAAW,kBAAC,aAAK,OAAQ,CAC5B,CACF;AAEJ;;;AC3BA;AACA;AAEO,IAAM,eAAe,cAAmC,CAAC,CAAC;AAU1D,cAAc,OAAkB;AACrC,MAAI;AACJ,MAAI;AACF,cAAU,WAAW,YAAY;AAAA,EACnC,SAAS,KAAP;AACA,YAAQ,IAAI,GAAG;AACf,UAAM,IAAI,MACR,iFACA,EAAC,OAAO,IAAG,CACb;AAAA,EACF;AACA,UAAQ,KAAK,MAAM,QAAQ;AAC3B,SAAO;AACT;;;AC1BA;AACA;AAEO,IAAM,iBAAiB,eAA6B,CAAC,CAAC;AAYtD,gBAAgB,OAAoB;AACzC,MAAI;AACJ,MAAI;AACF,cAAU,YAAW,cAAc;AAAA,EACrC,SAAS,KAAP;AACA,UAAM,IAAI,MACR,mFACA,EAAC,OAAO,IAAG,CACb;AAAA,EACF;AACA,UAAQ,KAAK,KAAK;AAClB,SAAO;AACT;;;AC3BA;AACA;AACA;AAEO,IAAM,eAAe,eAAkC,IAAI;AAO3D,yBAAyB,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,UAAM,UAAS,MAAM;AACrB,UAAM,SAAS,kBAAkB;AACjC,QAAI,UAAU,OAAO,SAAS;AAC5B,mBAAa,WAAU,OAAO;AAAA,IAChC;AAAA,EACF,CAAC;AACD,SAAO,aAAa,WAAW,CAAC;AAClC;AAEO,2BAA2B;AAChC,QAAM,UAAU,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,QAAM,eAAe,oCAAS,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":[]}
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,70 +1,109 @@
|
|
|
1
1
|
// src/cli/commands/dev.ts
|
|
2
|
-
import
|
|
2
|
+
import path4 from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { default as express } from "express";
|
|
5
5
|
import { createServer as createViteServer } from "vite";
|
|
6
6
|
|
|
7
7
|
// src/render/vite-plugin-root.ts
|
|
8
|
-
import
|
|
8
|
+
import path2 from "path";
|
|
9
9
|
import glob from "tiny-glob";
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
// src/core/fsutils.ts
|
|
12
|
+
import { promises as fs } from "node:fs";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import fsExtra from "fs-extra";
|
|
15
|
+
function isJsFile(filename) {
|
|
16
|
+
return !!filename.match(/\.(j|t)sx?$/);
|
|
17
|
+
}
|
|
18
|
+
async function writeFile(filepath, content) {
|
|
19
|
+
const dirPath = path.dirname(filepath);
|
|
20
|
+
await makeDir(dirPath);
|
|
21
|
+
await fs.writeFile(filepath, content);
|
|
22
|
+
}
|
|
23
|
+
async function makeDir(dirpath) {
|
|
24
|
+
try {
|
|
25
|
+
await fs.access(dirpath);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
await fs.mkdir(dirpath, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function copyDir(srcdir, dstdir) {
|
|
31
|
+
if (!fsExtra.existsSync(srcdir)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
fsExtra.copySync(srcdir, dstdir, { recursive: true, overwrite: true });
|
|
35
|
+
}
|
|
36
|
+
async function rmDir(dirpath) {
|
|
37
|
+
await fs.rm(dirpath, { recursive: true, force: true });
|
|
38
|
+
}
|
|
39
|
+
async function loadJson(filepath) {
|
|
40
|
+
const content = await fs.readFile(filepath, "utf-8");
|
|
41
|
+
return JSON.parse(content);
|
|
42
|
+
}
|
|
43
|
+
async function isDirectory(dirpath) {
|
|
44
|
+
return fs.stat(dirpath).then((fsStat) => {
|
|
45
|
+
return fsStat.isDirectory();
|
|
46
|
+
}).catch((err) => {
|
|
47
|
+
if (err.code === "ENOENT") {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
throw err;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/render/vite-plugin-root.ts
|
|
55
|
+
var JSX_ELEMENTS_REGEX = /jsxs?\("(\w[\w-]+\w)"/g;
|
|
56
|
+
var HTML_ELEMENTS_REGEX = /<(\w[\w-]+\w)/g;
|
|
11
57
|
function pluginRoot(options) {
|
|
12
58
|
const rootDir = (options == null ? void 0 : options.rootDir) || process.cwd();
|
|
13
|
-
let config;
|
|
14
|
-
let server;
|
|
15
59
|
let elementMap;
|
|
16
60
|
async function updateElementMap() {
|
|
17
61
|
elementMap = {};
|
|
18
62
|
const files = await glob("./elements/**/*", { cwd: rootDir });
|
|
19
63
|
files.forEach((file) => {
|
|
20
|
-
const parts =
|
|
64
|
+
const parts = path2.parse(file);
|
|
21
65
|
if (isJsFile(parts.base)) {
|
|
22
|
-
elementMap[parts.name] =
|
|
66
|
+
elementMap[parts.name] = `/${file}`;
|
|
23
67
|
}
|
|
24
68
|
});
|
|
69
|
+
console.log(JSON.stringify(elementMap));
|
|
25
70
|
}
|
|
26
|
-
async function getElementImport(
|
|
71
|
+
async function getElementImport(tagname) {
|
|
27
72
|
if (!elementMap) {
|
|
28
73
|
await updateElementMap();
|
|
29
74
|
}
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
if (server && server.moduleGraph) {
|
|
33
|
-
const moduleSet = server.moduleGraph.getModulesByFile(filePath);
|
|
34
|
-
if (moduleSet && moduleSet.size > 0) {
|
|
35
|
-
const module = moduleSet.values().next().value;
|
|
36
|
-
return module.url;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
75
|
+
if (tagname in elementMap) {
|
|
76
|
+
return elementMap[tagname];
|
|
39
77
|
}
|
|
40
78
|
return null;
|
|
41
79
|
}
|
|
42
80
|
return {
|
|
43
81
|
name: "vite-plugin-root",
|
|
44
|
-
configResolved(resolvedConfig) {
|
|
45
|
-
config = resolvedConfig;
|
|
46
|
-
},
|
|
47
|
-
configureServer(_server) {
|
|
48
|
-
server = _server;
|
|
49
|
-
},
|
|
50
82
|
async transform(src, id) {
|
|
51
|
-
if (id.
|
|
52
|
-
|
|
83
|
+
if (!id.startsWith(rootDir)) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const moduleId = id.slice(rootDir.length);
|
|
87
|
+
if (moduleId.startsWith("/elements/") && isJsFile(id)) {
|
|
88
|
+
const idParts = path2.parse(id);
|
|
53
89
|
const deps = /* @__PURE__ */ new Set();
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
90
|
+
const tagnames = [
|
|
91
|
+
...src.matchAll(JSX_ELEMENTS_REGEX),
|
|
92
|
+
...src.matchAll(HTML_ELEMENTS_REGEX)
|
|
93
|
+
];
|
|
94
|
+
for (const match of tagnames) {
|
|
95
|
+
const tagname = match[1];
|
|
96
|
+
if (!tagname.includes("-")) {
|
|
58
97
|
continue;
|
|
59
98
|
}
|
|
60
|
-
if (
|
|
99
|
+
if (tagname === idParts.name) {
|
|
61
100
|
continue;
|
|
62
101
|
}
|
|
63
|
-
deps.add(
|
|
102
|
+
deps.add(tagname);
|
|
64
103
|
}
|
|
65
104
|
const importUrls = [];
|
|
66
|
-
await Promise.all(Array.from(deps).map(async (
|
|
67
|
-
const importUrl = await getElementImport(
|
|
105
|
+
await Promise.all(Array.from(deps).map(async (tagname) => {
|
|
106
|
+
const importUrl = await getElementImport(tagname);
|
|
68
107
|
if (importUrl) {
|
|
69
108
|
importUrls.push(importUrl);
|
|
70
109
|
}
|
|
@@ -76,6 +115,7 @@ function pluginRoot(options) {
|
|
|
76
115
|
// autogenerated by root:
|
|
77
116
|
${importLines}
|
|
78
117
|
`;
|
|
118
|
+
console.log(code);
|
|
79
119
|
return { code };
|
|
80
120
|
}
|
|
81
121
|
return null;
|
|
@@ -83,13 +123,9 @@ ${importLines}
|
|
|
83
123
|
}
|
|
84
124
|
};
|
|
85
125
|
}
|
|
86
|
-
function isJsFile(file) {
|
|
87
|
-
return !!file.match(/\.(j|t)sx?$/);
|
|
88
|
-
}
|
|
89
|
-
var vite_plugin_root_default = pluginRoot;
|
|
90
126
|
|
|
91
127
|
// src/render/asset-map/dev-asset-map.ts
|
|
92
|
-
import
|
|
128
|
+
import path3 from "node:path";
|
|
93
129
|
var DevServerAssetMap = class {
|
|
94
130
|
constructor(moduleGraph) {
|
|
95
131
|
this.moduleGraph = moduleGraph;
|
|
@@ -135,7 +171,7 @@ var DevServerAsset = class {
|
|
|
135
171
|
return;
|
|
136
172
|
}
|
|
137
173
|
visited.add(asset.moduleId);
|
|
138
|
-
const parts =
|
|
174
|
+
const parts = path3.parse(asset.assetUrl);
|
|
139
175
|
if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && asset.moduleId.includes("/elements/")) {
|
|
140
176
|
urls.add(asset.assetUrl);
|
|
141
177
|
}
|
|
@@ -158,7 +194,7 @@ var DevServerAsset = class {
|
|
|
158
194
|
}
|
|
159
195
|
visited.add(asset.assetUrl);
|
|
160
196
|
if (asset.moduleId.endsWith(".scss")) {
|
|
161
|
-
const parts =
|
|
197
|
+
const parts = path3.parse(asset.assetUrl);
|
|
162
198
|
if (!parts.name.startsWith("_")) {
|
|
163
199
|
urls.add(asset.assetUrl);
|
|
164
200
|
}
|
|
@@ -202,15 +238,15 @@ async function htmlMinify(html) {
|
|
|
202
238
|
}
|
|
203
239
|
|
|
204
240
|
// src/cli/commands/dev.ts
|
|
205
|
-
|
|
241
|
+
import glob2 from "tiny-glob";
|
|
242
|
+
var __dirname2 = path4.dirname(fileURLToPath(import.meta.url));
|
|
206
243
|
async function createServer(options) {
|
|
207
244
|
const app = express();
|
|
208
245
|
app.use(express.static("public"));
|
|
209
246
|
const middlewares = await getMiddlewares({ rootDir: options == null ? void 0 : options.rootDir });
|
|
210
247
|
middlewares.forEach((middleware) => app.use(middleware));
|
|
211
248
|
const port = parseInt(process.env.PORT || "4007");
|
|
212
|
-
|
|
213
|
-
console.log(`\u{1F333} Root.js v${version}`);
|
|
249
|
+
console.log("\u{1F333} Root.js");
|
|
214
250
|
console.log();
|
|
215
251
|
console.log(`Started server: http://localhost:${port}`);
|
|
216
252
|
app.listen(port);
|
|
@@ -219,19 +255,52 @@ async function getMiddlewares(options) {
|
|
|
219
255
|
const rootDir = (options == null ? void 0 : options.rootDir) || process.cwd();
|
|
220
256
|
const rootConfig = await loadRootConfig(rootDir);
|
|
221
257
|
const viteConfig = rootConfig.vite || {};
|
|
222
|
-
const renderModulePath =
|
|
258
|
+
const renderModulePath = path4.resolve(__dirname2, "./render.js");
|
|
259
|
+
const pages = [];
|
|
260
|
+
if (await isDirectory(path4.join(rootDir, "routes"))) {
|
|
261
|
+
const pageFiles = await glob2(path4.join(rootDir, "routes/**/*"));
|
|
262
|
+
pageFiles.forEach((file) => {
|
|
263
|
+
const parts = path4.parse(file);
|
|
264
|
+
if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
|
|
265
|
+
pages.push(file);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const elements = [];
|
|
270
|
+
if (await isDirectory(path4.join(rootDir, "elements"))) {
|
|
271
|
+
const elementFiles = await glob2(path4.join(rootDir, "elements/**/*"));
|
|
272
|
+
elementFiles.forEach((file) => {
|
|
273
|
+
const parts = path4.parse(file);
|
|
274
|
+
if (isJsFile(parts.base)) {
|
|
275
|
+
elements.push(file);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
const bundleScripts = [];
|
|
280
|
+
if (await isDirectory(path4.join(rootDir, "bundles"))) {
|
|
281
|
+
const bundleFiles = await glob2(path4.join(rootDir, "bundles/*"));
|
|
282
|
+
bundleFiles.forEach((file) => {
|
|
283
|
+
const parts = path4.parse(file);
|
|
284
|
+
if (isJsFile(parts.base)) {
|
|
285
|
+
bundleScripts.push(file);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
223
289
|
const viteServer = await createViteServer({
|
|
224
290
|
...viteConfig,
|
|
225
291
|
server: { middlewareMode: true },
|
|
226
292
|
appType: "custom",
|
|
227
293
|
optimizeDeps: {
|
|
228
|
-
include: [
|
|
294
|
+
include: [...pages, ...elements, ...bundleScripts]
|
|
295
|
+
},
|
|
296
|
+
ssr: {
|
|
297
|
+
noExternal: ["@blinkk/root"]
|
|
229
298
|
},
|
|
230
299
|
esbuild: {
|
|
231
300
|
jsx: "automatic",
|
|
232
301
|
jsxImportSource: "preact"
|
|
233
302
|
},
|
|
234
|
-
plugins: [...viteConfig.plugins || [],
|
|
303
|
+
plugins: [...viteConfig.plugins || [], pluginRoot({ rootDir, rootConfig })]
|
|
235
304
|
});
|
|
236
305
|
const rootMiddleware = async (req, res, next) => {
|
|
237
306
|
const url = req.originalUrl;
|
|
@@ -266,11 +335,11 @@ function dev(rootDir) {
|
|
|
266
335
|
import path6 from "node:path";
|
|
267
336
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
268
337
|
import fsExtra2 from "fs-extra";
|
|
269
|
-
import
|
|
338
|
+
import glob3 from "tiny-glob";
|
|
270
339
|
import { build as viteBuild } from "vite";
|
|
271
340
|
|
|
272
341
|
// src/render/asset-map/build-asset-map.ts
|
|
273
|
-
import
|
|
342
|
+
import path5 from "path";
|
|
274
343
|
var BuildAssetMap = class {
|
|
275
344
|
constructor(manifest) {
|
|
276
345
|
this.manifest = manifest;
|
|
@@ -323,8 +392,8 @@ var BuildAsset = class {
|
|
|
323
392
|
return;
|
|
324
393
|
}
|
|
325
394
|
visited.add(asset.moduleId);
|
|
326
|
-
const parts =
|
|
327
|
-
if ([".ts", ".tsx"].includes(parts.ext) && asset.moduleId.includes("/elements/")) {
|
|
395
|
+
const parts = path5.parse(asset.assetUrl);
|
|
396
|
+
if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && asset.moduleId.includes("/elements/")) {
|
|
328
397
|
urls.add(asset.assetUrl);
|
|
329
398
|
}
|
|
330
399
|
await Promise.all(asset.importedModules.map(async (moduleId) => {
|
|
@@ -361,54 +430,10 @@ var BuildAsset = class {
|
|
|
361
430
|
}
|
|
362
431
|
};
|
|
363
432
|
|
|
364
|
-
// src/core/fsutils.ts
|
|
365
|
-
import { promises as fs } from "node:fs";
|
|
366
|
-
import path5 from "node:path";
|
|
367
|
-
import fsExtra from "fs-extra";
|
|
368
|
-
function isJsFile2(file) {
|
|
369
|
-
return !!file.match(/\.(j|t)sx?$/);
|
|
370
|
-
}
|
|
371
|
-
async function writeFile(filePath, content) {
|
|
372
|
-
const dirPath = path5.dirname(filePath);
|
|
373
|
-
await makeDir(dirPath);
|
|
374
|
-
await fs.writeFile(filePath, content);
|
|
375
|
-
}
|
|
376
|
-
async function makeDir(dirPath) {
|
|
377
|
-
try {
|
|
378
|
-
await fs.access(dirPath);
|
|
379
|
-
} catch (e) {
|
|
380
|
-
await fs.mkdir(dirPath, { recursive: true });
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
async function copyDir(srcDir, dstDir) {
|
|
384
|
-
if (!fsExtra.existsSync(srcDir)) {
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
fsExtra.copySync(srcDir, dstDir, { recursive: true, overwrite: true });
|
|
388
|
-
}
|
|
389
|
-
async function rmDir(dirPath) {
|
|
390
|
-
await fs.rm(dirPath, { recursive: true, force: true });
|
|
391
|
-
}
|
|
392
|
-
async function loadJson(filePath) {
|
|
393
|
-
const content = await fs.readFile(filePath, "utf-8");
|
|
394
|
-
return JSON.parse(content);
|
|
395
|
-
}
|
|
396
|
-
async function isDirectory(dirPath) {
|
|
397
|
-
return fs.stat(dirPath).then((fsStat) => {
|
|
398
|
-
return fsStat.isDirectory();
|
|
399
|
-
}).catch((err) => {
|
|
400
|
-
if (err.code === "ENOENT") {
|
|
401
|
-
return false;
|
|
402
|
-
}
|
|
403
|
-
throw err;
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
|
|
407
433
|
// src/cli/commands/build.ts
|
|
408
434
|
var __dirname3 = path6.dirname(fileURLToPath2(import.meta.url));
|
|
409
435
|
async function build(rootDir) {
|
|
410
|
-
|
|
411
|
-
console.log(`\u{1F333} Root.js v${version}`);
|
|
436
|
+
console.log("\u{1F333} Root.js");
|
|
412
437
|
if (!rootDir) {
|
|
413
438
|
rootDir = process.cwd();
|
|
414
439
|
}
|
|
@@ -418,30 +443,30 @@ async function build(rootDir) {
|
|
|
418
443
|
await makeDir(distDir);
|
|
419
444
|
const pages = [];
|
|
420
445
|
if (await isDirectory(path6.join(rootDir, "routes"))) {
|
|
421
|
-
const pageFiles = await
|
|
446
|
+
const pageFiles = await glob3(path6.join(rootDir, "routes/**/*"));
|
|
422
447
|
pageFiles.forEach((file) => {
|
|
423
448
|
const parts = path6.parse(file);
|
|
424
|
-
if (!parts.name.startsWith("_") &&
|
|
449
|
+
if (!parts.name.startsWith("_") && isJsFile(parts.base)) {
|
|
425
450
|
pages.push(file);
|
|
426
451
|
}
|
|
427
452
|
});
|
|
428
453
|
}
|
|
429
454
|
const elements = [];
|
|
430
455
|
if (await isDirectory(path6.join(rootDir, "elements"))) {
|
|
431
|
-
const elementFiles = await
|
|
456
|
+
const elementFiles = await glob3(path6.join(rootDir, "elements/**/*"));
|
|
432
457
|
elementFiles.forEach((file) => {
|
|
433
458
|
const parts = path6.parse(file);
|
|
434
|
-
if (
|
|
459
|
+
if (isJsFile(parts.base)) {
|
|
435
460
|
elements.push(file);
|
|
436
461
|
}
|
|
437
462
|
});
|
|
438
463
|
}
|
|
439
464
|
const bundleScripts = [];
|
|
440
465
|
if (await isDirectory(path6.join(rootDir, "bundles"))) {
|
|
441
|
-
const bundleFiles = await
|
|
466
|
+
const bundleFiles = await glob3(path6.join(rootDir, "bundles/*"));
|
|
442
467
|
bundleFiles.forEach((file) => {
|
|
443
468
|
const parts = path6.parse(file);
|
|
444
|
-
if (
|
|
469
|
+
if (isJsFile(parts.base)) {
|
|
445
470
|
bundleScripts.push(file);
|
|
446
471
|
}
|
|
447
472
|
});
|
|
@@ -451,11 +476,11 @@ async function build(rootDir) {
|
|
|
451
476
|
...viteConfig,
|
|
452
477
|
root: rootDir,
|
|
453
478
|
esbuild: {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
479
|
+
jsx: "automatic",
|
|
480
|
+
jsxImportSource: "preact",
|
|
481
|
+
treeShaking: true
|
|
457
482
|
},
|
|
458
|
-
plugins: [...viteConfig.plugins || [], pluginRoot()]
|
|
483
|
+
plugins: [...viteConfig.plugins || [], pluginRoot({ rootDir, rootConfig })]
|
|
459
484
|
};
|
|
460
485
|
await viteBuild({
|
|
461
486
|
...baseConfig,
|
|
@@ -478,6 +503,9 @@ async function build(rootDir) {
|
|
|
478
503
|
minify: false,
|
|
479
504
|
polyfillModulePreload: false,
|
|
480
505
|
reportCompressedSize: false
|
|
506
|
+
},
|
|
507
|
+
ssr: {
|
|
508
|
+
noExternal: ["@blinkk/root"]
|
|
481
509
|
}
|
|
482
510
|
});
|
|
483
511
|
await viteBuild({
|
|
@@ -537,7 +565,7 @@ async function build(rootDir) {
|
|
|
537
565
|
}
|
|
538
566
|
|
|
539
567
|
// src/cli/commands/start.ts
|
|
540
|
-
async function start(
|
|
568
|
+
async function start() {
|
|
541
569
|
console.log("SSR production server is coming soon");
|
|
542
570
|
}
|
|
543
571
|
export {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/dev.ts","../src/render/vite-plugin-root.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/core/fsutils.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';\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 const version = process.env.npm_package_version || 'dev';\n console.log(`🌳 Root.js v${version}`);\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 viteServer = await createViteServer({\n ...viteConfig,\n server: {middlewareMode: true},\n appType: 'custom',\n optimizeDeps: {\n include: [renderModulePath],\n },\n esbuild: {\n jsx: 'automatic',\n jsxImportSource: 'preact',\n },\n plugins: [...(viteConfig.plugins || []), pluginRoot()],\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 {ViteDevServer} from 'vite';\n\nconst ELEMENTS_REGEX = /h\\(\"(\\w[\\w-]+\\w)\"/g;\n\nexport interface RootPluginOptions {\n // Project directory.\n rootDir?: string;\n}\n\nexport function pluginRoot(options?: RootPluginOptions) {\n const rootDir = options?.rootDir || process.cwd();\n let config: any;\n let server: ViteDevServer;\n let elementMap: Record<string, string>;\n\n async function updateElementMap() {\n elementMap = {};\n const files = await glob('./elements/**/*', {cwd: rootDir});\n files.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n elementMap[parts.name] = `${rootDir}/${file}`;\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 const filePath = elementMap[tagName];\n if (server && server.moduleGraph) {\n const moduleSet = server.moduleGraph.getModulesByFile(filePath);\n if (moduleSet && moduleSet.size > 0) {\n const module = moduleSet.values().next().value;\n return module.url;\n }\n }\n }\n return null;\n }\n\n return {\n name: 'vite-plugin-root',\n\n // TODO(stevenle): when the config is resolved, store a list of places to\n // find custom elements.\n configResolved(resolvedConfig: any) {\n config = resolvedConfig;\n },\n\n configureServer(_server: ViteDevServer) {\n server = _server;\n },\n\n async transform(src: string, id: string): Promise<any> {\n if (id.includes('/elements/') && isJsFile(id)) {\n const idParts = path.parse(id);\n const deps = new Set<string>();\n const elementsRe = ELEMENTS_REGEX;\n for (const match of src.matchAll(elementsRe)) {\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 },\n };\n}\n\nfunction isJsFile(file: string): boolean {\n return !!file.match(/\\.(j|t)sx?$/);\n}\n\nexport default pluginRoot;\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} 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(rootDir?: string) {\n const version = process.env.npm_package_version || 'dev';\n console.log(`🌳 Root.js v${version}`);\n\n if (!rootDir) {\n rootDir = process.cwd();\n }\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 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 viteConfig = rootConfig.vite || {};\n const baseConfig = {\n ...viteConfig,\n root: rootDir,\n esbuild: {\n jsxFactory: 'h',\n jsxFragment: 'Fragment',\n jsxInject: 'import {h, Fragment} from \"preact\";',\n },\n plugins: [...(viteConfig.plugins || []), pluginRoot()],\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 });\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(path.join(distDir, 'client/manifest.json'));\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);\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\nexport class BuildAssetMap implements AssetMap {\n private manifest: Manifest;\n private moduleIdToAsset: Map<string, BuildAsset>;\n\n constructor(manifest: Manifest) {\n this.manifest = manifest;\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 toJson(): any {\n const result: any = {};\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 ['.ts', '.tsx'].includes(parts.ext) &&\n asset.moduleId.includes('/elements/')\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(): any {\n return {\n moduleId: this.moduleId,\n assetUrl: this.assetUrl,\n importedModules: this.importedModules,\n importedCss: this.importedCss,\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(file: string) {\n return !!file.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(filePath: string): Promise<any> {\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","export async function start(rootDir?: string) {\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 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 {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 rootDir = options?.rootDir || process.cwd();\n let elementMap: Record<string, string>;\n\n async function updateElementMap() {\n elementMap = {};\n const files = await glob('./elements/**/*', {cwd: rootDir});\n files.forEach((file) => {\n const parts = path.parse(file);\n if (isJsFile(parts.base)) {\n elementMap[parts.name] = `/${file}`;\n }\n });\n console.log(JSON.stringify(elementMap));\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 return {\n name: 'vite-plugin-root',\n\n async transform(src: string, id: string): Promise<any> {\n if (!id.startsWith(rootDir)) {\n return null;\n }\n const moduleId = id.slice(rootDir.length);\n if (moduleId.startsWith('/elements/') && isJsFile(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 console.log(code);\n return {code};\n }\n return null;\n }\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(rootDir?: string) {\n console.log('🌳 Root.js');\n\n if (!rootDir) {\n rootDir = process.cwd();\n }\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 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 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);\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\n constructor(manifest: Manifest) {\n this.manifest = manifest;\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 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 asset.moduleId.includes('/elements/')\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":[]}
|
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 { R as RootConfig, a as RootI18nConfig, d as defineConfig } from './
|
|
3
|
+
export { b as GetStaticPaths, G as GetStaticProps, R as RootConfig, a as RootI18nConfig, d as defineConfig } from './types-d6c0705e.js';
|
|
4
4
|
import 'vite';
|
|
5
5
|
|
|
6
6
|
interface ErrorPageProps {
|
|
@@ -35,7 +35,7 @@ interface I18nContext {
|
|
|
35
35
|
locale: string;
|
|
36
36
|
translations: Record<string, string>;
|
|
37
37
|
}
|
|
38
|
-
declare function t(str: string, params?: Record<string, string>): string;
|
|
39
38
|
declare function getTranslations(locale: string): Record<string, string>;
|
|
39
|
+
declare function useTranslations(): (str: string, params?: Record<string, string>) => string;
|
|
40
40
|
|
|
41
|
-
export { ErrorPage, ErrorPageProps, HEAD_CONTEXT, Head, HeadProps, I18N_CONTEXT, I18nContext, SCRIPT_CONTEXT, Script, ScriptProps, getTranslations,
|
|
41
|
+
export { ErrorPage, ErrorPageProps, HEAD_CONTEXT, Head, HeadProps, I18N_CONTEXT, I18nContext, SCRIPT_CONTEXT, Script, ScriptProps, getTranslations, useTranslations };
|
package/dist/core.js
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
SCRIPT_CONTEXT,
|
|
7
7
|
Script,
|
|
8
8
|
getTranslations,
|
|
9
|
-
|
|
10
|
-
} from "./chunk-
|
|
9
|
+
useTranslations
|
|
10
|
+
} from "./chunk-CDPH3RKE.js";
|
|
11
11
|
|
|
12
12
|
// src/core/config.ts
|
|
13
13
|
function defineConfig(config) {
|
|
@@ -22,6 +22,6 @@ export {
|
|
|
22
22
|
Script,
|
|
23
23
|
defineConfig,
|
|
24
24
|
getTranslations,
|
|
25
|
-
|
|
25
|
+
useTranslations
|
|
26
26
|
};
|
|
27
27
|
//# sourceMappingURL=core.js.map
|
package/dist/render.d.ts
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ComponentType } from 'preact';
|
|
2
|
+
import { b as GetStaticPaths, G as GetStaticProps, R as RootConfig } from './types-d6c0705e.js';
|
|
2
3
|
import 'vite';
|
|
3
4
|
|
|
4
|
-
declare type GetStaticProps<T = unknown> = (ctx: {
|
|
5
|
-
params: Record<string, string>;
|
|
6
|
-
}) => Promise<{
|
|
7
|
-
props: T;
|
|
8
|
-
notFound?: boolean;
|
|
9
|
-
}>;
|
|
10
|
-
declare type GetStaticPaths<T = Record<string, string>> = () => Promise<{
|
|
11
|
-
paths: Array<{
|
|
12
|
-
params: T;
|
|
13
|
-
}>;
|
|
14
|
-
}>;
|
|
15
|
-
|
|
16
5
|
interface RouteModule {
|
|
17
|
-
default
|
|
6
|
+
default?: ComponentType<unknown>;
|
|
18
7
|
getStaticPaths?: GetStaticPaths;
|
|
19
8
|
getStaticProps?: GetStaticProps;
|
|
20
9
|
}
|
package/dist/render.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
I18N_CONTEXT,
|
|
5
5
|
SCRIPT_CONTEXT,
|
|
6
6
|
getTranslations
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CDPH3RKE.js";
|
|
8
8
|
|
|
9
9
|
// src/render/render.tsx
|
|
10
10
|
import path2 from "node:path";
|
|
@@ -79,7 +79,8 @@ var RouteTrie = class {
|
|
|
79
79
|
addPromise(cb(`/${subpath}${childPath}`, childRoute));
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
|
-
return Promise.all(promises)
|
|
82
|
+
return Promise.all(promises).then(() => {
|
|
83
|
+
});
|
|
83
84
|
}
|
|
84
85
|
clear() {
|
|
85
86
|
this.children = {};
|
|
@@ -229,6 +230,9 @@ var Renderer = class {
|
|
|
229
230
|
const routeParams = options.routeParams;
|
|
230
231
|
const assetMap = options.assetMap;
|
|
231
232
|
const Component = route.module.default;
|
|
233
|
+
if (!Component) {
|
|
234
|
+
throw new Error("unable to render route. the route should have a default export that renders a jsx component.");
|
|
235
|
+
}
|
|
232
236
|
let props = {};
|
|
233
237
|
if (route.module.getStaticProps) {
|
|
234
238
|
const propsData = await route.module.getStaticProps({
|
|
@@ -304,9 +308,6 @@ var Renderer = class {
|
|
|
304
308
|
lang: options.locale
|
|
305
309
|
}, /* @__PURE__ */ h("head", null, /* @__PURE__ */ h("meta", {
|
|
306
310
|
charSet: "utf-8"
|
|
307
|
-
}), /* @__PURE__ */ h("meta", {
|
|
308
|
-
name: "viewport",
|
|
309
|
-
content: "width=device-width, initial-scale=1.0"
|
|
310
311
|
}), options.headComponents), /* @__PURE__ */ h("body", {
|
|
311
312
|
dangerouslySetInnerHTML: { __html: options.mainHtml }
|
|
312
313
|
}));
|
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":["import path from 'node:path';\nimport {h, ComponentChildren} from 'preact';\nimport renderToString from 'preact-render-to-string';\nimport {getRoutes, RouteModule, 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';\n\n// TODO(stevenle): this should be added via config.\nconst ELEMENTS_MAP: Record<string, string> = {};\nconst ELEMENTS_MODULES = import.meta.glob([\n '/elements/**/*.ts',\n '/elements/**/*.tsx',\n]) as Record<string, () => Promise<RouteModule>>;\nObject.keys(ELEMENTS_MODULES).forEach((elementPath) => {\n const parts = path.parse(elementPath);\n ELEMENTS_MAP[parts.name] = elementPath;\n});\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 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 <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1.0\"\n />\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 ELEMENTS_MAP) {\n const modulePath = ELEMENTS_MAP[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 {RootConfig} from '../core/config';\nimport {GetStaticPaths, GetStaticProps} from '../core/types';\nimport {RouteTrie} from './route-trie';\n\nexport interface RouteModule {\n default: any;\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<any> | void): Promise<any> {\n const promises: Array<Promise<any>> = [];\n const addPromise = (promise: Promise<any> | 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);\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":[]}
|
|
1
|
+
{"version":3,"sources":["../src/render/render.tsx","../src/render/router.ts","../src/render/route-trie.ts"],"sourcesContent":["import path from 'node:path';\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {h, ComponentChildren} from 'preact';\nimport renderToString from 'preact-render-to-string';\nimport {getRoutes, RouteModule, 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';\n\n// TODO(stevenle): this should be added via config.\nconst ELEMENTS_MAP: Record<string, string> = {};\nconst ELEMENTS_MODULES = import.meta.glob([\n '/elements/**/*.ts',\n '/elements/**/*.tsx',\n]) as Record<string, () => Promise<RouteModule>>;\nObject.keys(ELEMENTS_MODULES).forEach((elementPath) => {\n const parts = path.parse(elementPath);\n ELEMENTS_MAP[parts.name] = elementPath;\n});\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 ELEMENTS_MAP) {\n const modulePath = ELEMENTS_MAP[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":[]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { UserConfig } from 'vite';
|
|
2
|
+
|
|
3
|
+
interface RootConfig {
|
|
4
|
+
i18n?: RootI18nConfig;
|
|
5
|
+
vite?: UserConfig;
|
|
6
|
+
sitemap?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface RootI18nConfig {
|
|
9
|
+
locales?: string[];
|
|
10
|
+
defaultLocale?: string;
|
|
11
|
+
urlFormat?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function defineConfig(config: RootConfig): RootConfig;
|
|
14
|
+
|
|
15
|
+
declare type GetStaticProps<T = unknown> = (ctx: {
|
|
16
|
+
params: Record<string, string>;
|
|
17
|
+
}) => Promise<{
|
|
18
|
+
props: T;
|
|
19
|
+
notFound?: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
declare type GetStaticPaths<T = Record<string, string>> = () => Promise<{
|
|
22
|
+
paths: Array<{
|
|
23
|
+
params: T;
|
|
24
|
+
}>;
|
|
25
|
+
}>;
|
|
26
|
+
|
|
27
|
+
export { GetStaticProps as G, RootConfig as R, RootI18nConfig as a, GetStaticPaths as b, defineConfig as d };
|
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.3",
|
|
4
4
|
"author": "s@blinkk.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -54,8 +54,10 @@
|
|
|
54
54
|
"@types/fs-extra": "^9.0.13",
|
|
55
55
|
"@types/html-minifier-terser": "^7.0.0",
|
|
56
56
|
"@types/node": "^18.7.14",
|
|
57
|
+
"@types/preact-custom-element": "^4.0.1",
|
|
57
58
|
"nodemon": "^2.0.19",
|
|
58
59
|
"preact": "^10.10.6",
|
|
60
|
+
"preact-custom-element": "^4.2.1",
|
|
59
61
|
"preact-render-to-string": "^5.2.3",
|
|
60
62
|
"rollup": "^2.79.0",
|
|
61
63
|
"tsup": "^5.12.1",
|
|
@@ -65,6 +67,7 @@
|
|
|
65
67
|
"scripts": {
|
|
66
68
|
"build": "rm -rf dist && tsup-node",
|
|
67
69
|
"dev": "nodemon --watch src -e ts,tsx --exec pnpm build",
|
|
68
|
-
"test": "pnpm build && vitest"
|
|
70
|
+
"test": "pnpm build && vitest run",
|
|
71
|
+
"test:watch": "pnpm build && vitest"
|
|
69
72
|
}
|
|
70
73
|
}
|
|
@@ -1 +0,0 @@
|
|
|
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":["import {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 t(str: string, params?: Record<string, string>) {\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 let translation = translations[str] || str;\n if (params) {\n for (const key in params) {\n const val = String(params[key] || '');\n translation = translation.replaceAll(`{${key}}`, val);\n }\n }\n return translation;\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"],"mappings":";AAAA;AAMO,mBAAmB,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,kBAAC,aACC,kBAAC,aACC,kBAAC,WAAE,2DAAyD,GAC3D,WAAW,kBAAC,aAAK,OAAQ,CAC5B,CACF;AAEJ;;;AC1BA;AACA;AAEO,IAAM,eAAe,cAAmC,CAAC,CAAC;AAU1D,cAAc,OAAkB;AACrC,MAAI;AACJ,MAAI;AACF,cAAU,WAAW,YAAY;AAAA,EACnC,SAAS,KAAP;AACA,YAAQ,IAAI,GAAG;AACf,UAAM,IAAI,MACR,iFACA,EAAC,OAAO,IAAG,CACb;AAAA,EACF;AACA,UAAQ,KAAK,MAAM,QAAQ;AAC3B,SAAO;AACT;;;AC1BA;AACA;AAEO,IAAM,iBAAiB,eAA6B,CAAC,CAAC;AAYtD,gBAAgB,OAAoB;AACzC,MAAI;AACJ,MAAI;AACF,cAAU,YAAW,cAAc;AAAA,EACrC,SAAS,KAAP;AACA,UAAM,IAAI,MACR,mFACA,EAAC,OAAO,IAAG,CACb;AAAA,EACF;AACA,UAAQ,KAAK,KAAK;AAClB,SAAO;AACT;;;AC3BA;AACA;AACA;AAEO,IAAM,eAAe,eAAkC,IAAI;AAO3D,WAAW,KAAa,QAAiC;AAC9D,QAAM,UAAU,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,QAAM,eAAe,oCAAS,iBAAgB,CAAC;AAC/C,MAAI,cAAc,aAAa,QAAQ;AACvC,MAAI,QAAQ;AACV,eAAW,OAAO,QAAQ;AACxB,YAAM,MAAM,OAAO,OAAO,QAAQ,EAAE;AACpC,oBAAc,YAAY,WAAW,IAAI,QAAQ,GAAG;AAAA,IACtD;AAAA,EACF;AACA,SAAO;AACT;AAEO,yBAAyB,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,UAAM,UAAS,MAAM;AACrB,UAAM,SAAS,kBAAkB;AACjC,QAAI,UAAU,OAAO,SAAS;AAC5B,mBAAa,WAAU,OAAO;AAAA,IAChC;AAAA,EACF,CAAC;AACD,SAAO,aAAa,WAAW,CAAC;AAClC;","names":[]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { UserConfig } from 'vite';
|
|
2
|
-
|
|
3
|
-
interface RootConfig {
|
|
4
|
-
i18n?: RootI18nConfig;
|
|
5
|
-
vite?: UserConfig;
|
|
6
|
-
sitemap?: boolean;
|
|
7
|
-
}
|
|
8
|
-
interface RootI18nConfig {
|
|
9
|
-
locales?: string[];
|
|
10
|
-
defaultLocale?: string;
|
|
11
|
-
urlFormat?: string;
|
|
12
|
-
}
|
|
13
|
-
declare function defineConfig(config: RootConfig): RootConfig;
|
|
14
|
-
|
|
15
|
-
export { RootConfig as R, RootI18nConfig as a, defineConfig as d };
|