@blinkk/root 1.0.0-rc.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/bin/root.js +6 -32
- package/dist/{chunk-MJCIAH6K.js → chunk-7IDJ3PBT.js} +1 -1
- package/dist/{chunk-MJCIAH6K.js.map → chunk-7IDJ3PBT.js.map} +1 -1
- package/dist/chunk-IUQLRDFW.js +237 -0
- package/dist/chunk-IUQLRDFW.js.map +1 -0
- package/dist/{chunk-J2ANSYAE.js → chunk-KGPR2CJV.js} +111 -9
- package/dist/chunk-KGPR2CJV.js.map +1 -0
- package/dist/{chunk-YF6DPNDK.js → chunk-RLFKEIOC.js} +449 -121
- package/dist/chunk-RLFKEIOC.js.map +1 -0
- package/dist/{chunk-WNXIRMFF.js → chunk-TZAHHHA4.js} +27 -7
- package/dist/chunk-TZAHHHA4.js.map +1 -0
- package/dist/cli.d.ts +18 -3
- package/dist/cli.js +8 -4
- package/dist/core.d.ts +5 -3
- package/dist/core.js +8 -3
- package/dist/core.js.map +1 -1
- package/dist/functions.d.ts +1 -1
- package/dist/functions.js +7 -7
- package/dist/functions.js.map +1 -1
- package/dist/middleware.d.ts +12 -5
- package/dist/middleware.js +3 -1
- package/dist/node.d.ts +11 -2
- package/dist/node.js +7 -1
- package/dist/render.d.ts +1 -1
- package/dist/render.js +290 -289
- package/dist/render.js.map +1 -1
- package/dist/{types-9209ea89.d.ts → types-403nR8i5.d.ts} +96 -8
- package/package.json +38 -35
- package/dist/chunk-DFBTOMQF.js +0 -61
- package/dist/chunk-DFBTOMQF.js.map +0 -1
- package/dist/chunk-J2ANSYAE.js.map +0 -1
- package/dist/chunk-WNXIRMFF.js.map +0 -1
- package/dist/chunk-YF6DPNDK.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2024 Blinkk LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/bin/root.js
CHANGED
|
@@ -3,42 +3,16 @@
|
|
|
3
3
|
import {createRequire} from 'node:module';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import {fileURLToPath} from 'node:url';
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {bgGreen, black} from 'kleur/colors';
|
|
6
|
+
import {CliRunner} from '../dist/cli.js';
|
|
7
|
+
import 'dotenv/config';
|
|
9
8
|
|
|
10
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
10
|
const require = createRequire(import.meta.url);
|
|
12
11
|
const packageJson = require(path.join(__dirname, '../package.json'));
|
|
13
12
|
|
|
14
|
-
async function main() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const program = new Command('root');
|
|
18
|
-
program.version(packageJson.version);
|
|
19
|
-
program
|
|
20
|
-
.command('build [path]')
|
|
21
|
-
.description('generates a static build')
|
|
22
|
-
.option('--ssr-only', 'produce a ssr-only build')
|
|
23
|
-
.option('--mode <mode>', 'see: https://vitejs.dev/guide/env-and-mode.html#modes', 'production')
|
|
24
|
-
.option('-c, --concurrency <num>', 'number of files to build concurrently', 10)
|
|
25
|
-
.action(build);
|
|
26
|
-
program
|
|
27
|
-
.command('dev [path]')
|
|
28
|
-
.description('starts the server in development mode')
|
|
29
|
-
.option('--host <host>', 'network address the server should listen on, e.g. 127.0.0.1')
|
|
30
|
-
.action(dev);
|
|
31
|
-
program
|
|
32
|
-
.command('preview [path]')
|
|
33
|
-
.description('starts the server in preview mode')
|
|
34
|
-
.option('--host <host>', 'network address the server should listen on, e.g. 127.0.0.1')
|
|
35
|
-
.action(preview);
|
|
36
|
-
program
|
|
37
|
-
.command('start [path]')
|
|
38
|
-
.description('starts the server in production mode')
|
|
39
|
-
.option('--host <host>', 'network address the server should listen on, e.g. 127.0.0.1')
|
|
40
|
-
.action(start);
|
|
41
|
-
await program.parseAsync(process.argv);
|
|
13
|
+
async function main(argv) {
|
|
14
|
+
const cli = new CliRunner('root.js', packageJson.version);
|
|
15
|
+
await cli.run(argv);
|
|
42
16
|
}
|
|
43
17
|
|
|
44
|
-
main();
|
|
18
|
+
main(process.argv);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/components/Html.tsx","../src/core/hooks/useI18nContext.ts","../src/core/hooks/useRequestContext.ts"],"sourcesContent":["import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport interface HtmlContext {\n htmlAttrs: preact.JSX.HTMLAttributes<HTMLHtmlElement>;\n headAttrs: preact.JSX.HTMLAttributes<HTMLHeadElement>;\n headComponents: ComponentChildren[];\n bodyAttrs: preact.JSX.HTMLAttributes<HTMLBodyElement>;\n scriptDeps: Array<preact.JSX.HTMLAttributes<HTMLScriptElement>>;\n}\n\nexport const HTML_CONTEXT = createContext<HtmlContext | null>(null);\n\nexport type HtmlProps = preact.JSX.HTMLAttributes<HTMLHtmlElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The `<Html>` component can be used to update attrs in the `<html>` tag.\n *\n * Usage:\n *\n * ```tsx\n * <Html lang=\"en-US\">\n * <h1>Hello world</h1>\n * </Html>\n * ```\n */\nexport const Html: FunctionalComponent<HtmlProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Html> component'\n );\n }\n context.htmlAttrs = attrs;\n return <>{children}</>;\n};\n","import path from 'node:path';\n\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\n/**\n * A hook that returns information about the current i18n context, including the\n * locale for the given route and a map of translations for that locale.\n */\nexport function useI18nContext() {\n const context = useContext(I18N_CONTEXT);\n if (!context) {\n throw new Error('I18N_CONTEXT not found');\n }\n return context;\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","import {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nimport {Route} from '../types';\n\nexport interface RequestContext {\n /**\n * The current request path, e.g. `/foo/bar` (default route path) or\n * `/{locale}/foo/bar` (localized route path).\n */\n currentPath: string;\n /** The route file. */\n route: Route;\n /**\n * Route param values. E.g. for a route like `routes/blog/[slug].tsx`,\n * visiting `/blog/foo` will pass {slug: 'foo'} here.\n */\n routeParams: Record<string, string>;\n /** Props passed to the route's server component. */\n props: any;\n /** The current locale. */\n locale: string;\n /** Translations map for the current locale. */\n translations: Record<string, string>;\n}\n\nexport const REQUEST_CONTEXT = createContext<RequestContext | null>(null);\n\n/**\n * A hook that returns information about the current route.\n *\n * Usage:\n *\n * ```ts\n * const ctx = useRequestContext();\n * ctx.route.src;\n * // => 'routes/index.tsx'\n * ```\n */\nexport function useRequestContext() {\n const context = useContext(REQUEST_CONTEXT);\n if (!context) {\n throw new Error('REQUEST_CONTEXT not found');\n }\n return context;\n}\n"],"mappings":";AAAA,SAAgD,qBAAoB;AACpE,SAAQ,kBAAiB;AAmChB;AAzBF,IAAM,eAAe,cAAkC,IAAI;AAiB3D,IAAM,OAAuC,CAAC,EAAC,UAAU,GAAG,MAAK,MAAM;AAC5E,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,YAAY;AACpB,SAAO,gCAAG,UAAS;AACrB;;;ACrCA,OAAO,UAAU;AAEjB,SAAQ,iBAAAA,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;AAElB,IAAM,eAAeD,eAAkC,IAAI;AAW3D,SAAS,iBAAiB;AAC/B,QAAM,UAAUC,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AACA,SAAO;AACT;AAEO,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,UAAMC,UAAS,MAAM;AACrB,UAAM,SAAS,kBAAkB,eAAe;AAChD,QAAI,UAAU,OAAO,SAAS;AAC5B,mBAAaA,OAAM,IAAI,OAAO;AAAA,IAChC;AAAA,EACF,CAAC;AACD,SAAO,aAAa,MAAM,KAAK,CAAC;AAClC;;;ACtCA,SAAQ,iBAAAC,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;
|
|
1
|
+
{"version":3,"sources":["../src/core/components/Html.tsx","../src/core/hooks/useI18nContext.ts","../src/core/hooks/useRequestContext.ts"],"sourcesContent":["import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport interface HtmlContext {\n htmlAttrs: preact.JSX.HTMLAttributes<HTMLHtmlElement>;\n headAttrs: preact.JSX.HTMLAttributes<HTMLHeadElement>;\n headComponents: ComponentChildren[];\n bodyAttrs: preact.JSX.HTMLAttributes<HTMLBodyElement>;\n scriptDeps: Array<preact.JSX.HTMLAttributes<HTMLScriptElement>>;\n}\n\nexport const HTML_CONTEXT = createContext<HtmlContext | null>(null);\n\nexport type HtmlProps = preact.JSX.HTMLAttributes<HTMLHtmlElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The `<Html>` component can be used to update attrs in the `<html>` tag.\n *\n * Usage:\n *\n * ```tsx\n * <Html lang=\"en-US\">\n * <h1>Hello world</h1>\n * </Html>\n * ```\n */\nexport const Html: FunctionalComponent<HtmlProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Html> component'\n );\n }\n context.htmlAttrs = attrs;\n return <>{children}</>;\n};\n","import path from 'node:path';\n\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\n/**\n * A hook that returns information about the current i18n context, including the\n * locale for the given route and a map of translations for that locale.\n */\nexport function useI18nContext() {\n const context = useContext(I18N_CONTEXT);\n if (!context) {\n throw new Error('I18N_CONTEXT not found');\n }\n return context;\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","import {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nimport {Route} from '../types';\n\nexport interface RequestContext {\n /**\n * The current request path, e.g. `/foo/bar` (default route path) or\n * `/{locale}/foo/bar` (localized route path).\n */\n currentPath: string;\n /** The route file. */\n route: Route;\n /**\n * Route param values. E.g. for a route like `routes/blog/[slug].tsx`,\n * visiting `/blog/foo` will pass {slug: 'foo'} here.\n */\n routeParams: Record<string, string>;\n /** Props passed to the route's server component. */\n props: any;\n /** The current locale. */\n locale: string;\n /** Translations map for the current locale. */\n translations: Record<string, string>;\n /** CSP nonce value. */\n nonce?: string;\n}\n\nexport const REQUEST_CONTEXT = createContext<RequestContext | null>(null);\n\n/**\n * A hook that returns information about the current route.\n *\n * Usage:\n *\n * ```ts\n * const ctx = useRequestContext();\n * ctx.route.src;\n * // => 'routes/index.tsx'\n * ```\n */\nexport function useRequestContext() {\n const context = useContext(REQUEST_CONTEXT);\n if (!context) {\n throw new Error('REQUEST_CONTEXT not found');\n }\n return context;\n}\n"],"mappings":";AAAA,SAAgD,qBAAoB;AACpE,SAAQ,kBAAiB;AAmChB;AAzBF,IAAM,eAAe,cAAkC,IAAI;AAiB3D,IAAM,OAAuC,CAAC,EAAC,UAAU,GAAG,MAAK,MAAM;AAC5E,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,YAAY;AACpB,SAAO,gCAAG,UAAS;AACrB;;;ACrCA,OAAO,UAAU;AAEjB,SAAQ,iBAAAA,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;AAElB,IAAM,eAAeD,eAAkC,IAAI;AAW3D,SAAS,iBAAiB;AAC/B,QAAM,UAAUC,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AACA,SAAO;AACT;AAEO,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,UAAMC,UAAS,MAAM;AACrB,UAAM,SAAS,kBAAkB,eAAe;AAChD,QAAI,UAAU,OAAO,SAAS;AAC5B,mBAAaA,OAAM,IAAI,OAAO;AAAA,IAChC;AAAA,EACF,CAAC;AACD,SAAO,aAAa,MAAM,KAAK,CAAC;AAClC;;;ACtCA,SAAQ,iBAAAC,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;AA2BlB,IAAM,kBAAkBD,eAAqC,IAAI;AAajE,SAAS,oBAAoB;AAClC,QAAM,UAAUC,YAAW,eAAe;AAC1C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,SAAO;AACT;","names":["createContext","useContext","locale","createContext","useContext"]}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
// src/utils/elements.ts
|
|
2
|
+
var ELEMENT_RE = /^[a-z][\w-]*-[\w-]*$/;
|
|
3
|
+
var HTML_ELEMENTS_REGEX = /<([a-z][\w-]*-[\w-]*)/g;
|
|
4
|
+
function isValidTagName(tagName) {
|
|
5
|
+
return ELEMENT_RE.test(tagName);
|
|
6
|
+
}
|
|
7
|
+
function parseTagNames(src) {
|
|
8
|
+
const tagNames = /* @__PURE__ */ new Set();
|
|
9
|
+
const matches = Array.from(src.matchAll(HTML_ELEMENTS_REGEX));
|
|
10
|
+
for (const match of matches) {
|
|
11
|
+
const tagName = match[1];
|
|
12
|
+
tagNames.add(tagName);
|
|
13
|
+
}
|
|
14
|
+
return Array.from(tagNames);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/render/html-minify.ts
|
|
18
|
+
import { createRequire } from "module";
|
|
19
|
+
var require2 = createRequire(import.meta.url);
|
|
20
|
+
var { minify } = require2("html-minifier-terser");
|
|
21
|
+
async function htmlMinify(html, options) {
|
|
22
|
+
const minifyOptions = options || {
|
|
23
|
+
collapseWhitespace: true,
|
|
24
|
+
removeComments: true,
|
|
25
|
+
preserveLineBreaks: true
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
const min = await minify(html, minifyOptions);
|
|
29
|
+
return min.trimStart();
|
|
30
|
+
} catch (e) {
|
|
31
|
+
console.error("failed to minify html:", e);
|
|
32
|
+
return html;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/render/html-pretty.ts
|
|
37
|
+
import { createRequire as createRequire2 } from "module";
|
|
38
|
+
var require3 = createRequire2(import.meta.url);
|
|
39
|
+
var beautify = require3("js-beautify");
|
|
40
|
+
async function htmlPretty(html, options) {
|
|
41
|
+
const prettyOptions = options || {
|
|
42
|
+
indent_size: 0,
|
|
43
|
+
end_with_newline: true,
|
|
44
|
+
extra_liners: []
|
|
45
|
+
};
|
|
46
|
+
try {
|
|
47
|
+
const output = beautify.html(html, prettyOptions);
|
|
48
|
+
return output.trimStart();
|
|
49
|
+
} catch (e) {
|
|
50
|
+
console.error("failed to pretty html:", e);
|
|
51
|
+
return html;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/render/route-trie.ts
|
|
56
|
+
var RouteTrie = class _RouteTrie {
|
|
57
|
+
constructor() {
|
|
58
|
+
this.children = {};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Adds a route to the trie.
|
|
62
|
+
*/
|
|
63
|
+
add(path, route) {
|
|
64
|
+
path = this.normalizePath(path);
|
|
65
|
+
if (path === "") {
|
|
66
|
+
this.route = route;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const [head, tail] = this.splitPath(path);
|
|
70
|
+
if (head.startsWith("[[...") && head.endsWith("]]")) {
|
|
71
|
+
const paramName = head.slice(5, -2);
|
|
72
|
+
this.optCatchAllNodes = new CatchAllNode(paramName, route);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (head.startsWith("[...") && head.endsWith("]")) {
|
|
76
|
+
const paramName = head.slice(4, -1);
|
|
77
|
+
this.catchAllNodes = new CatchAllNode(paramName, route);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
let nextNode;
|
|
81
|
+
if (head.startsWith("[") && head.endsWith("]")) {
|
|
82
|
+
if (!this.paramNodes) {
|
|
83
|
+
this.paramNodes = {};
|
|
84
|
+
}
|
|
85
|
+
const paramName = head.slice(1, -1);
|
|
86
|
+
if (!this.paramNodes[paramName]) {
|
|
87
|
+
this.paramNodes[paramName] = new ParamNode(paramName);
|
|
88
|
+
}
|
|
89
|
+
nextNode = this.paramNodes[paramName].trie;
|
|
90
|
+
} else {
|
|
91
|
+
nextNode = this.children[head];
|
|
92
|
+
if (!nextNode) {
|
|
93
|
+
nextNode = new _RouteTrie();
|
|
94
|
+
this.children[head] = nextNode;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
nextNode.add(tail, route);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Returns a route mapped to the given path and any parameter values from the
|
|
101
|
+
* URL.
|
|
102
|
+
*/
|
|
103
|
+
get(path) {
|
|
104
|
+
const params = {};
|
|
105
|
+
const route = this.getRoute(path, params);
|
|
106
|
+
return [route, params];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Walks the route trie and calls a callback function for each route.
|
|
110
|
+
*/
|
|
111
|
+
walk(cb) {
|
|
112
|
+
const promises = [];
|
|
113
|
+
const addPromise = (promise) => {
|
|
114
|
+
if (promise) {
|
|
115
|
+
promises.push(promise);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
if (this.route) {
|
|
119
|
+
addPromise(cb("/", this.route));
|
|
120
|
+
}
|
|
121
|
+
if (this.paramNodes) {
|
|
122
|
+
Object.values(this.paramNodes).forEach((paramChild) => {
|
|
123
|
+
const param = `[${paramChild.name}]`;
|
|
124
|
+
paramChild.trie.walk((childPath, route) => {
|
|
125
|
+
const paramUrlPath = `/${param}${childPath}`;
|
|
126
|
+
addPromise(cb(paramUrlPath, route));
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
if (this.catchAllNodes) {
|
|
131
|
+
const wildcardUrlPath = `/[...${this.catchAllNodes.name}]`;
|
|
132
|
+
addPromise(cb(wildcardUrlPath, this.catchAllNodes.route));
|
|
133
|
+
}
|
|
134
|
+
if (this.optCatchAllNodes) {
|
|
135
|
+
const wildcardUrlPath = `/[[...${this.optCatchAllNodes.name}]]`;
|
|
136
|
+
addPromise(cb(wildcardUrlPath, this.optCatchAllNodes.route));
|
|
137
|
+
}
|
|
138
|
+
for (const subpath of Object.keys(this.children)) {
|
|
139
|
+
const childTrie = this.children[subpath];
|
|
140
|
+
childTrie.walk((childPath, childRoute) => {
|
|
141
|
+
addPromise(cb(`/${subpath}${childPath}`, childRoute));
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return Promise.all(promises).then(() => {
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Removes all routes from the trie.
|
|
149
|
+
*/
|
|
150
|
+
clear() {
|
|
151
|
+
this.children = {};
|
|
152
|
+
this.paramNodes = void 0;
|
|
153
|
+
this.catchAllNodes = void 0;
|
|
154
|
+
this.optCatchAllNodes = void 0;
|
|
155
|
+
this.route = void 0;
|
|
156
|
+
}
|
|
157
|
+
getRoute(urlPath, params) {
|
|
158
|
+
urlPath = this.normalizePath(urlPath);
|
|
159
|
+
if (urlPath === "") {
|
|
160
|
+
if (this.route) {
|
|
161
|
+
return this.route;
|
|
162
|
+
}
|
|
163
|
+
if (this.optCatchAllNodes) {
|
|
164
|
+
if (urlPath) {
|
|
165
|
+
params[this.optCatchAllNodes.name] = urlPath;
|
|
166
|
+
}
|
|
167
|
+
return this.optCatchAllNodes.route;
|
|
168
|
+
}
|
|
169
|
+
return void 0;
|
|
170
|
+
}
|
|
171
|
+
const [head, tail] = this.splitPath(urlPath);
|
|
172
|
+
const child = this.children[head];
|
|
173
|
+
if (child) {
|
|
174
|
+
const route = child.getRoute(tail, params);
|
|
175
|
+
if (route) {
|
|
176
|
+
return route;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (this.paramNodes) {
|
|
180
|
+
for (const paramChild of Object.values(this.paramNodes)) {
|
|
181
|
+
const route = paramChild.trie.getRoute(tail, params);
|
|
182
|
+
if (route) {
|
|
183
|
+
params[paramChild.name] = head;
|
|
184
|
+
return route;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (this.catchAllNodes) {
|
|
189
|
+
params[this.catchAllNodes.name] = urlPath;
|
|
190
|
+
return this.catchAllNodes.route;
|
|
191
|
+
}
|
|
192
|
+
if (this.optCatchAllNodes) {
|
|
193
|
+
params[this.optCatchAllNodes.name] = urlPath;
|
|
194
|
+
return this.optCatchAllNodes.route;
|
|
195
|
+
}
|
|
196
|
+
return void 0;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Normalizes a path for inclusion into the route trie.
|
|
200
|
+
*/
|
|
201
|
+
normalizePath(path) {
|
|
202
|
+
return path.replace(/^\/+/g, "").replace(/\/+$/g, "");
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Splits the parent directory from its children, e.g.:
|
|
206
|
+
*
|
|
207
|
+
* splitPath("foo/bar/baz") -> ["foo", "bar/baz"]
|
|
208
|
+
*/
|
|
209
|
+
splitPath(path) {
|
|
210
|
+
const i = path.indexOf("/");
|
|
211
|
+
if (i === -1) {
|
|
212
|
+
return [path, ""];
|
|
213
|
+
}
|
|
214
|
+
return [path.slice(0, i), path.slice(i + 1)];
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
var ParamNode = class {
|
|
218
|
+
constructor(name) {
|
|
219
|
+
this.trie = new RouteTrie();
|
|
220
|
+
this.name = name;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
var CatchAllNode = class {
|
|
224
|
+
constructor(name, route) {
|
|
225
|
+
this.name = name;
|
|
226
|
+
this.route = route;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export {
|
|
231
|
+
isValidTagName,
|
|
232
|
+
parseTagNames,
|
|
233
|
+
htmlMinify,
|
|
234
|
+
htmlPretty,
|
|
235
|
+
RouteTrie
|
|
236
|
+
};
|
|
237
|
+
//# sourceMappingURL=chunk-IUQLRDFW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/elements.ts","../src/render/html-minify.ts","../src/render/html-pretty.ts","../src/render/route-trie.ts"],"sourcesContent":["export const ELEMENT_RE = /^[a-z][\\w-]*-[\\w-]*$/;\nexport const HTML_ELEMENTS_REGEX = /<([a-z][\\w-]*-[\\w-]*)/g;\n\n/**\n * Returns true if the tagName is a valid custom element tag.\n */\nexport function isValidTagName(tagName: string) {\n return ELEMENT_RE.test(tagName);\n}\n\n/**\n * Returns a list of custom elements used in a src string (e.g. HTML, jsx, lit).\n * NOTE: the impl uses a simple regex, so tagNames used in comments and attr\n * values may be included.\n */\nexport function parseTagNames(src: string): string[] {\n const tagNames = new Set<string>();\n const matches = Array.from(src.matchAll(HTML_ELEMENTS_REGEX));\n for (const match of matches) {\n const tagName = match[1];\n tagNames.add(tagName);\n }\n return Array.from(tagNames);\n}\n","import {createRequire} from 'module';\n\nconst require = createRequire(import.meta.url);\nimport type {Options} from 'html-minifier-terser';\n\nconst {minify} = require('html-minifier-terser');\n\nexport type HtmlMinifyOptions = Options;\n\nexport async function htmlMinify(\n html: string,\n options?: HtmlMinifyOptions\n): Promise<string> {\n const minifyOptions = options || {\n collapseWhitespace: true,\n removeComments: true,\n preserveLineBreaks: true,\n };\n try {\n const min = await minify(html, minifyOptions);\n return min.trimStart();\n } catch (e) {\n console.error('failed to minify html:', e);\n return html;\n }\n}\n","import {createRequire} from 'module';\n\nconst require = createRequire(import.meta.url);\nimport type {HTMLBeautifyOptions} from 'js-beautify';\n\nconst beautify = require('js-beautify');\n\nexport type HtmlPrettyOptions = HTMLBeautifyOptions;\n\nexport async function htmlPretty(\n html: string,\n options?: HtmlPrettyOptions\n): Promise<string> {\n const prettyOptions = options || {\n indent_size: 0,\n end_with_newline: true,\n extra_liners: [],\n };\n try {\n const output = beautify.html(html, prettyOptions);\n return output.trimStart();\n } catch (e) {\n console.error('failed to pretty html:', e);\n return html;\n }\n}\n","/**\n * A trie data structure that stores routes. Supports Next-style routing using\n * [param], [...catchall], and [[...optcatchall]] placeholders.\n */\nexport class RouteTrie<T> {\n private children: Record<string, RouteTrie<T>> = {};\n private paramNodes?: {[param: string]: ParamNode<T>};\n private catchAllNodes?: CatchAllNode<T>;\n private optCatchAllNodes?: CatchAllNode<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\n if (head.startsWith('[[...') && head.endsWith(']]')) {\n const paramName = head.slice(5, -2);\n this.optCatchAllNodes = new CatchAllNode(paramName, route);\n return;\n }\n if (head.startsWith('[...') && head.endsWith(']')) {\n const paramName = head.slice(4, -1);\n this.catchAllNodes = new CatchAllNode(paramName, route);\n return;\n }\n\n let nextNode: RouteTrie<T>;\n if (head.startsWith('[') && head.endsWith(']')) {\n if (!this.paramNodes) {\n this.paramNodes = {};\n }\n const paramName = head.slice(1, -1);\n if (!this.paramNodes[paramName]) {\n this.paramNodes[paramName] = new ParamNode(paramName);\n }\n nextNode = this.paramNodes[paramName].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.paramNodes) {\n Object.values(this.paramNodes).forEach((paramChild) => {\n const param = `[${paramChild.name}]`;\n paramChild.trie.walk((childPath: string, route: T) => {\n const paramUrlPath = `/${param}${childPath}`;\n addPromise(cb(paramUrlPath, route));\n });\n });\n }\n if (this.catchAllNodes) {\n const wildcardUrlPath = `/[...${this.catchAllNodes.name}]`;\n addPromise(cb(wildcardUrlPath, this.catchAllNodes.route));\n }\n if (this.optCatchAllNodes) {\n const wildcardUrlPath = `/[[...${this.optCatchAllNodes.name}]]`;\n addPromise(cb(wildcardUrlPath, this.optCatchAllNodes.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.paramNodes = undefined;\n this.catchAllNodes = undefined;\n this.optCatchAllNodes = 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 if (this.route) {\n return this.route;\n }\n if (this.optCatchAllNodes) {\n if (urlPath) {\n params[this.optCatchAllNodes.name] = urlPath;\n }\n return this.optCatchAllNodes.route;\n }\n return undefined;\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.paramNodes) {\n for (const paramChild of Object.values(this.paramNodes)) {\n const route = paramChild.trie.getRoute(tail, params);\n if (route) {\n params[paramChild.name] = head;\n return route;\n }\n }\n }\n\n if (this.catchAllNodes) {\n params[this.catchAllNodes.name] = urlPath;\n return this.catchAllNodes.route;\n }\n\n if (this.optCatchAllNodes) {\n params[this.optCatchAllNodes.name] = urlPath;\n return this.optCatchAllNodes.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/trailing slashes.\n return path.replace(/^\\/+/g, '').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 ParamNode<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 CatchAllNode<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":["require","createRequire","require"]}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
// src/node/load-config.ts
|
|
6
6
|
import path2 from "node:path";
|
|
7
7
|
import { bundleRequire } from "bundle-require";
|
|
8
|
+
import { build } from "esbuild";
|
|
8
9
|
|
|
9
10
|
// src/utils/fsutils.ts
|
|
10
11
|
import { promises as fs } from "node:fs";
|
|
@@ -26,6 +27,12 @@ async function makeDir(dirpath) {
|
|
|
26
27
|
await fs.mkdir(dirpath, { recursive: true });
|
|
27
28
|
}
|
|
28
29
|
}
|
|
30
|
+
async function copyDir(srcdir, dstdir) {
|
|
31
|
+
if (!fsExtra.existsSync(srcdir)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
fsExtra.copySync(srcdir, dstdir, { overwrite: true });
|
|
35
|
+
}
|
|
29
36
|
async function copyGlob(pattern, srcdir, dstdir) {
|
|
30
37
|
const files = await glob(pattern, { cwd: srcdir });
|
|
31
38
|
if (files.length > 0) {
|
|
@@ -42,6 +49,10 @@ async function loadJson(filepath) {
|
|
|
42
49
|
const content = await fs.readFile(filepath, "utf-8");
|
|
43
50
|
return JSON.parse(content);
|
|
44
51
|
}
|
|
52
|
+
async function writeJson(filepath, data) {
|
|
53
|
+
const content = JSON.stringify(data, null, 2);
|
|
54
|
+
await writeFile(filepath, content);
|
|
55
|
+
}
|
|
45
56
|
async function isDirectory(dirpath) {
|
|
46
57
|
return fs.stat(dirpath).then((fsStat) => {
|
|
47
58
|
return fsStat.isDirectory();
|
|
@@ -89,17 +100,90 @@ async function loadRootConfig(rootDir, options) {
|
|
|
89
100
|
}
|
|
90
101
|
return Object.assign({}, config, { rootDir });
|
|
91
102
|
}
|
|
103
|
+
async function bundleRootConfig(rootDir, outPath) {
|
|
104
|
+
const configPath = path2.resolve(rootDir, "root.config.ts");
|
|
105
|
+
const configExists = await fileExists(configPath);
|
|
106
|
+
if (!configExists) {
|
|
107
|
+
throw new Error(`${configPath} does not exist`);
|
|
108
|
+
}
|
|
109
|
+
const packageJsonPath = path2.resolve(rootDir, "package.json");
|
|
110
|
+
const packageJson = await loadPackageJson(packageJsonPath);
|
|
111
|
+
const allDeps = {
|
|
112
|
+
...packageJson.peerDependencies,
|
|
113
|
+
...packageJson.dependencies
|
|
114
|
+
};
|
|
115
|
+
function getPackageName(id) {
|
|
116
|
+
const segments = id.split("/");
|
|
117
|
+
if (segments.length > 1) {
|
|
118
|
+
if (segments[0].startsWith("@") && segments[0].length > 1) {
|
|
119
|
+
return `${segments[0]}/${segments[1]}`;
|
|
120
|
+
}
|
|
121
|
+
return segments[0];
|
|
122
|
+
}
|
|
123
|
+
return id;
|
|
124
|
+
}
|
|
125
|
+
await build({
|
|
126
|
+
entryPoints: [configPath],
|
|
127
|
+
bundle: true,
|
|
128
|
+
minify: true,
|
|
129
|
+
platform: "node",
|
|
130
|
+
outfile: outPath,
|
|
131
|
+
sourcemap: "inline",
|
|
132
|
+
metafile: true,
|
|
133
|
+
format: "esm",
|
|
134
|
+
plugins: [
|
|
135
|
+
// Externalizes deps that are in package.json.
|
|
136
|
+
{
|
|
137
|
+
name: "externalize-package-json-deps",
|
|
138
|
+
setup(build2) {
|
|
139
|
+
build2.onResolve({ filter: /.*/ }, (args) => {
|
|
140
|
+
const id = args.path;
|
|
141
|
+
if (id[0] !== "." && !id.startsWith("@/")) {
|
|
142
|
+
const packageName = getPackageName(id);
|
|
143
|
+
if (packageName in allDeps) {
|
|
144
|
+
return {
|
|
145
|
+
external: true
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
async function loadBundledConfig(rootDir, options) {
|
|
157
|
+
const configPath = path2.resolve(rootDir, "dist/root.config.js");
|
|
158
|
+
const exists = await fileExists(configPath);
|
|
159
|
+
if (!exists) {
|
|
160
|
+
throw new Error(`${configPath} does not exist`);
|
|
161
|
+
}
|
|
162
|
+
const module = await import(configPath);
|
|
163
|
+
let config = module.default || {};
|
|
164
|
+
if (typeof config === "function") {
|
|
165
|
+
config = await config(options) || {};
|
|
166
|
+
}
|
|
167
|
+
return Object.assign({}, config, { rootDir });
|
|
168
|
+
}
|
|
169
|
+
async function loadPackageJson(filepath) {
|
|
170
|
+
try {
|
|
171
|
+
const packageJson = await loadJson(filepath);
|
|
172
|
+
return packageJson || {};
|
|
173
|
+
} catch (err) {
|
|
174
|
+
return {};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
92
177
|
|
|
93
178
|
// src/node/vite.ts
|
|
94
179
|
import { createServer } from "vite";
|
|
95
180
|
async function createViteServer(rootConfig, options) {
|
|
96
|
-
var _a, _b, _c;
|
|
97
181
|
const rootDir = rootConfig.rootDir;
|
|
98
182
|
const viteConfig = rootConfig.vite || {};
|
|
99
|
-
let hmrOptions =
|
|
100
|
-
if (
|
|
183
|
+
let hmrOptions = viteConfig.server?.hmr;
|
|
184
|
+
if (options?.hmr === false) {
|
|
101
185
|
hmrOptions = false;
|
|
102
|
-
} else if (typeof hmrOptions === "undefined" &&
|
|
186
|
+
} else if (typeof hmrOptions === "undefined" && options?.port) {
|
|
103
187
|
hmrOptions = { port: options.port + 10 };
|
|
104
188
|
}
|
|
105
189
|
const viteServer = await createServer({
|
|
@@ -117,16 +201,29 @@ async function createViteServer(rootConfig, options) {
|
|
|
117
201
|
},
|
|
118
202
|
appType: "custom",
|
|
119
203
|
optimizeDeps: {
|
|
204
|
+
// As of vite v5 / esbuild v19, experimentalDecorators need to be
|
|
205
|
+
// explicitly set, and for some reason this option isn't read from the
|
|
206
|
+
// project's tsconfig.json file by default.
|
|
207
|
+
// See: https://vitejs.dev/blog/announcing-vite5
|
|
208
|
+
esbuildOptions: {
|
|
209
|
+
tsconfigRaw: {
|
|
210
|
+
compilerOptions: {
|
|
211
|
+
target: "esnext",
|
|
212
|
+
experimentalDecorators: true,
|
|
213
|
+
useDefineForClassFields: false
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
120
217
|
...viteConfig.optimizeDeps || {},
|
|
121
218
|
include: [
|
|
122
|
-
...
|
|
123
|
-
...
|
|
219
|
+
...options?.optimizeDeps || [],
|
|
220
|
+
...viteConfig.optimizeDeps?.include || []
|
|
124
221
|
],
|
|
125
|
-
extensions: [...
|
|
222
|
+
extensions: [...viteConfig.optimizeDeps?.extensions || [], ".tsx"]
|
|
126
223
|
},
|
|
127
224
|
ssr: {
|
|
128
225
|
...viteConfig.ssr || {},
|
|
129
|
-
noExternal: ["@blinkk/root"]
|
|
226
|
+
noExternal: ["@blinkk/root", "@blinkk/root-cms/richtext"]
|
|
130
227
|
},
|
|
131
228
|
esbuild: {
|
|
132
229
|
...viteConfig.esbuild || {},
|
|
@@ -151,15 +248,20 @@ export {
|
|
|
151
248
|
isJsFile,
|
|
152
249
|
writeFile,
|
|
153
250
|
makeDir,
|
|
251
|
+
copyDir,
|
|
154
252
|
copyGlob,
|
|
155
253
|
rmDir,
|
|
156
254
|
loadJson,
|
|
255
|
+
writeJson,
|
|
157
256
|
isDirectory,
|
|
158
257
|
fileExists,
|
|
159
258
|
dirExists,
|
|
160
259
|
directoryContains,
|
|
161
260
|
loadRootConfig,
|
|
261
|
+
bundleRootConfig,
|
|
262
|
+
loadBundledConfig,
|
|
263
|
+
loadPackageJson,
|
|
162
264
|
createViteServer,
|
|
163
265
|
viteSsrLoadModule
|
|
164
266
|
};
|
|
165
|
-
//# sourceMappingURL=chunk-
|
|
267
|
+
//# sourceMappingURL=chunk-KGPR2CJV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/node/load-config.ts","../src/utils/fsutils.ts","../src/node/vite.ts"],"sourcesContent":["import path from 'node:path';\nimport {bundleRequire} from 'bundle-require';\nimport {build} from 'esbuild';\nimport {RootConfig} from '../core/config';\nimport {fileExists, loadJson} from '../utils/fsutils';\n\nexport interface ConfigOptions {\n command: string;\n}\n\nexport async function loadRootConfig(\n rootDir: string,\n options: ConfigOptions\n): Promise<RootConfig> {\n const configPath = path.resolve(rootDir, 'root.config.ts');\n const exists = await fileExists(configPath);\n if (!exists) {\n throw new Error(`${configPath} does not exist`);\n }\n const configBundle = await bundleRequire({\n filepath: configPath,\n });\n let config = configBundle.mod.default || {};\n if (typeof config === 'function') {\n config = (await config(options)) || {};\n }\n return Object.assign({}, config, {rootDir});\n}\n\n/**\n * Compiles a root.config.ts file to root.config.js.\n */\nexport async function bundleRootConfig(rootDir: string, outPath: string) {\n const configPath = path.resolve(rootDir, 'root.config.ts');\n const configExists = await fileExists(configPath);\n if (!configExists) {\n throw new Error(`${configPath} does not exist`);\n }\n\n const packageJsonPath = path.resolve(rootDir, 'package.json');\n const packageJson = await loadPackageJson(packageJsonPath);\n const allDeps = {\n ...packageJson.peerDependencies,\n ...packageJson.dependencies,\n };\n\n function getPackageName(id: string): string {\n const segments = id.split('/');\n if (segments.length > 1) {\n // Check if package is an org path like `@blinkk/root`.\n if (segments[0].startsWith('@') && segments[0].length > 1) {\n return `${segments[0]}/${segments[1]}`;\n }\n // For imports like `my-package/subpackage`, return `my-package`.\n return segments[0];\n }\n return id;\n }\n\n await build({\n entryPoints: [configPath],\n bundle: true,\n minify: true,\n platform: 'node',\n outfile: outPath,\n sourcemap: 'inline',\n metafile: true,\n format: 'esm',\n plugins: [\n // Externalizes deps that are in package.json.\n {\n name: 'externalize-package-json-deps',\n setup(build) {\n build.onResolve({filter: /.*/}, (args) => {\n const id = args.path;\n if (id[0] !== '.' && !id.startsWith('@/')) {\n const packageName = getPackageName(id);\n if (packageName in allDeps) {\n return {\n external: true,\n };\n }\n }\n return null;\n });\n },\n },\n ],\n });\n}\n\n/**\n * Loads a pre-bundled config file from dist/root.config.js.\n */\nexport async function loadBundledConfig(\n rootDir: string,\n options: ConfigOptions\n): Promise<RootConfig> {\n const configPath = path.resolve(rootDir, 'dist/root.config.js');\n const exists = await fileExists(configPath);\n if (!exists) {\n throw new Error(`${configPath} does not exist`);\n }\n const module = await import(configPath);\n let config = module.default || {};\n if (typeof config === 'function') {\n config = (await config(options)) || {};\n }\n return Object.assign({}, config, {rootDir});\n}\n\nexport async function loadPackageJson(filepath: string): Promise<any> {\n try {\n const packageJson = await loadJson(filepath);\n return packageJson || {};\n } catch (err) {\n return {};\n }\n}\n","import {promises as fs} from 'node:fs';\nimport path from 'node:path';\n\nimport fsExtra from 'fs-extra';\nimport glob from 'tiny-glob';\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, {overwrite: true});\n}\n\n/**\n * Copies a glob of files from one directory to another.\n *\n * Example:\n *\n * ```\n * await copyGlob('*.css', 'src/styles', 'dist/html/styles');\n * ```\n */\nexport async function copyGlob(\n pattern: string,\n srcdir: string,\n dstdir: string\n) {\n const files = await glob(pattern, {cwd: srcdir});\n if (files.length > 0) {\n await makeDir(dstdir);\n }\n files.forEach((file) => {\n fsExtra.copySync(path.resolve(srcdir, file), path.resolve(dstdir, file));\n });\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 writeJson(filepath: string, data: any) {\n const content = JSON.stringify(data, null, 2);\n await writeFile(filepath, 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\nexport async function dirExists(dirpath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirpath);\n return stat.isDirectory();\n } catch (error) {\n if (error.code === 'ENOENT') {\n return false;\n }\n throw error;\n }\n}\n\nexport async function directoryContains(\n dirpath: string,\n subpath: string\n): Promise<boolean> {\n const outer = await fs.realpath(dirpath);\n const inner = await fs.realpath(subpath);\n const rel = path.relative(outer, inner);\n return !rel.startsWith('..');\n}\n\nexport async function listFilesRecursive(dirPath: string): Promise<string[]> {\n const files: string[] = [];\n const entries = await fs.readdir(dirPath, {withFileTypes: true});\n for (const entry of entries) {\n const fullPath = path.join(dirPath, entry.name);\n if (entry.isDirectory()) {\n const subFiles = await listFilesRecursive(fullPath);\n files.push(...subFiles);\n } else {\n files.push(fullPath);\n }\n }\n return files;\n}\n","import path from 'node:path';\n\nimport {createServer, ViteDevServer} from 'vite';\n\nimport {RootConfig} from '../core/config.js';\nimport {getVitePlugins} from '../core/plugin.js';\n\nexport interface CreateViteServerOptions {\n /** Override HMR settings. */\n hmr?: boolean;\n /** The port the server will run on. */\n port?: number;\n /** List of files to include in the optimizeDeps.include config. */\n optimizeDeps?: string[];\n}\n\n/**\n * Returns a vite dev server.\n */\nexport async function createViteServer(\n rootConfig: RootConfig,\n options?: CreateViteServerOptions\n): Promise<ViteDevServer> {\n const rootDir = rootConfig.rootDir;\n const viteConfig = rootConfig.vite || {};\n\n let hmrOptions = viteConfig.server?.hmr;\n if (options?.hmr === false) {\n hmrOptions = false;\n } else if (typeof hmrOptions === 'undefined' && options?.port) {\n // Automatically set the HMR port to `port + 10`. This allows multiple\n // root.js dev servers to run without conflicts.\n hmrOptions = {port: options.port + 10};\n }\n\n const viteServer = await createServer({\n ...viteConfig,\n mode: 'development',\n root: rootDir,\n // publicDir is disabled from the vite dev server since it's handled by the\n // root dev server directly, which allows user middlewares to override\n // files in the public dir.\n publicDir: false,\n server: {\n ...(viteConfig.server || {}),\n middlewareMode: true,\n hmr: hmrOptions,\n },\n appType: 'custom',\n optimizeDeps: {\n // As of vite v5 / esbuild v19, experimentalDecorators need to be\n // explicitly set, and for some reason this option isn't read from the\n // project's tsconfig.json file by default.\n // See: https://vitejs.dev/blog/announcing-vite5\n esbuildOptions: {\n tsconfigRaw: {\n compilerOptions: {\n target: 'esnext',\n experimentalDecorators: true,\n useDefineForClassFields: false,\n },\n },\n },\n ...(viteConfig.optimizeDeps || {}),\n include: [\n ...(options?.optimizeDeps || []),\n ...(viteConfig.optimizeDeps?.include || []),\n ],\n extensions: [...(viteConfig.optimizeDeps?.extensions || []), '.tsx'],\n },\n ssr: {\n ...(viteConfig.ssr || {}),\n noExternal: ['@blinkk/root', '@blinkk/root-cms/richtext'],\n },\n esbuild: {\n ...(viteConfig.esbuild || {}),\n jsx: 'automatic',\n jsxImportSource: 'preact',\n },\n plugins: [\n ...(viteConfig.plugins || []),\n ...getVitePlugins(rootConfig.plugins || []),\n ],\n });\n return viteServer;\n}\n\n/**\n * Shortcut `viteServer.ssrLoadModule()` without starting an actual dev server.\n */\nexport async function viteSsrLoadModule(\n rootConfig: RootConfig,\n file: string\n): Promise<Record<string, any>> {\n const viteServer = await createViteServer(rootConfig, {hmr: false});\n const module = await viteServer.ssrLoadModule(file);\n await viteServer.close();\n return module;\n}\n"],"mappings":"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","names":["path","path","build"]}
|