@blinkk/root 1.0.0-alpha.3 → 1.0.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/root.js +19 -15
- package/dist/{chunk-CDPH3RKE.js → chunk-5FQTLGCQ.js} +22 -5
- package/dist/{chunk-CDPH3RKE.js.map → chunk-5FQTLGCQ.js.map} +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +170 -75
- package/dist/cli.js.map +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/render.d.ts +1 -1
- package/dist/render.js +102 -82
- package/dist/render.js.map +1 -1
- package/dist/types-27ca8c1c.d.ts +61 -0
- package/package.json +2 -2
- package/dist/types-d6c0705e.d.ts +0 -27
package/bin/root.js
CHANGED
|
@@ -10,20 +10,24 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
10
10
|
const require = createRequire(import.meta.url);
|
|
11
11
|
const packageJson = require(path.join(__dirname, '../package.json'));
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
program
|
|
13
|
+
async function main() {
|
|
14
|
+
const program = new Command('root');
|
|
15
|
+
program.version(packageJson.version);
|
|
15
16
|
|
|
16
|
-
program
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
program
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
program
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
program
|
|
18
|
+
.command('build [path]')
|
|
19
|
+
.description('generates a static build')
|
|
20
|
+
.action(build);
|
|
21
|
+
program
|
|
22
|
+
.command('dev [path]')
|
|
23
|
+
.description('starts the server in development mode')
|
|
24
|
+
.action(dev);
|
|
25
|
+
program
|
|
26
|
+
.command('start [path]')
|
|
27
|
+
.description('starts the server in production mode')
|
|
28
|
+
.action(start);
|
|
28
29
|
|
|
29
|
-
program.
|
|
30
|
+
await program.parseAsync(process.argv);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
main();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/core/components/error-page.tsx
|
|
2
|
-
import {
|
|
2
|
+
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
3
3
|
function ErrorPage(props) {
|
|
4
4
|
const error = props.error;
|
|
5
5
|
let message = void 0;
|
|
@@ -10,7 +10,18 @@ function ErrorPage(props) {
|
|
|
10
10
|
message = String(error);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
return /* @__PURE__ */
|
|
13
|
+
return /* @__PURE__ */ jsx("div", {
|
|
14
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
15
|
+
children: [
|
|
16
|
+
/* @__PURE__ */ jsx("p", {
|
|
17
|
+
children: "An error occured during route handling or page rendering."
|
|
18
|
+
}),
|
|
19
|
+
message && /* @__PURE__ */ jsx("pre", {
|
|
20
|
+
children: message
|
|
21
|
+
})
|
|
22
|
+
]
|
|
23
|
+
})
|
|
24
|
+
});
|
|
14
25
|
}
|
|
15
26
|
|
|
16
27
|
// src/core/components/head.ts
|
|
@@ -23,7 +34,10 @@ function Head(props) {
|
|
|
23
34
|
context = useContext(HEAD_CONTEXT);
|
|
24
35
|
} catch (err) {
|
|
25
36
|
console.log(err);
|
|
26
|
-
throw new Error(
|
|
37
|
+
throw new Error(
|
|
38
|
+
"<Head> component is not supported in the browser, or during suspense renders.",
|
|
39
|
+
{ cause: err }
|
|
40
|
+
);
|
|
27
41
|
}
|
|
28
42
|
context.push(props.children);
|
|
29
43
|
return null;
|
|
@@ -38,7 +52,10 @@ function Script(props) {
|
|
|
38
52
|
try {
|
|
39
53
|
context = useContext2(SCRIPT_CONTEXT);
|
|
40
54
|
} catch (err) {
|
|
41
|
-
throw new Error(
|
|
55
|
+
throw new Error(
|
|
56
|
+
"<Script> component is not supported in the browser, or during suspense renders.",
|
|
57
|
+
{ cause: err }
|
|
58
|
+
);
|
|
42
59
|
}
|
|
43
60
|
context.push(props);
|
|
44
61
|
return null;
|
|
@@ -93,4 +110,4 @@ export {
|
|
|
93
110
|
getTranslations,
|
|
94
111
|
useTranslations
|
|
95
112
|
};
|
|
96
|
-
//# sourceMappingURL=chunk-
|
|
113
|
+
//# sourceMappingURL=chunk-5FQTLGCQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/components/error-page.tsx","../src/core/components/head.ts","../src/core/components/script.ts","../src/core/i18n.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {h} from 'preact';\n\nexport interface ErrorPageProps {\n error: unknown;\n}\n\nexport function ErrorPage(props: ErrorPageProps) {\n const error = props.error;\n\n let message = undefined;\n if (import.meta.env.DEV) {\n if (error instanceof Error) {\n message = error.stack;\n } else {\n message = String(error);\n }\n }\n\n return (\n <div>\n <div>\n <p>An error occured during route handling or page rendering.</p>\n {message && <pre>{message}</pre>}\n </div>\n </div>\n );\n}\n","import {ComponentChildren, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const HEAD_CONTEXT = createContext<ComponentChildren[]>([]);\n\nexport interface HeadProps {\n children?: ComponentChildren;\n}\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page.\n */\nexport function Head(props: HeadProps) {\n let context: ComponentChildren[];\n try {\n context = useContext(HEAD_CONTEXT);\n } catch (err) {\n console.log(err);\n throw new Error(\n '<Head> component is not supported in the browser, or during suspense renders.',\n {cause: err}\n );\n }\n context.push(props.children);\n return null;\n}\n","import {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const SCRIPT_CONTEXT = createContext<ScriptProps[]>([]);\n\nexport interface ScriptProps {\n src: string;\n type?: string;\n}\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `src/bundles` folder at the root of the project.\n */\nexport function Script(props: ScriptProps) {\n let context: ScriptProps[];\n try {\n context = useContext(SCRIPT_CONTEXT);\n } catch (err) {\n throw new Error(\n '<Script> component is not supported in the browser, or during suspense renders.',\n {cause: err}\n );\n }\n context.push(props);\n return null;\n}\n","import path from 'node:path';\nimport {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const I18N_CONTEXT = createContext<I18nContext | null>(null);\n\nexport interface I18nContext {\n locale: string;\n translations: Record<string, string>;\n}\n\nexport function getTranslations(locale: string): Record<string, string> {\n const translations: Record<string, Record<string, string>> = {};\n const translationsFiles = import.meta.glob(['/translations/*.json'], {\n eager: true,\n }) as Record<string, {default?: Record<string, string>}>;\n Object.keys(translationsFiles).forEach((translationPath) => {\n const parts = path.parse(translationPath);\n const locale = parts.name;\n const module = translationsFiles[translationPath];\n if (module && module.default) {\n translations[locale] = module.default;\n }\n });\n return translations[locale] || {};\n}\n\nexport function useTranslations() {\n const context = useContext(I18N_CONTEXT);\n if (!context) {\n throw new Error('could not find i18n context');\n }\n const translations = context?.translations || {};\n const t = (str: string, params?: Record<string, string>) => {\n let translation = translations[str] || str || '';\n if (params) {\n for (const key of Object.keys(params)) {\n const val = String(params[key] || '');\n translation = translation.replaceAll(`{${key}}`, val);\n }\n }\n return translation;\n };\n return t;\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../src/core/components/error-page.tsx","../src/core/components/head.ts","../src/core/components/script.ts","../src/core/i18n.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {h} from 'preact';\n\nexport interface ErrorPageProps {\n error: unknown;\n}\n\nexport function ErrorPage(props: ErrorPageProps) {\n const error = props.error;\n\n let message = undefined;\n if (import.meta.env.DEV) {\n if (error instanceof Error) {\n message = error.stack;\n } else {\n message = String(error);\n }\n }\n\n return (\n <div>\n <div>\n <p>An error occured during route handling or page rendering.</p>\n {message && <pre>{message}</pre>}\n </div>\n </div>\n );\n}\n","import {ComponentChildren, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const HEAD_CONTEXT = createContext<ComponentChildren[]>([]);\n\nexport interface HeadProps {\n children?: ComponentChildren;\n}\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page.\n */\nexport function Head(props: HeadProps) {\n let context: ComponentChildren[];\n try {\n context = useContext(HEAD_CONTEXT);\n } catch (err) {\n console.log(err);\n throw new Error(\n '<Head> component is not supported in the browser, or during suspense renders.',\n {cause: err}\n );\n }\n context.push(props.children);\n return null;\n}\n","import {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const SCRIPT_CONTEXT = createContext<ScriptProps[]>([]);\n\nexport interface ScriptProps {\n src: string;\n type?: string;\n}\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `src/bundles` folder at the root of the project.\n */\nexport function Script(props: ScriptProps) {\n let context: ScriptProps[];\n try {\n context = useContext(SCRIPT_CONTEXT);\n } catch (err) {\n throw new Error(\n '<Script> component is not supported in the browser, or during suspense renders.',\n {cause: err}\n );\n }\n context.push(props);\n return null;\n}\n","import path from 'node:path';\nimport {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const I18N_CONTEXT = createContext<I18nContext | null>(null);\n\nexport interface I18nContext {\n locale: string;\n translations: Record<string, string>;\n}\n\nexport function getTranslations(locale: string): Record<string, string> {\n const translations: Record<string, Record<string, string>> = {};\n const translationsFiles = import.meta.glob(['/translations/*.json'], {\n eager: true,\n }) as Record<string, {default?: Record<string, string>}>;\n Object.keys(translationsFiles).forEach((translationPath) => {\n const parts = path.parse(translationPath);\n const locale = parts.name;\n const module = translationsFiles[translationPath];\n if (module && module.default) {\n translations[locale] = module.default;\n }\n });\n return translations[locale] || {};\n}\n\nexport function useTranslations() {\n const context = useContext(I18N_CONTEXT);\n if (!context) {\n throw new Error('could not find i18n context');\n }\n const translations = context?.translations || {};\n const t = (str: string, params?: Record<string, string>) => {\n let translation = translations[str] || str || '';\n if (params) {\n for (const key of Object.keys(params)) {\n const val = String(params[key] || '');\n translation = translation.replaceAll(`{${key}}`, val);\n }\n }\n return translation;\n };\n return t;\n}\n"],"mappings":";AAqBM,SACE,KADF;AAdC,SAAS,UAAU,OAAuB;AAC/C,QAAM,QAAQ,MAAM;AAEpB,MAAI,UAAU;AACd,MAAI,YAAY,IAAI,KAAK;AACvB,QAAI,iBAAiB,OAAO;AAC1B,gBAAU,MAAM;AAAA,IAClB,OAAO;AACL,gBAAU,OAAO,KAAK;AAAA,IACxB;AAAA,EACF;AAEA,SACE,oBAAC;AAAA,IACC,+BAAC;AAAA,MACC;AAAA,4BAAC;AAAA,UAAE;AAAA,SAAyD;AAAA,QAC3D,WAAW,oBAAC;AAAA,UAAK;AAAA,SAAQ;AAAA;AAAA,KAC5B;AAAA,GACF;AAEJ;;;AC3BA,SAA2B,qBAAoB;AAC/C,SAAQ,kBAAiB;AAElB,IAAM,eAAe,cAAmC,CAAC,CAAC;AAU1D,SAAS,KAAK,OAAkB;AACrC,MAAI;AACJ,MAAI;AACF,cAAU,WAAW,YAAY;AAAA,EACnC,SAAS,KAAP;AACA,YAAQ,IAAI,GAAG;AACf,UAAM,IAAI;AAAA,MACR;AAAA,MACA,EAAC,OAAO,IAAG;AAAA,IACb;AAAA,EACF;AACA,UAAQ,KAAK,MAAM,QAAQ;AAC3B,SAAO;AACT;;;AC1BA,SAAQ,iBAAAA,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;AAElB,IAAM,iBAAiBD,eAA6B,CAAC,CAAC;AAYtD,SAAS,OAAO,OAAoB;AACzC,MAAI;AACJ,MAAI;AACF,cAAUC,YAAW,cAAc;AAAA,EACrC,SAAS,KAAP;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA,EAAC,OAAO,IAAG;AAAA,IACb;AAAA,EACF;AACA,UAAQ,KAAK,KAAK;AAClB,SAAO;AACT;;;AC3BA,OAAO,UAAU;AACjB,SAAQ,iBAAAC,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;AAElB,IAAM,eAAeD,eAAkC,IAAI;AAO3D,SAAS,gBAAgB,QAAwC;AACtE,QAAM,eAAuD,CAAC;AAC9D,QAAM,oBAAoB,YAAY,KAAK,CAAC,sBAAsB,GAAG;AAAA,IACnE,OAAO;AAAA,EACT,CAAC;AACD,SAAO,KAAK,iBAAiB,EAAE,QAAQ,CAAC,oBAAoB;AAC1D,UAAM,QAAQ,KAAK,MAAM,eAAe;AACxC,UAAME,UAAS,MAAM;AACrB,UAAM,SAAS,kBAAkB;AACjC,QAAI,UAAU,OAAO,SAAS;AAC5B,mBAAaA,WAAU,OAAO;AAAA,IAChC;AAAA,EACF,CAAC;AACD,SAAO,aAAa,WAAW,CAAC;AAClC;AAEO,SAAS,kBAAkB;AAChC,QAAM,UAAUD,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC/C;AACA,QAAM,gBAAe,mCAAS,iBAAgB,CAAC;AAC/C,QAAM,IAAI,CAAC,KAAa,WAAoC;AAC1D,QAAI,cAAc,aAAa,QAAQ,OAAO;AAC9C,QAAI,QAAQ;AACV,iBAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,cAAM,MAAM,OAAO,OAAO,QAAQ,EAAE;AACpC,sBAAc,YAAY,WAAW,IAAI,QAAQ,GAAG;AAAA,MACtD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":["createContext","useContext","createContext","useContext","locale"]}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
declare function dev(rootDir?: string): void
|
|
1
|
+
declare function dev(rootDir?: string): Promise<void>;
|
|
2
2
|
|
|
3
|
-
declare function build(
|
|
3
|
+
declare function build(rootProjectDir?: string): Promise<void>;
|
|
4
4
|
|
|
5
5
|
declare function start(): Promise<void>;
|
|
6
6
|
|
package/dist/cli.js
CHANGED
|
@@ -55,18 +55,42 @@ async function isDirectory(dirpath) {
|
|
|
55
55
|
var JSX_ELEMENTS_REGEX = /jsxs?\("(\w[\w-]+\w)"/g;
|
|
56
56
|
var HTML_ELEMENTS_REGEX = /<(\w[\w-]+\w)/g;
|
|
57
57
|
function pluginRoot(options) {
|
|
58
|
+
var _a;
|
|
59
|
+
const elementsVirtualId = "virtual:root-elements";
|
|
60
|
+
const resolvedElementsVirtualId = "\0" + elementsVirtualId;
|
|
58
61
|
const rootDir = (options == null ? void 0 : options.rootDir) || process.cwd();
|
|
62
|
+
const rootConfig = (options == null ? void 0 : options.rootConfig) || {};
|
|
63
|
+
const elementsDirs = [path2.join(rootDir, "elements")];
|
|
64
|
+
const includeDirs = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
|
|
65
|
+
includeDirs.forEach((dirPath) => {
|
|
66
|
+
const elementsDir = path2.resolve(rootDir, dirPath);
|
|
67
|
+
if (!elementsDir.startsWith(rootDir)) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
elementsDirs.push(elementsDir);
|
|
73
|
+
});
|
|
59
74
|
let elementMap;
|
|
60
75
|
async function updateElementMap() {
|
|
61
76
|
elementMap = {};
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
await Promise.all(
|
|
78
|
+
elementsDirs.map(async (dirPath) => {
|
|
79
|
+
const dirExists = await isDirectory(dirPath);
|
|
80
|
+
if (!dirExists) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const files = await glob("**/*", { cwd: dirPath });
|
|
84
|
+
files.forEach((file) => {
|
|
85
|
+
const parts = path2.parse(file);
|
|
86
|
+
if (isJsFile(parts.base)) {
|
|
87
|
+
const fullPath = path2.join(dirPath, file);
|
|
88
|
+
const moduleId = fullPath.slice(rootDir.length);
|
|
89
|
+
elementMap[parts.name] = moduleId;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
})
|
|
93
|
+
);
|
|
70
94
|
}
|
|
71
95
|
async function getElementImport(tagname) {
|
|
72
96
|
if (!elementMap) {
|
|
@@ -77,14 +101,31 @@ function pluginRoot(options) {
|
|
|
77
101
|
}
|
|
78
102
|
return null;
|
|
79
103
|
}
|
|
104
|
+
function isCustomElement(id) {
|
|
105
|
+
if (!isJsFile(id)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
return elementsDirs.some((elementsDir) => {
|
|
109
|
+
return id.startsWith(elementsDir);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
80
112
|
return {
|
|
81
113
|
name: "vite-plugin-root",
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
return
|
|
114
|
+
resolveId(id) {
|
|
115
|
+
if (id === elementsVirtualId) {
|
|
116
|
+
return resolvedElementsVirtualId;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
},
|
|
120
|
+
async load(id) {
|
|
121
|
+
if (id === resolvedElementsVirtualId) {
|
|
122
|
+
await updateElementMap();
|
|
123
|
+
return `export const elementsMap = ${JSON.stringify(elementMap)}`;
|
|
85
124
|
}
|
|
86
|
-
|
|
87
|
-
|
|
125
|
+
return null;
|
|
126
|
+
},
|
|
127
|
+
async transform(src, id) {
|
|
128
|
+
if (isCustomElement(id)) {
|
|
88
129
|
const idParts = path2.parse(id);
|
|
89
130
|
const deps = /* @__PURE__ */ new Set();
|
|
90
131
|
const tagnames = [
|
|
@@ -102,12 +143,14 @@ function pluginRoot(options) {
|
|
|
102
143
|
deps.add(tagname);
|
|
103
144
|
}
|
|
104
145
|
const importUrls = [];
|
|
105
|
-
await Promise.all(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
146
|
+
await Promise.all(
|
|
147
|
+
Array.from(deps).map(async (tagname) => {
|
|
148
|
+
const importUrl = await getElementImport(tagname);
|
|
149
|
+
if (importUrl) {
|
|
150
|
+
importUrls.push(importUrl);
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
);
|
|
111
154
|
if (importUrls.length > 0) {
|
|
112
155
|
const importLines = importUrls.map((url) => `import '${url}';`).join("\n");
|
|
113
156
|
const code = `${src}
|
|
@@ -115,11 +158,11 @@ function pluginRoot(options) {
|
|
|
115
158
|
// autogenerated by root:
|
|
116
159
|
${importLines}
|
|
117
160
|
`;
|
|
118
|
-
console.log(code);
|
|
119
161
|
return { code };
|
|
120
162
|
}
|
|
121
163
|
return null;
|
|
122
164
|
}
|
|
165
|
+
return null;
|
|
123
166
|
}
|
|
124
167
|
};
|
|
125
168
|
}
|
|
@@ -239,7 +282,7 @@ async function htmlMinify(html) {
|
|
|
239
282
|
|
|
240
283
|
// src/cli/commands/dev.ts
|
|
241
284
|
import glob2 from "tiny-glob";
|
|
242
|
-
var
|
|
285
|
+
var __dirname = path4.dirname(fileURLToPath(import.meta.url));
|
|
243
286
|
async function createServer(options) {
|
|
244
287
|
const app = express();
|
|
245
288
|
app.use(express.static("public"));
|
|
@@ -248,14 +291,14 @@ async function createServer(options) {
|
|
|
248
291
|
const port = parseInt(process.env.PORT || "4007");
|
|
249
292
|
console.log("\u{1F333} Root.js");
|
|
250
293
|
console.log();
|
|
251
|
-
console.log(`Started server: http://localhost:${port}`);
|
|
294
|
+
console.log(`Started dev server: http://localhost:${port}`);
|
|
252
295
|
app.listen(port);
|
|
253
296
|
}
|
|
254
297
|
async function getMiddlewares(options) {
|
|
255
298
|
const rootDir = (options == null ? void 0 : options.rootDir) || process.cwd();
|
|
256
299
|
const rootConfig = await loadRootConfig(rootDir);
|
|
257
300
|
const viteConfig = rootConfig.vite || {};
|
|
258
|
-
const renderModulePath = path4.resolve(
|
|
301
|
+
const renderModulePath = path4.resolve(__dirname, "./render.js");
|
|
259
302
|
const pages = [];
|
|
260
303
|
if (await isDirectory(path4.join(rootDir, "routes"))) {
|
|
261
304
|
const pageFiles = await glob2(path4.join(rootDir, "routes/**/*"));
|
|
@@ -288,6 +331,7 @@ async function getMiddlewares(options) {
|
|
|
288
331
|
}
|
|
289
332
|
const viteServer = await createViteServer({
|
|
290
333
|
...viteConfig,
|
|
334
|
+
mode: "development",
|
|
291
335
|
server: { middlewareMode: true },
|
|
292
336
|
appType: "custom",
|
|
293
337
|
optimizeDeps: {
|
|
@@ -304,20 +348,28 @@ async function getMiddlewares(options) {
|
|
|
304
348
|
});
|
|
305
349
|
const rootMiddleware = async (req, res, next) => {
|
|
306
350
|
const url = req.originalUrl;
|
|
307
|
-
|
|
308
|
-
const renderer = new render.Renderer(rootConfig);
|
|
351
|
+
let renderer = null;
|
|
309
352
|
try {
|
|
353
|
+
const render = await viteServer.ssrLoadModule(renderModulePath);
|
|
354
|
+
renderer = new render.Renderer(rootConfig);
|
|
310
355
|
const assetMap = new DevServerAssetMap(viteServer.moduleGraph);
|
|
311
356
|
const data = await renderer.render(url, {
|
|
312
357
|
assetMap
|
|
313
358
|
});
|
|
314
|
-
|
|
359
|
+
let html = await viteServer.transformIndexHtml(url, data.html || "");
|
|
360
|
+
if (rootConfig.minifyHtml !== false) {
|
|
361
|
+
html = await htmlMinify(html);
|
|
362
|
+
}
|
|
315
363
|
res.status(200).set({ "Content-Type": "text/html" }).end(html);
|
|
316
364
|
} catch (e) {
|
|
317
365
|
viteServer.ssrFixStacktrace(e);
|
|
318
366
|
try {
|
|
319
|
-
|
|
320
|
-
|
|
367
|
+
if (renderer) {
|
|
368
|
+
const { html } = await renderer.renderError(e);
|
|
369
|
+
res.status(500).set({ "Content-Type": "text/html" }).end(html);
|
|
370
|
+
} else {
|
|
371
|
+
next(e);
|
|
372
|
+
}
|
|
321
373
|
} catch (e2) {
|
|
322
374
|
console.error("failed to render custom error");
|
|
323
375
|
console.error(e2);
|
|
@@ -327,8 +379,13 @@ async function getMiddlewares(options) {
|
|
|
327
379
|
};
|
|
328
380
|
return [viteServer.middlewares, rootMiddleware];
|
|
329
381
|
}
|
|
330
|
-
function dev(rootDir) {
|
|
331
|
-
|
|
382
|
+
async function dev(rootDir) {
|
|
383
|
+
process.env.NODE_ENV = "development";
|
|
384
|
+
try {
|
|
385
|
+
await createServer({ rootDir });
|
|
386
|
+
} catch (err) {
|
|
387
|
+
console.error("an error occurred");
|
|
388
|
+
}
|
|
332
389
|
}
|
|
333
390
|
|
|
334
391
|
// src/cli/commands/build.ts
|
|
@@ -341,17 +398,24 @@ import { build as viteBuild } from "vite";
|
|
|
341
398
|
// src/render/asset-map/build-asset-map.ts
|
|
342
399
|
import path5 from "path";
|
|
343
400
|
var BuildAssetMap = class {
|
|
344
|
-
constructor(manifest) {
|
|
401
|
+
constructor(manifest, options) {
|
|
345
402
|
this.manifest = manifest;
|
|
403
|
+
this.elementMap = options.elementMap;
|
|
346
404
|
this.moduleIdToAsset = /* @__PURE__ */ new Map();
|
|
347
405
|
Object.keys(this.manifest).forEach((manifestKey) => {
|
|
348
406
|
const moduleId = `/${manifestKey}`;
|
|
349
|
-
this.moduleIdToAsset.set(
|
|
407
|
+
this.moduleIdToAsset.set(
|
|
408
|
+
moduleId,
|
|
409
|
+
new BuildAsset(this, moduleId, this.manifest[manifestKey])
|
|
410
|
+
);
|
|
350
411
|
});
|
|
351
412
|
}
|
|
352
413
|
async get(moduleId) {
|
|
353
414
|
return this.moduleIdToAsset.get(moduleId) || null;
|
|
354
415
|
}
|
|
416
|
+
isElement(moduleId) {
|
|
417
|
+
return Object.values(this.elementMap).includes(moduleId);
|
|
418
|
+
}
|
|
355
419
|
toJson() {
|
|
356
420
|
const result = {};
|
|
357
421
|
for (const moduleId of this.moduleIdToAsset.keys()) {
|
|
@@ -366,8 +430,12 @@ var BuildAsset = class {
|
|
|
366
430
|
this.moduleId = moduleId;
|
|
367
431
|
this.manifestData = manifestData;
|
|
368
432
|
this.assetUrl = `/${manifestData.file}`;
|
|
369
|
-
this.importedModules = (this.manifestData.imports || []).map(
|
|
370
|
-
|
|
433
|
+
this.importedModules = (this.manifestData.imports || []).map(
|
|
434
|
+
(relPath) => `/${relPath}`
|
|
435
|
+
);
|
|
436
|
+
this.importedCss = (this.manifestData.css || []).map(
|
|
437
|
+
(relPath) => `/${relPath}`
|
|
438
|
+
);
|
|
371
439
|
}
|
|
372
440
|
async getCssDeps() {
|
|
373
441
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -393,13 +461,15 @@ var BuildAsset = class {
|
|
|
393
461
|
}
|
|
394
462
|
visited.add(asset.moduleId);
|
|
395
463
|
const parts = path5.parse(asset.assetUrl);
|
|
396
|
-
if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && asset.moduleId
|
|
464
|
+
if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && this.assetMap.isElement(asset.moduleId)) {
|
|
397
465
|
urls.add(asset.assetUrl);
|
|
398
466
|
}
|
|
399
|
-
await Promise.all(
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
467
|
+
await Promise.all(
|
|
468
|
+
asset.importedModules.map(async (moduleId) => {
|
|
469
|
+
const importedAsset = await this.assetMap.get(moduleId);
|
|
470
|
+
this.collectJs(importedAsset, urls, visited);
|
|
471
|
+
})
|
|
472
|
+
);
|
|
403
473
|
}
|
|
404
474
|
async collectCss(asset, urls, visited) {
|
|
405
475
|
if (!asset) {
|
|
@@ -415,10 +485,12 @@ var BuildAsset = class {
|
|
|
415
485
|
if (asset.importedCss) {
|
|
416
486
|
asset.importedCss.forEach((cssUrl) => urls.add(cssUrl));
|
|
417
487
|
}
|
|
418
|
-
await Promise.all(
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
488
|
+
await Promise.all(
|
|
489
|
+
asset.importedModules.map(async (moduleId) => {
|
|
490
|
+
const importedAsset = await this.assetMap.get(moduleId);
|
|
491
|
+
this.collectCss(importedAsset, urls, visited);
|
|
492
|
+
})
|
|
493
|
+
);
|
|
422
494
|
}
|
|
423
495
|
toJson() {
|
|
424
496
|
return {
|
|
@@ -431,12 +503,11 @@ var BuildAsset = class {
|
|
|
431
503
|
};
|
|
432
504
|
|
|
433
505
|
// src/cli/commands/build.ts
|
|
434
|
-
var
|
|
435
|
-
async function build(
|
|
506
|
+
var __dirname2 = path6.dirname(fileURLToPath2(import.meta.url));
|
|
507
|
+
async function build(rootProjectDir) {
|
|
508
|
+
var _a;
|
|
436
509
|
console.log("\u{1F333} Root.js");
|
|
437
|
-
|
|
438
|
-
rootDir = process.cwd();
|
|
439
|
-
}
|
|
510
|
+
const rootDir = rootProjectDir || process.cwd();
|
|
440
511
|
const rootConfig = await loadRootConfig(rootDir);
|
|
441
512
|
const distDir = path6.join(rootDir, "dist");
|
|
442
513
|
await rmDir(distDir);
|
|
@@ -451,15 +522,32 @@ async function build(rootDir) {
|
|
|
451
522
|
}
|
|
452
523
|
});
|
|
453
524
|
}
|
|
525
|
+
const elementsDirs = [path6.join(rootDir, "elements")];
|
|
526
|
+
const elementsInclude = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
|
|
527
|
+
for (const dirPath of elementsInclude) {
|
|
528
|
+
const elementsDir = path6.resolve(rootDir, dirPath);
|
|
529
|
+
if (!elementsDir.startsWith(rootDir)) {
|
|
530
|
+
throw new Error(
|
|
531
|
+
`the elements dir (${dirPath}) should be relative to the project's root dir (${rootDir})`
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
elementsDirs.push(elementsDir);
|
|
535
|
+
}
|
|
454
536
|
const elements = [];
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
537
|
+
const elementMap = {};
|
|
538
|
+
for (const dirPath of elementsDirs) {
|
|
539
|
+
if (await isDirectory(dirPath)) {
|
|
540
|
+
const elementFiles = await glob3("**/*", { cwd: dirPath });
|
|
541
|
+
elementFiles.forEach((file) => {
|
|
542
|
+
const parts = path6.parse(file);
|
|
543
|
+
if (isJsFile(parts.base)) {
|
|
544
|
+
const fullPath = path6.join(dirPath, file);
|
|
545
|
+
const moduleId = fullPath.slice(rootDir.length);
|
|
546
|
+
elements.push(fullPath);
|
|
547
|
+
elementMap[parts.name] = moduleId;
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
}
|
|
463
551
|
}
|
|
464
552
|
const bundleScripts = [];
|
|
465
553
|
if (await isDirectory(path6.join(rootDir, "bundles"))) {
|
|
@@ -488,7 +576,7 @@ async function build(rootDir) {
|
|
|
488
576
|
publicDir: false,
|
|
489
577
|
build: {
|
|
490
578
|
rollupOptions: {
|
|
491
|
-
input: [path6.resolve(
|
|
579
|
+
input: [path6.resolve(__dirname2, "./render.js")],
|
|
492
580
|
output: {
|
|
493
581
|
format: "esm",
|
|
494
582
|
chunkFileNames: "chunks/[name].[hash].js",
|
|
@@ -532,9 +620,14 @@ async function build(rootDir) {
|
|
|
532
620
|
reportCompressedSize: false
|
|
533
621
|
}
|
|
534
622
|
});
|
|
535
|
-
const manifest = await loadJson(
|
|
536
|
-
|
|
537
|
-
|
|
623
|
+
const manifest = await loadJson(
|
|
624
|
+
path6.join(distDir, "client/manifest.json")
|
|
625
|
+
);
|
|
626
|
+
const assetMap = new BuildAssetMap(manifest, { elementMap });
|
|
627
|
+
writeFile(
|
|
628
|
+
path6.join(distDir, "client/root-manifest.json"),
|
|
629
|
+
JSON.stringify(assetMap.toJson(), null, 2)
|
|
630
|
+
);
|
|
538
631
|
const buildDir = path6.join(distDir, "html");
|
|
539
632
|
const publicDir = path6.join(rootDir, "public");
|
|
540
633
|
if (fsExtra2.existsSync(path6.join(rootDir, "public"))) {
|
|
@@ -547,21 +640,23 @@ async function build(rootDir) {
|
|
|
547
640
|
const render = await import(path6.join(distDir, "server/render.js"));
|
|
548
641
|
const renderer = new render.Renderer(rootConfig);
|
|
549
642
|
const sitemap = await renderer.getSitemap();
|
|
550
|
-
await Promise.all(
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
643
|
+
await Promise.all(
|
|
644
|
+
Object.keys(sitemap).map(async (urlPath) => {
|
|
645
|
+
const { route, params } = sitemap[urlPath];
|
|
646
|
+
const data = await renderer.renderRoute(route, {
|
|
647
|
+
assetMap,
|
|
648
|
+
routeParams: params
|
|
649
|
+
});
|
|
650
|
+
let outPath = path6.join(distDir, `html${urlPath}`, "index.html");
|
|
651
|
+
if (outPath.endsWith("404/index.html")) {
|
|
652
|
+
outPath = outPath.replace("404/index.html", "404.html");
|
|
653
|
+
}
|
|
654
|
+
const html = await htmlMinify(data.html || "");
|
|
655
|
+
await writeFile(outPath, html);
|
|
656
|
+
const relPath = outPath.slice(path6.dirname(distDir).length + 1);
|
|
657
|
+
console.log(`saved ${relPath}`);
|
|
658
|
+
})
|
|
659
|
+
);
|
|
565
660
|
}
|
|
566
661
|
|
|
567
662
|
// src/cli/commands/start.ts
|