@blinkk/root 1.0.0-rc.14 → 1.0.0-rc.16

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.
@@ -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";
@@ -89,6 +90,52 @@ async function loadRootConfig(rootDir, options) {
89
90
  }
90
91
  return Object.assign({}, config, { rootDir });
91
92
  }
93
+ async function bundleRootConfig(rootDir, outPath) {
94
+ const configPath = path2.resolve(rootDir, "root.config.ts");
95
+ const exists = await fileExists(configPath);
96
+ if (!exists) {
97
+ throw new Error(`${configPath} does not exist`);
98
+ }
99
+ await build({
100
+ entryPoints: [configPath],
101
+ bundle: true,
102
+ minify: true,
103
+ platform: "node",
104
+ outfile: outPath,
105
+ sourcemap: "inline",
106
+ metafile: true,
107
+ format: "esm",
108
+ plugins: [
109
+ {
110
+ name: "externalize-deps",
111
+ setup(build2) {
112
+ build2.onResolve({ filter: /.*/ }, (args) => {
113
+ const id = args.path;
114
+ if (id[0] !== "." && !path2.isAbsolute(id)) {
115
+ return {
116
+ external: true
117
+ };
118
+ }
119
+ return null;
120
+ });
121
+ }
122
+ }
123
+ ]
124
+ });
125
+ }
126
+ async function loadBundledConfig(rootDir, options) {
127
+ const configPath = path2.resolve(rootDir, "dist/root.config.js");
128
+ const exists = await fileExists(configPath);
129
+ if (!exists) {
130
+ throw new Error(`${configPath} does not exist`);
131
+ }
132
+ const module = await import(configPath);
133
+ let config = module.default || {};
134
+ if (typeof config === "function") {
135
+ config = await config(options) || {};
136
+ }
137
+ return Object.assign({}, config, { rootDir });
138
+ }
92
139
 
93
140
  // src/node/vite.ts
94
141
  import { createServer } from "vite";
@@ -126,7 +173,7 @@ async function createViteServer(rootConfig, options) {
126
173
  },
127
174
  ssr: {
128
175
  ...viteConfig.ssr || {},
129
- noExternal: ["@blinkk/root"]
176
+ noExternal: ["@blinkk/root", "@blinkk/root-cms/richtext"]
130
177
  },
131
178
  esbuild: {
132
179
  ...viteConfig.esbuild || {},
@@ -159,7 +206,9 @@ export {
159
206
  dirExists,
160
207
  directoryContains,
161
208
  loadRootConfig,
209
+ bundleRootConfig,
210
+ loadBundledConfig,
162
211
  createViteServer,
163
212
  viteSsrLoadModule
164
213
  };
165
- //# sourceMappingURL=chunk-HPVFCSVJ.js.map
214
+ //# sourceMappingURL=chunk-AJZIUTCI.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} 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 exists = await fileExists(configPath);\n if (!exists) {\n throw new Error(`${configPath} does not exist`);\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 {\n name: 'externalize-deps',\n setup(build) {\n build.onResolve({filter: /.*/}, (args) => {\n const id = args.path;\n if (id[0] !== '.' && !path.isAbsolute(id)) {\n return {\n external: true,\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","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 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 ...(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"]}
@@ -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"]}
@@ -4,6 +4,7 @@ import {
4
4
  trailingSlashMiddleware
5
5
  } from "./chunk-WNXIRMFF.js";
6
6
  import {
7
+ bundleRootConfig,
7
8
  copyGlob,
8
9
  createViteServer,
9
10
  dirExists,
@@ -11,22 +12,24 @@ import {
11
12
  fileExists,
12
13
  isDirectory,
13
14
  isJsFile,
15
+ loadBundledConfig,
14
16
  loadJson,
15
17
  loadRootConfig,
16
18
  makeDir,
17
19
  rmDir,
18
20
  writeFile
19
- } from "./chunk-HPVFCSVJ.js";
21
+ } from "./chunk-AJZIUTCI.js";
20
22
  import {
21
23
  configureServerPlugins,
22
24
  getVitePlugins
23
25
  } from "./chunk-QKBMWK5B.js";
24
26
  import {
27
+ RouteTrie,
25
28
  htmlMinify,
26
29
  htmlPretty,
27
30
  isValidTagName,
28
31
  parseTagNames
29
- } from "./chunk-DFBTOMQF.js";
32
+ } from "./chunk-IUQLRDFW.js";
30
33
 
31
34
  // src/cli/commands/build.ts
32
35
  import path3 from "node:path";
@@ -415,7 +418,7 @@ async function build(rootProjectDir, options) {
415
418
  ssr: {
416
419
  ...viteConfig.ssr,
417
420
  target: "node",
418
- noExternal: ["@blinkk/root", ...noExternal]
421
+ noExternal: ["@blinkk/root", "@blinkk/root-cms/richtext", ...noExternal]
419
422
  }
420
423
  });
421
424
  await viteBuild({
@@ -483,6 +486,7 @@ async function build(rootProjectDir, options) {
483
486
  "{}"
484
487
  );
485
488
  }
489
+ await bundleRootConfig(rootDir, path3.join(distDir, "root.config.js"));
486
490
  await copyGlob(
487
491
  "**/*.css",
488
492
  path3.join(distDir, ".build/routes"),
@@ -698,6 +702,51 @@ var Hooks = class {
698
702
  }
699
703
  };
700
704
 
705
+ // src/middleware/redirects.ts
706
+ function redirectsMiddleware(options) {
707
+ const routeTrie = new RouteTrie();
708
+ const redirects = options.redirects || [];
709
+ redirects.forEach((redirect) => {
710
+ if (!verifyRedirectConfig(redirect)) {
711
+ console.warn("ignoring invalid redirect config:", redirect);
712
+ return;
713
+ }
714
+ routeTrie.add(redirect.source, redirect);
715
+ });
716
+ return (req, res, next) => {
717
+ const [redirect, params] = routeTrie.get(req.path);
718
+ if (redirect) {
719
+ const destination = replaceParams(redirect.destination, params);
720
+ const code = redirect.type || 302;
721
+ res.redirect(code, destination);
722
+ return;
723
+ }
724
+ next();
725
+ };
726
+ }
727
+ function verifyRedirectConfig(redirect) {
728
+ if (!redirect.source) {
729
+ return false;
730
+ }
731
+ if (!redirect.destination) {
732
+ return false;
733
+ }
734
+ return true;
735
+ }
736
+ function replaceParams(urlPathFormat, params) {
737
+ const urlPath = urlPathFormat.replaceAll(
738
+ /\[\[?(\.\.\.)?([\w\-_]*)\]?\]/g,
739
+ (match, _wildcard, key) => {
740
+ const val = params[key];
741
+ if (!val) {
742
+ throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);
743
+ }
744
+ return val;
745
+ }
746
+ );
747
+ return urlPath;
748
+ }
749
+
701
750
  // src/render/asset-map/dev-asset-map.ts
702
751
  import path4 from "node:path";
703
752
  import { searchForWorkspaceRoot as searchForWorkspaceRoot2 } from "vite";
@@ -908,11 +957,16 @@ async function createDevServer(options) {
908
957
  await configureServerPlugins(
909
958
  server,
910
959
  async () => {
911
- var _a2;
960
+ var _a2, _b;
912
961
  const userMiddlewares = ((_a2 = rootConfig.server) == null ? void 0 : _a2.middlewares) || [];
913
962
  for (const middleware of userMiddlewares) {
914
963
  server.use(middleware);
915
964
  }
965
+ if ((_b = rootConfig.server) == null ? void 0 : _b.redirects) {
966
+ server.use(
967
+ redirectsMiddleware({ redirects: rootConfig.server.redirects })
968
+ );
969
+ }
916
970
  const publicDir = path5.join(rootDir, "public");
917
971
  if (await dirExists(publicDir)) {
918
972
  server.use(sirv(publicDir, { dev: false }));
@@ -1059,7 +1113,7 @@ async function preview(rootProjectDir, options) {
1059
1113
  async function createPreviewServer(options) {
1060
1114
  var _a;
1061
1115
  const rootDir = options.rootDir;
1062
- const rootConfig = await loadRootConfig(rootDir, { command: "preview" });
1116
+ const rootConfig = await loadBundledConfig(rootDir, { command: "preview" });
1063
1117
  const distDir = path6.join(rootDir, "dist");
1064
1118
  const server = express2();
1065
1119
  server.disable("x-powered-by");
@@ -1074,11 +1128,16 @@ async function createPreviewServer(options) {
1074
1128
  configureServerPlugins(
1075
1129
  server,
1076
1130
  async () => {
1077
- var _a2;
1131
+ var _a2, _b;
1078
1132
  const userMiddlewares = ((_a2 = rootConfig.server) == null ? void 0 : _a2.middlewares) || [];
1079
1133
  userMiddlewares.forEach((middleware) => {
1080
1134
  server.use(middleware);
1081
1135
  });
1136
+ if ((_b = rootConfig.server) == null ? void 0 : _b.redirects) {
1137
+ server.use(
1138
+ redirectsMiddleware({ redirects: rootConfig.server.redirects })
1139
+ );
1140
+ }
1082
1141
  const publicDir = path6.join(distDir, "html");
1083
1142
  server.use(sirv2(publicDir, { dev: false }));
1084
1143
  server.use(trailingSlashMiddleware({ rootConfig }));
@@ -1194,7 +1253,7 @@ async function start(rootProjectDir, options) {
1194
1253
  async function createProdServer(options) {
1195
1254
  var _a;
1196
1255
  const rootDir = options.rootDir;
1197
- const rootConfig = await loadRootConfig(rootDir, { command: "start" });
1256
+ const rootConfig = await loadBundledConfig(rootDir, { command: "start" });
1198
1257
  const distDir = path7.join(rootDir, "dist");
1199
1258
  const server = express3();
1200
1259
  server.disable("x-powered-by");
@@ -1209,11 +1268,16 @@ async function createProdServer(options) {
1209
1268
  configureServerPlugins(
1210
1269
  server,
1211
1270
  async () => {
1212
- var _a2;
1271
+ var _a2, _b;
1213
1272
  const userMiddlewares = ((_a2 = rootConfig.server) == null ? void 0 : _a2.middlewares) || [];
1214
1273
  userMiddlewares.forEach((middleware) => {
1215
1274
  server.use(middleware);
1216
1275
  });
1276
+ if ((_b = rootConfig.server) == null ? void 0 : _b.redirects) {
1277
+ server.use(
1278
+ redirectsMiddleware({ redirects: rootConfig.server.redirects })
1279
+ );
1280
+ }
1217
1281
  const publicDir = path7.join(distDir, "html");
1218
1282
  server.use(sirv3(publicDir, { dev: false }));
1219
1283
  server.use(trailingSlashMiddleware({ rootConfig }));
@@ -1315,4 +1379,4 @@ export {
1315
1379
  start,
1316
1380
  createProdServer
1317
1381
  };
1318
- //# sourceMappingURL=chunk-DWOQYJXQ.js.map
1382
+ //# sourceMappingURL=chunk-SPCBGLM7.js.map