@blinkk/root 1.0.0-alpha.1 → 1.0.0-alpha.11
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 +34 -16
- package/dist/{chunk-4SVK7R4Z.js → chunk-ZV52A6YZ.js} +42 -22
- package/dist/chunk-ZV52A6YZ.js.map +1 -0
- package/dist/cli.d.ts +10 -4
- package/dist/cli.js +540 -199
- package/dist/cli.js.map +1 -1
- package/dist/config-ea7b8b9c.d.ts +81 -0
- package/dist/core.d.ts +7 -6
- package/dist/core.js +3 -3
- package/dist/core.js.map +1 -1
- package/dist/render.d.ts +9 -16
- package/dist/render.js +238 -86
- package/dist/render.js.map +1 -1
- package/package.json +19 -22
- package/dist/chunk-4SVK7R4Z.js.map +0 -1
- package/dist/config-5b8f6033.d.ts +0 -15
package/dist/render.js
CHANGED
|
@@ -4,11 +4,9 @@ import {
|
|
|
4
4
|
I18N_CONTEXT,
|
|
5
5
|
SCRIPT_CONTEXT,
|
|
6
6
|
getTranslations
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZV52A6YZ.js";
|
|
8
8
|
|
|
9
9
|
// src/render/render.tsx
|
|
10
|
-
import path2 from "node:path";
|
|
11
|
-
import { h } from "preact";
|
|
12
10
|
import renderToString from "preact-render-to-string";
|
|
13
11
|
|
|
14
12
|
// src/render/router.ts
|
|
@@ -19,13 +17,13 @@ var RouteTrie = class {
|
|
|
19
17
|
constructor() {
|
|
20
18
|
this.children = {};
|
|
21
19
|
}
|
|
22
|
-
add(
|
|
23
|
-
|
|
24
|
-
if (
|
|
20
|
+
add(path2, route) {
|
|
21
|
+
path2 = this.normalizePath(path2);
|
|
22
|
+
if (path2 === "") {
|
|
25
23
|
this.route = route;
|
|
26
24
|
return;
|
|
27
25
|
}
|
|
28
|
-
const [head, tail] = this.splitPath(
|
|
26
|
+
const [head, tail] = this.splitPath(path2);
|
|
29
27
|
if (head.startsWith("[...") && head.endsWith("]")) {
|
|
30
28
|
const paramName = head.slice(4, -1);
|
|
31
29
|
this.wildcardChild = new WildcardChild(paramName, route);
|
|
@@ -47,9 +45,9 @@ var RouteTrie = class {
|
|
|
47
45
|
}
|
|
48
46
|
nextNode.add(tail, route);
|
|
49
47
|
}
|
|
50
|
-
get(
|
|
48
|
+
get(path2) {
|
|
51
49
|
const params = {};
|
|
52
|
-
const route = this.getRoute(
|
|
50
|
+
const route = this.getRoute(path2, params);
|
|
53
51
|
return [route, params];
|
|
54
52
|
}
|
|
55
53
|
walk(cb) {
|
|
@@ -79,7 +77,8 @@ var RouteTrie = class {
|
|
|
79
77
|
addPromise(cb(`/${subpath}${childPath}`, childRoute));
|
|
80
78
|
});
|
|
81
79
|
}
|
|
82
|
-
return Promise.all(promises)
|
|
80
|
+
return Promise.all(promises).then(() => {
|
|
81
|
+
});
|
|
83
82
|
}
|
|
84
83
|
clear() {
|
|
85
84
|
this.children = {};
|
|
@@ -113,15 +112,15 @@ var RouteTrie = class {
|
|
|
113
112
|
}
|
|
114
113
|
return void 0;
|
|
115
114
|
}
|
|
116
|
-
normalizePath(
|
|
117
|
-
return
|
|
115
|
+
normalizePath(path2) {
|
|
116
|
+
return path2.replace(/^\/+/g, "");
|
|
118
117
|
}
|
|
119
|
-
splitPath(
|
|
120
|
-
const i =
|
|
118
|
+
splitPath(path2) {
|
|
119
|
+
const i = path2.indexOf("/");
|
|
121
120
|
if (i === -1) {
|
|
122
|
-
return [
|
|
121
|
+
return [path2, ""];
|
|
123
122
|
}
|
|
124
|
-
return [
|
|
123
|
+
return [path2.slice(0, i), path2.slice(i + 1)];
|
|
125
124
|
}
|
|
126
125
|
};
|
|
127
126
|
var ParamChild = class {
|
|
@@ -143,9 +142,12 @@ function getRoutes(config) {
|
|
|
143
142
|
const locales = ((_a = config.i18n) == null ? void 0 : _a.locales) || [];
|
|
144
143
|
const i18nUrlFormat = ((_b = config.i18n) == null ? void 0 : _b.urlFormat) || "/{locale}/{path}";
|
|
145
144
|
const defaultLocale = ((_c = config.i18n) == null ? void 0 : _c.defaultLocale) || "en";
|
|
146
|
-
const routes = import.meta.glob(
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
const routes = import.meta.glob(
|
|
146
|
+
["/routes/*.ts", "/routes/**/*.ts", "/routes/*.tsx", "/routes/**/*.tsx"],
|
|
147
|
+
{
|
|
148
|
+
eager: true
|
|
149
|
+
}
|
|
150
|
+
);
|
|
149
151
|
const trie = new RouteTrie();
|
|
150
152
|
Object.keys(routes).forEach((filePath) => {
|
|
151
153
|
let routePath = filePath.replace(/^\/routes/, "");
|
|
@@ -181,38 +183,153 @@ async function getAllPathsForRoute(urlPathFormat, route) {
|
|
|
181
183
|
const routeModule = route.module;
|
|
182
184
|
if (routeModule.getStaticPaths) {
|
|
183
185
|
const staticPaths = await routeModule.getStaticPaths();
|
|
184
|
-
staticPaths.paths
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
if (staticPaths.paths) {
|
|
187
|
+
staticPaths.paths.forEach(
|
|
188
|
+
(pathParams) => {
|
|
189
|
+
const urlPath = replaceParams(urlPathFormat, pathParams.params || {});
|
|
190
|
+
if (pathContainsPlaceholders(urlPath)) {
|
|
191
|
+
console.warn(
|
|
192
|
+
`path contains placeholders: ${urlPathFormat}, double check getStaticPaths() and ensure all params are returned`
|
|
193
|
+
);
|
|
194
|
+
} else {
|
|
195
|
+
urlPaths.push({
|
|
196
|
+
urlPath: replaceParams(urlPathFormat, pathParams.params),
|
|
197
|
+
params: pathParams.params || {}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
} else if (pathContainsPlaceholders(urlPathFormat)) {
|
|
204
|
+
console.warn(
|
|
205
|
+
`path contains placeholders: ${urlPathFormat}, did you forget to define getStaticPaths()?`
|
|
206
|
+
);
|
|
190
207
|
} else {
|
|
191
208
|
urlPaths.push({ urlPath: urlPathFormat, params: {} });
|
|
192
209
|
}
|
|
193
210
|
return urlPaths;
|
|
194
211
|
}
|
|
195
212
|
function replaceParams(urlPathFormat, params) {
|
|
196
|
-
const urlPath = urlPathFormat.replaceAll(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
213
|
+
const urlPath = urlPathFormat.replaceAll(
|
|
214
|
+
/\[(\.\.\.)?([\w\-_]*)\]/g,
|
|
215
|
+
(match, _wildcard, key) => {
|
|
216
|
+
const val = params[key];
|
|
217
|
+
if (!val) {
|
|
218
|
+
throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);
|
|
219
|
+
}
|
|
220
|
+
return val;
|
|
200
221
|
}
|
|
201
|
-
|
|
202
|
-
});
|
|
222
|
+
);
|
|
203
223
|
return urlPath;
|
|
204
224
|
}
|
|
225
|
+
function pathContainsPlaceholders(urlPath) {
|
|
226
|
+
const segments = urlPath.split("/");
|
|
227
|
+
return segments.some((segment) => {
|
|
228
|
+
return segment.startsWith("[") && segment.endsWith("]");
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/render/render.tsx
|
|
233
|
+
import { elementsMap } from "virtual:root-elements";
|
|
234
|
+
|
|
235
|
+
// src/core/components/dev-not-found-page.tsx
|
|
236
|
+
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
237
|
+
var STYLES = `
|
|
238
|
+
body {
|
|
239
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
h1 {
|
|
243
|
+
margin-bottom: 40px;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.route-list {
|
|
247
|
+
display: grid;
|
|
248
|
+
grid-template-columns: auto 1fr;
|
|
249
|
+
align-items: center;
|
|
250
|
+
column-gap: 24px;
|
|
251
|
+
row-gap: 8px;
|
|
252
|
+
padding: 0 40px;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.route-module {
|
|
256
|
+
text-align: right;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
hr {
|
|
260
|
+
margin: 60px 0;
|
|
261
|
+
}
|
|
262
|
+
`;
|
|
263
|
+
function DevNotFoundPage(props) {
|
|
264
|
+
const routesList = [];
|
|
265
|
+
Object.keys(props.sitemap).forEach((urlPath) => {
|
|
266
|
+
const route = props.sitemap[urlPath].route;
|
|
267
|
+
routesList.push(Object.assign({}, route, { urlPath }));
|
|
268
|
+
});
|
|
269
|
+
return /* @__PURE__ */ jsxs(Fragment, {
|
|
270
|
+
children: [
|
|
271
|
+
/* @__PURE__ */ jsx("style", {
|
|
272
|
+
dangerouslySetInnerHTML: { __html: STYLES }
|
|
273
|
+
}),
|
|
274
|
+
/* @__PURE__ */ jsxs("div", {
|
|
275
|
+
children: [
|
|
276
|
+
/* @__PURE__ */ jsxs("h1", {
|
|
277
|
+
children: [
|
|
278
|
+
/* @__PURE__ */ jsx("strong", {
|
|
279
|
+
children: "404:"
|
|
280
|
+
}),
|
|
281
|
+
" Not Found"
|
|
282
|
+
]
|
|
283
|
+
}),
|
|
284
|
+
routesList.length > 0 ? /* @__PURE__ */ jsxs(Fragment, {
|
|
285
|
+
children: [
|
|
286
|
+
/* @__PURE__ */ jsx("h2", {
|
|
287
|
+
children: "Routes found in the project:"
|
|
288
|
+
}),
|
|
289
|
+
/* @__PURE__ */ jsx("div", {
|
|
290
|
+
class: "route-list",
|
|
291
|
+
children: routesList.map((route) => /* @__PURE__ */ jsxs(Fragment, {
|
|
292
|
+
children: [
|
|
293
|
+
/* @__PURE__ */ jsx("div", {
|
|
294
|
+
class: "route-module",
|
|
295
|
+
children: route.modulePath
|
|
296
|
+
}),
|
|
297
|
+
/* @__PURE__ */ jsx("a", {
|
|
298
|
+
class: "route-url",
|
|
299
|
+
href: route.urlPath,
|
|
300
|
+
children: route.urlPath
|
|
301
|
+
})
|
|
302
|
+
]
|
|
303
|
+
}))
|
|
304
|
+
})
|
|
305
|
+
]
|
|
306
|
+
}) : /* @__PURE__ */ jsxs(Fragment, {
|
|
307
|
+
children: [
|
|
308
|
+
/* @__PURE__ */ jsx("h2", {
|
|
309
|
+
children: "No routes found in the project"
|
|
310
|
+
}),
|
|
311
|
+
/* @__PURE__ */ jsxs("p", {
|
|
312
|
+
children: [
|
|
313
|
+
"Add your first route at ",
|
|
314
|
+
/* @__PURE__ */ jsx("code", {
|
|
315
|
+
children: "/routes/index.tsx"
|
|
316
|
+
})
|
|
317
|
+
]
|
|
318
|
+
})
|
|
319
|
+
]
|
|
320
|
+
}),
|
|
321
|
+
/* @__PURE__ */ jsx("hr", {}),
|
|
322
|
+
/* @__PURE__ */ jsx("p", {
|
|
323
|
+
children: "Note: This page could use some love! If you're interested in helping to style this page, please reach out to the root.js developers!"
|
|
324
|
+
})
|
|
325
|
+
]
|
|
326
|
+
})
|
|
327
|
+
]
|
|
328
|
+
});
|
|
329
|
+
}
|
|
205
330
|
|
|
206
331
|
// src/render/render.tsx
|
|
207
|
-
|
|
208
|
-
var ELEMENTS_MODULES = import.meta.glob([
|
|
209
|
-
"/elements/**/*.ts",
|
|
210
|
-
"/elements/**/*.tsx"
|
|
211
|
-
]);
|
|
212
|
-
Object.keys(ELEMENTS_MODULES).forEach((elementPath) => {
|
|
213
|
-
const parts = path2.parse(elementPath);
|
|
214
|
-
ELEMENTS_MAP[parts.name] = elementPath;
|
|
215
|
-
});
|
|
332
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
216
333
|
var Renderer = class {
|
|
217
334
|
constructor(config) {
|
|
218
335
|
this.routes = getRoutes(config);
|
|
@@ -223,12 +340,17 @@ var Renderer = class {
|
|
|
223
340
|
if (route && route.module && route.module.default) {
|
|
224
341
|
return await this.renderRoute(route, { routeParams, assetMap });
|
|
225
342
|
}
|
|
226
|
-
return
|
|
343
|
+
return { notFound: true };
|
|
227
344
|
}
|
|
228
345
|
async renderRoute(route, options) {
|
|
229
346
|
const routeParams = options.routeParams;
|
|
230
347
|
const assetMap = options.assetMap;
|
|
231
348
|
const Component = route.module.default;
|
|
349
|
+
if (!Component) {
|
|
350
|
+
throw new Error(
|
|
351
|
+
"unable to render route. the route should have a default export that renders a jsx component."
|
|
352
|
+
);
|
|
353
|
+
}
|
|
232
354
|
let props = {};
|
|
233
355
|
if (route.module.getStaticProps) {
|
|
234
356
|
const propsData = await route.module.getStaticProps({
|
|
@@ -245,21 +367,24 @@ var Renderer = class {
|
|
|
245
367
|
const translations = getTranslations(locale);
|
|
246
368
|
const headComponents = [];
|
|
247
369
|
const userScripts = [];
|
|
248
|
-
const vdom = /* @__PURE__ */
|
|
249
|
-
value: { locale, translations }
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
370
|
+
const vdom = /* @__PURE__ */ jsx2(I18N_CONTEXT.Provider, {
|
|
371
|
+
value: { locale, translations },
|
|
372
|
+
children: /* @__PURE__ */ jsx2(SCRIPT_CONTEXT.Provider, {
|
|
373
|
+
value: userScripts,
|
|
374
|
+
children: /* @__PURE__ */ jsx2(HEAD_CONTEXT.Provider, {
|
|
375
|
+
value: headComponents,
|
|
376
|
+
children: /* @__PURE__ */ jsx2(Component, {
|
|
377
|
+
...props
|
|
378
|
+
})
|
|
379
|
+
})
|
|
380
|
+
})
|
|
381
|
+
});
|
|
257
382
|
const mainHtml = renderToString(vdom, {}, { pretty: true });
|
|
258
383
|
const pageAsset = await assetMap.get(route.modulePath);
|
|
259
384
|
const cssDeps = await (pageAsset == null ? void 0 : pageAsset.getCssDeps());
|
|
260
385
|
if (cssDeps) {
|
|
261
386
|
cssDeps.forEach((cssUrl) => {
|
|
262
|
-
headComponents.push(/* @__PURE__ */
|
|
387
|
+
headComponents.push(/* @__PURE__ */ jsx2("link", {
|
|
263
388
|
rel: "stylesheet",
|
|
264
389
|
href: cssUrl
|
|
265
390
|
}));
|
|
@@ -267,22 +392,23 @@ var Renderer = class {
|
|
|
267
392
|
}
|
|
268
393
|
const scriptDeps = await this.getScriptDeps(mainHtml, { assetMap });
|
|
269
394
|
scriptDeps.forEach((jsUrls) => {
|
|
270
|
-
headComponents.push(/* @__PURE__ */
|
|
395
|
+
headComponents.push(/* @__PURE__ */ jsx2("script", {
|
|
271
396
|
type: "module",
|
|
272
397
|
src: jsUrls
|
|
273
398
|
}));
|
|
274
399
|
});
|
|
275
|
-
await Promise.all(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
400
|
+
await Promise.all(
|
|
401
|
+
userScripts.map(async (scriptDep) => {
|
|
402
|
+
const scriptAsset = await assetMap.get(scriptDep.src);
|
|
403
|
+
if (scriptAsset) {
|
|
404
|
+
const scriptUrl = scriptAsset ? scriptAsset.assetUrl : scriptDep.src;
|
|
405
|
+
headComponents.push(/* @__PURE__ */ jsx2("script", {
|
|
406
|
+
type: "module",
|
|
407
|
+
src: scriptUrl
|
|
408
|
+
}));
|
|
409
|
+
}
|
|
410
|
+
})
|
|
411
|
+
);
|
|
286
412
|
const html = await this.renderHtml({ mainHtml, locale, headComponents });
|
|
287
413
|
return { html };
|
|
288
414
|
}
|
|
@@ -300,18 +426,28 @@ var Renderer = class {
|
|
|
300
426
|
return sitemap;
|
|
301
427
|
}
|
|
302
428
|
async renderHtml(options) {
|
|
303
|
-
const page = /* @__PURE__ */
|
|
304
|
-
lang: options.locale
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
429
|
+
const page = /* @__PURE__ */ jsxs2("html", {
|
|
430
|
+
lang: options.locale,
|
|
431
|
+
children: [
|
|
432
|
+
/* @__PURE__ */ jsxs2("head", {
|
|
433
|
+
children: [
|
|
434
|
+
/* @__PURE__ */ jsx2("meta", {
|
|
435
|
+
charSet: "utf-8"
|
|
436
|
+
}),
|
|
437
|
+
options.headComponents
|
|
438
|
+
]
|
|
439
|
+
}),
|
|
440
|
+
/* @__PURE__ */ jsx2("body", {
|
|
441
|
+
dangerouslySetInnerHTML: { __html: options.mainHtml }
|
|
442
|
+
})
|
|
443
|
+
]
|
|
444
|
+
});
|
|
313
445
|
const html = `<!doctype html>
|
|
314
|
-
${renderToString(
|
|
446
|
+
${renderToString(
|
|
447
|
+
page,
|
|
448
|
+
{},
|
|
449
|
+
{ pretty: true }
|
|
450
|
+
)}
|
|
315
451
|
`;
|
|
316
452
|
return html;
|
|
317
453
|
}
|
|
@@ -322,29 +458,45 @@ ${renderToString(page, {}, { pretty: true })}
|
|
|
322
458
|
};
|
|
323
459
|
}
|
|
324
460
|
async renderError(error) {
|
|
325
|
-
const mainHtml = renderToString(/* @__PURE__ */
|
|
461
|
+
const mainHtml = renderToString(/* @__PURE__ */ jsx2(ErrorPage, {
|
|
326
462
|
error
|
|
327
463
|
}));
|
|
328
464
|
const html = await this.renderHtml({ mainHtml, locale: "en" });
|
|
329
465
|
return { html };
|
|
330
466
|
}
|
|
467
|
+
async renderDevNotFound() {
|
|
468
|
+
const sitemap = await this.getSitemap();
|
|
469
|
+
const mainHtml = renderToString(/* @__PURE__ */ jsx2(DevNotFoundPage, {
|
|
470
|
+
sitemap
|
|
471
|
+
}));
|
|
472
|
+
const html = await this.renderHtml({
|
|
473
|
+
mainHtml,
|
|
474
|
+
locale: "en",
|
|
475
|
+
headComponents: [/* @__PURE__ */ jsx2("title", {
|
|
476
|
+
children: "404: Not Found"
|
|
477
|
+
})]
|
|
478
|
+
});
|
|
479
|
+
return { html };
|
|
480
|
+
}
|
|
331
481
|
async getScriptDeps(html, options) {
|
|
332
482
|
const assetMap = options.assetMap;
|
|
333
483
|
const deps = /* @__PURE__ */ new Set();
|
|
334
484
|
const re = /<(\w[\w-]+\w)/g;
|
|
335
485
|
const matches = Array.from(html.matchAll(re));
|
|
336
|
-
await Promise.all(
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
486
|
+
await Promise.all(
|
|
487
|
+
matches.map(async (match) => {
|
|
488
|
+
const tagName = match[1];
|
|
489
|
+
if (tagName && tagName.includes("-") && tagName in elementsMap) {
|
|
490
|
+
const modulePath = elementsMap[tagName];
|
|
491
|
+
const asset = await assetMap.get(modulePath);
|
|
492
|
+
if (!asset) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
const assetJsDeps = await asset.getJsDeps();
|
|
496
|
+
assetJsDeps.forEach((dep) => deps.add(dep));
|
|
343
497
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
}));
|
|
498
|
+
})
|
|
499
|
+
);
|
|
348
500
|
return Array.from(deps);
|
|
349
501
|
}
|
|
350
502
|
};
|
package/dist/render.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/render/render.tsx","../src/render/router.ts","../src/render/route-trie.ts"],"sourcesContent":["import path from 'node:path';\nimport {h, ComponentChildren} from 'preact';\nimport renderToString from 'preact-render-to-string';\nimport {getRoutes, RouteModule, Route, getAllPathsForRoute} from './router';\nimport {HEAD_CONTEXT} from '../core/components/head';\nimport {ErrorPage} from '../core/components/error-page';\nimport {getTranslations, I18N_CONTEXT} from '../core/i18n';\nimport {ScriptProps, SCRIPT_CONTEXT} from '../core/components/script';\nimport {AssetMap} from './asset-map/asset-map';\nimport {RootConfig} from '../core/config';\nimport {RouteTrie} from './route-trie';\n\n// TODO(stevenle): this should be added via config.\nconst ELEMENTS_MAP: Record<string, string> = {};\nconst ELEMENTS_MODULES = import.meta.glob([\n '/elements/**/*.ts',\n '/elements/**/*.tsx',\n]) as Record<string, () => Promise<RouteModule>>;\nObject.keys(ELEMENTS_MODULES).forEach((elementPath) => {\n const parts = path.parse(elementPath);\n ELEMENTS_MAP[parts.name] = elementPath;\n});\n\ninterface RenderOptions {\n assetMap: AssetMap;\n}\n\ninterface RenderHtmlOptions {\n mainHtml: string;\n locale: string;\n headComponents?: ComponentChildren[];\n}\n\nexport class Renderer {\n private routes: RouteTrie<Route>;\n\n constructor(config: RootConfig) {\n this.routes = getRoutes(config);\n }\n\n async render(\n url: string,\n options: RenderOptions\n ): Promise<{html: string; notFound?: boolean}> {\n const assetMap = options.assetMap;\n const [route, routeParams] = this.routes.get(url);\n if (route && route.module && route.module.default) {\n return await this.renderRoute(route, {routeParams, assetMap});\n }\n return this.render404();\n }\n\n async renderRoute(\n route: Route,\n options: {routeParams: Record<string, string>; assetMap: AssetMap}\n ): Promise<{html: string; notFound?: boolean}> {\n const routeParams = options.routeParams;\n const assetMap = options.assetMap;\n const Component = route.module.default;\n let props = {};\n if (route.module.getStaticProps) {\n const propsData = await route.module.getStaticProps({\n params: routeParams,\n });\n if (propsData.notFound) {\n return this.render404();\n }\n if (propsData.props) {\n props = propsData.props;\n }\n }\n\n const locale = route.locale;\n const translations = getTranslations(locale);\n\n const headComponents: ComponentChildren[] = [];\n const userScripts: ScriptProps[] = [];\n const vdom = (\n <I18N_CONTEXT.Provider value={{locale, translations}}>\n <SCRIPT_CONTEXT.Provider value={userScripts}>\n <HEAD_CONTEXT.Provider value={headComponents}>\n <Component {...props} />\n </HEAD_CONTEXT.Provider>\n </SCRIPT_CONTEXT.Provider>\n </I18N_CONTEXT.Provider>\n );\n const mainHtml = renderToString(vdom, {}, {pretty: true});\n\n // Walk the page's dependency tree for CSS dependencies that are added via\n // `import 'foo.scss'` or `import 'foo.module.scss'`.\n const pageAsset = await assetMap.get(route.modulePath);\n const cssDeps = await pageAsset?.getCssDeps();\n if (cssDeps) {\n cssDeps.forEach((cssUrl) => {\n headComponents.push(<link rel=\"stylesheet\" href={cssUrl} />);\n });\n }\n\n // Parse the HTML for custom elements that are found within the project\n // and automatically inject the script deps for them.\n const scriptDeps = await this.getScriptDeps(mainHtml, {assetMap});\n scriptDeps.forEach((jsUrls) => {\n headComponents.push(<script type=\"module\" src={jsUrls} />);\n });\n\n // Add user defined scripts added via the `<Script>` component.\n await Promise.all(\n userScripts.map(async (scriptDep) => {\n const scriptAsset = await assetMap.get(scriptDep.src);\n if (!scriptAsset && import.meta.env.PROD) {\n console.log(`could not find precompiled asset: ${scriptDep.src}`);\n }\n const scriptUrl = scriptAsset ? scriptAsset.assetUrl : scriptDep.src;\n headComponents.push(<script type=\"module\" src={scriptUrl} />);\n })\n );\n\n const html = await this.renderHtml({mainHtml, locale, headComponents});\n return {html};\n }\n\n async getSitemap(): Promise<\n Record<string, {route: Route; params: Record<string, string>}>\n > {\n const sitemap: Record<\n string,\n {route: Route; params: Record<string, string>}\n > = {};\n await this.routes.walk(async (urlPath: string, route: Route) => {\n const routePaths = await getAllPathsForRoute(urlPath, route);\n routePaths.forEach((routePath) => {\n sitemap[routePath.urlPath] = {\n route,\n params: routePath.params,\n };\n });\n });\n return sitemap;\n }\n\n private async renderHtml(options: RenderHtmlOptions) {\n const page = (\n <html lang={options.locale}>\n <head>\n <meta charSet=\"utf-8\" />\n <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1.0\"\n />\n {options.headComponents}\n </head>\n <body dangerouslySetInnerHTML={{__html: options.mainHtml}} />\n </html>\n );\n const html = `<!doctype html>\\n${renderToString(\n page,\n {},\n {pretty: true}\n )}\\n`;\n return html;\n }\n\n async render404() {\n return {\n html: '<!doctype html><html><title>404 Not Found</title><h1>404 Not Found</h1>',\n notFound: true,\n };\n }\n\n async renderError(error: unknown) {\n const mainHtml = renderToString(<ErrorPage error={error} />);\n const html = await this.renderHtml({mainHtml, locale: 'en'});\n return {html};\n }\n\n private async getScriptDeps(\n html: string,\n options: {assetMap: AssetMap}\n ): Promise<string[]> {\n const assetMap = options.assetMap as AssetMap;\n const deps = new Set<string>();\n\n const re = /<(\\w[\\w-]+\\w)/g;\n const matches = Array.from(html.matchAll(re));\n await Promise.all(\n matches.map(async (match) => {\n const tagName = match[1];\n // Custom elements require a dash.\n if (tagName && tagName.includes('-') && tagName in ELEMENTS_MAP) {\n const modulePath = ELEMENTS_MAP[tagName];\n const asset = await assetMap.get(modulePath);\n if (!asset) {\n return;\n }\n const assetJsDeps = await asset.getJsDeps();\n assetJsDeps.forEach((dep) => deps.add(dep));\n }\n })\n );\n\n return Array.from(deps);\n }\n}\n","import path from 'node:path';\nimport {RootConfig} from '../core/config';\nimport {GetStaticPaths, GetStaticProps} from '../core/types';\nimport {RouteTrie} from './route-trie';\n\nexport interface RouteModule {\n default: any;\n getStaticPaths?: GetStaticPaths;\n getStaticProps?: GetStaticProps;\n}\n\nexport interface Route {\n modulePath: string;\n module: RouteModule;\n locale: string;\n}\n\nexport function getRoutes(config: RootConfig) {\n const locales = config.i18n?.locales || [];\n const i18nUrlFormat = config.i18n?.urlFormat || '/{locale}/{path}';\n const defaultLocale = config.i18n?.defaultLocale || 'en';\n\n const routes = import.meta.glob(\n ['/routes/*.ts', '/routes/**/*.ts', '/routes/*.tsx', '/routes/**/*.tsx'],\n {\n eager: true,\n }\n );\n const trie = new RouteTrie<Route>();\n Object.keys(routes).forEach((filePath) => {\n let routePath = filePath.replace(/^\\/routes/, '');\n const parts = path.parse(routePath);\n if (parts.name.startsWith('_')) {\n return;\n }\n if (parts.name === 'index') {\n routePath = parts.dir;\n } else {\n routePath = path.join(parts.dir, parts.name);\n }\n trie.add(routePath, {\n modulePath: filePath,\n module: routes[filePath] as RouteModule,\n locale: defaultLocale,\n });\n\n // At the moment, all routes are assumed to use the site-wide i18n config.\n // TODO(stevenle): provide routes with a way to override the default\n // i18n serving behavior.\n locales.forEach((locale) => {\n const localeRoutePath = i18nUrlFormat\n .replace('{locale}', locale)\n .replace('{path}', routePath.replace(/^\\/*/, ''));\n if (localeRoutePath !== routePath) {\n trie.add(localeRoutePath, {\n modulePath: filePath,\n module: routes[filePath] as RouteModule,\n locale: locale,\n });\n }\n });\n });\n return trie;\n}\n\nexport async function getAllPathsForRoute(\n urlPathFormat: string,\n route: Route\n): Promise<Array<{urlPath: string; params: Record<string, string>}>> {\n const urlPaths: Array<{urlPath: string; params: Record<string, string>}> = [];\n const routeModule = route.module;\n if (routeModule.getStaticPaths) {\n const staticPaths = await routeModule.getStaticPaths();\n staticPaths.paths.forEach(\n (pathParams: {params: Record<string, string>}) => {\n urlPaths.push({\n urlPath: replaceParams(urlPathFormat, pathParams.params),\n params: pathParams.params || {},\n });\n }\n );\n } else {\n urlPaths.push({urlPath: urlPathFormat, params: {}});\n }\n return urlPaths;\n}\n\nexport function replaceParams(\n urlPathFormat: string,\n params: Record<string, string>\n) {\n const urlPath = urlPathFormat.replaceAll(\n /\\[(\\.\\.\\.)?([\\w\\-_]*)\\]/g,\n (match: string, _wildcard: string, key: string) => {\n const val = params[key];\n if (!val) {\n throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);\n }\n return val;\n }\n );\n return urlPath;\n}\n","/**\n * A trie data structure that stores routes. The trie supports `:param` and\n * `*wildcard` values.\n */\nexport class RouteTrie<T> {\n private children: Record<string, RouteTrie<T>> = {};\n private paramChild?: ParamChild<T>;\n private wildcardChild?: WildcardChild<T>;\n private route?: T;\n\n /**\n * Adds a route to the trie.\n */\n add(path: string, route: T) {\n path = this.normalizePath(path);\n\n // If the end was reached, save the value to the node.\n if (path === '') {\n this.route = route;\n return;\n }\n\n const [head, tail] = this.splitPath(path);\n if (head.startsWith('[...') && head.endsWith(']')) {\n const paramName = head.slice(4, -1);\n this.wildcardChild = new WildcardChild(paramName, route);\n return;\n }\n\n let nextNode: RouteTrie<T>;\n if (head.startsWith('[') && head.endsWith(']')) {\n if (!this.paramChild) {\n const paramName = head.slice(1, -1);\n this.paramChild = new ParamChild(paramName);\n }\n nextNode = this.paramChild.trie;\n } else {\n nextNode = this.children[head];\n if (!nextNode) {\n nextNode = new RouteTrie();\n this.children[head] = nextNode;\n }\n }\n nextNode.add(tail, route);\n }\n\n /**\n * Returns a route mapped to the given path and any parameter values from the\n * URL.\n */\n get(path: string): [T | undefined, Record<string, string>] {\n const params = {};\n const route = this.getRoute(path, params);\n return [route, params];\n }\n\n /**\n * Walks the route trie and calls a callback function for each route.\n */\n walk(cb: (urlPath: string, route: T) => Promise<any> | void): Promise<any> {\n const promises: Array<Promise<any>> = [];\n const addPromise = (promise: Promise<any> | void) => {\n if (promise) {\n promises.push(promise);\n }\n };\n if (this.route) {\n addPromise(cb('/', this.route));\n }\n if (this.paramChild) {\n const param = `[${this.paramChild.name}]`;\n this.paramChild.trie.walk((childPath: string, route: T) => {\n const paramUrlPath = `/${param}${childPath}`;\n addPromise(cb(paramUrlPath, route));\n });\n }\n if (this.wildcardChild) {\n const wildcardUrlPath = `/[...${this.wildcardChild.name}]`;\n addPromise(cb(wildcardUrlPath, this.wildcardChild.route));\n }\n for (const subpath of Object.keys(this.children)) {\n const childTrie = this.children[subpath];\n childTrie.walk((childPath: string, childRoute: T) => {\n addPromise(cb(`/${subpath}${childPath}`, childRoute));\n });\n }\n return Promise.all(promises);\n }\n\n /**\n * Removes all routes from the trie.\n */\n clear() {\n this.children = {};\n this.paramChild = undefined;\n this.wildcardChild = undefined;\n this.route = undefined;\n }\n\n private getRoute(\n urlPath: string,\n params: Record<string, string>\n ): T | undefined {\n urlPath = this.normalizePath(urlPath);\n if (urlPath === '') {\n return this.route;\n }\n\n const [head, tail] = this.splitPath(urlPath);\n\n const child = this.children[head];\n if (child) {\n const route = child.getRoute(tail, params);\n if (route) {\n return route;\n }\n }\n\n if (this.paramChild) {\n const route = this.paramChild.trie.getRoute(tail, params);\n if (route) {\n params[this.paramChild.name] = head;\n return route;\n }\n }\n\n if (this.wildcardChild) {\n params[this.wildcardChild.name] = urlPath;\n return this.wildcardChild.route;\n }\n\n return undefined;\n }\n\n /**\n * Normalizes a path for inclusion into the route trie.\n */\n private normalizePath(path: string) {\n // Remove leading slashes.\n return path.replace(/^\\/+/g, '');\n }\n\n /**\n * Splits the parent directory from its children, e.g.:\n *\n * splitPath(\"foo/bar/baz\") -> [\"foo\", \"bar/baz\"]\n */\n private splitPath(path: string): [string, string] {\n const i = path.indexOf('/');\n if (i === -1) {\n return [path, ''];\n }\n return [path.slice(0, i), path.slice(i + 1)];\n }\n}\n\n/**\n * A node in the RouteTrie for a :param child.\n */\nclass ParamChild<T> {\n readonly name: string;\n readonly trie: RouteTrie<T> = new RouteTrie();\n\n constructor(name: string) {\n this.name = name;\n }\n}\n\n/**\n * A node in the RouteTrie for a *wildcard child.\n */\nclass WildcardChild<T> {\n readonly name: string;\n readonly route: T;\n\n constructor(name: string, route: T) {\n this.name = name;\n this.route = route;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/render/render.tsx","../src/render/router.ts","../src/render/route-trie.ts","../src/core/components/dev-not-found-page.tsx"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {ComponentChildren} from 'preact';\nimport renderToString from 'preact-render-to-string';\nimport {getRoutes, Route, getAllPathsForRoute} from './router';\nimport {HEAD_CONTEXT} from '../core/components/head';\nimport {ErrorPage} from '../core/components/error-page';\nimport {getTranslations, I18N_CONTEXT} from '../core/i18n';\nimport {ScriptProps, SCRIPT_CONTEXT} from '../core/components/script';\nimport {AssetMap} from './asset-map/asset-map';\nimport {RootConfig} from '../core/config';\nimport {RouteTrie} from './route-trie';\nimport {elementsMap} from 'virtual:root-elements';\nimport {DevNotFoundPage} from '../core/components/dev-not-found-page';\n\ninterface RenderOptions {\n assetMap: AssetMap;\n}\n\ninterface RenderHtmlOptions {\n mainHtml: string;\n locale: string;\n headComponents?: ComponentChildren[];\n}\n\nexport class Renderer {\n private routes: RouteTrie<Route>;\n\n constructor(config: RootConfig) {\n this.routes = getRoutes(config);\n }\n\n async render(\n url: string,\n options: RenderOptions\n ): Promise<{html?: string; notFound?: boolean}> {\n const assetMap = options.assetMap;\n const [route, routeParams] = this.routes.get(url);\n if (route && route.module && route.module.default) {\n return await this.renderRoute(route, {routeParams, assetMap});\n }\n return {notFound: true};\n }\n\n async renderRoute(\n route: Route,\n options: {routeParams: Record<string, string>; assetMap: AssetMap}\n ): Promise<{html?: string; notFound?: boolean}> {\n const routeParams = options.routeParams;\n const assetMap = options.assetMap;\n const Component = route.module.default;\n if (!Component) {\n throw new Error(\n 'unable to render route. the route should have a default export that renders a jsx component.'\n );\n }\n let props = {};\n if (route.module.getStaticProps) {\n const propsData = await route.module.getStaticProps({\n params: routeParams,\n });\n if (propsData.notFound) {\n return this.render404();\n }\n if (propsData.props) {\n props = propsData.props;\n }\n }\n\n const locale = route.locale;\n const translations = getTranslations(locale);\n\n const headComponents: ComponentChildren[] = [];\n const userScripts: ScriptProps[] = [];\n const vdom = (\n <I18N_CONTEXT.Provider value={{locale, translations}}>\n <SCRIPT_CONTEXT.Provider value={userScripts}>\n <HEAD_CONTEXT.Provider value={headComponents}>\n <Component {...props} />\n </HEAD_CONTEXT.Provider>\n </SCRIPT_CONTEXT.Provider>\n </I18N_CONTEXT.Provider>\n );\n const mainHtml = renderToString(vdom, {}, {pretty: true});\n\n // Walk the page's dependency tree for CSS dependencies that are added via\n // `import 'foo.scss'` or `import 'foo.module.scss'`.\n const pageAsset = await assetMap.get(route.modulePath);\n const cssDeps = await pageAsset?.getCssDeps();\n if (cssDeps) {\n cssDeps.forEach((cssUrl) => {\n headComponents.push(<link rel=\"stylesheet\" href={cssUrl} />);\n });\n }\n\n // Parse the HTML for custom elements that are found within the project\n // and automatically inject the script deps for them.\n const scriptDeps = await this.getScriptDeps(mainHtml, {assetMap});\n scriptDeps.forEach((jsUrls) => {\n headComponents.push(<script type=\"module\" src={jsUrls} />);\n });\n\n // Add user defined scripts added via the `<Script>` component.\n await Promise.all(\n userScripts.map(async (scriptDep) => {\n const scriptAsset = await assetMap.get(scriptDep.src);\n if (scriptAsset) {\n const scriptUrl = scriptAsset ? scriptAsset.assetUrl : scriptDep.src;\n headComponents.push(<script type=\"module\" src={scriptUrl} />);\n }\n })\n );\n\n const html = await this.renderHtml({mainHtml, locale, headComponents});\n return {html};\n }\n\n async getSitemap(): Promise<\n Record<string, {route: Route; params: Record<string, string>}>\n > {\n const sitemap: Record<\n string,\n {route: Route; params: Record<string, string>}\n > = {};\n await this.routes.walk(async (urlPath: string, route: Route) => {\n const routePaths = await getAllPathsForRoute(urlPath, route);\n routePaths.forEach((routePath) => {\n sitemap[routePath.urlPath] = {\n route,\n params: routePath.params,\n };\n });\n });\n return sitemap;\n }\n\n private async renderHtml(options: RenderHtmlOptions) {\n const page = (\n <html lang={options.locale}>\n <head>\n <meta charSet=\"utf-8\" />\n {options.headComponents}\n </head>\n <body dangerouslySetInnerHTML={{__html: options.mainHtml}} />\n </html>\n );\n const html = `<!doctype html>\\n${renderToString(\n page,\n {},\n {pretty: true}\n )}\\n`;\n return html;\n }\n\n async render404() {\n return {\n html: '<!doctype html><html><title>404 Not Found</title><h1>404 Not Found</h1>',\n notFound: true,\n };\n }\n\n async renderError(error: unknown) {\n const mainHtml = renderToString(<ErrorPage error={error} />);\n const html = await this.renderHtml({mainHtml, locale: 'en'});\n return {html};\n }\n\n async renderDevNotFound() {\n const sitemap = await this.getSitemap();\n const mainHtml = renderToString(<DevNotFoundPage sitemap={sitemap} />);\n const html = await this.renderHtml({\n mainHtml,\n locale: 'en',\n headComponents: [<title>404: Not Found</title>],\n });\n return {html};\n }\n\n private async getScriptDeps(\n html: string,\n options: {assetMap: AssetMap}\n ): Promise<string[]> {\n const assetMap = options.assetMap as AssetMap;\n const deps = new Set<string>();\n\n const re = /<(\\w[\\w-]+\\w)/g;\n const matches = Array.from(html.matchAll(re));\n await Promise.all(\n matches.map(async (match) => {\n const tagName = match[1];\n // Custom elements require a dash.\n if (tagName && tagName.includes('-') && tagName in elementsMap) {\n const modulePath = elementsMap[tagName];\n const asset = await assetMap.get(modulePath);\n if (!asset) {\n return;\n }\n const assetJsDeps = await asset.getJsDeps();\n assetJsDeps.forEach((dep) => deps.add(dep));\n }\n })\n );\n\n return Array.from(deps);\n }\n}\n","import path from 'node:path';\nimport {ComponentType} from 'preact';\nimport {RootConfig} from '../core/config';\nimport {GetStaticPaths, GetStaticProps} from '../core/types';\nimport {RouteTrie} from './route-trie';\n\nexport interface RouteModule {\n default?: ComponentType<unknown>;\n getStaticPaths?: GetStaticPaths;\n getStaticProps?: GetStaticProps;\n}\n\nexport interface Route {\n modulePath: string;\n module: RouteModule;\n locale: string;\n}\n\nexport function getRoutes(config: RootConfig) {\n const locales = config.i18n?.locales || [];\n const i18nUrlFormat = config.i18n?.urlFormat || '/{locale}/{path}';\n const defaultLocale = config.i18n?.defaultLocale || 'en';\n\n const routes = import.meta.glob(\n ['/routes/*.ts', '/routes/**/*.ts', '/routes/*.tsx', '/routes/**/*.tsx'],\n {\n eager: true,\n }\n );\n const trie = new RouteTrie<Route>();\n Object.keys(routes).forEach((filePath) => {\n let routePath = filePath.replace(/^\\/routes/, '');\n const parts = path.parse(routePath);\n if (parts.name.startsWith('_')) {\n return;\n }\n if (parts.name === 'index') {\n routePath = parts.dir;\n } else {\n routePath = path.join(parts.dir, parts.name);\n }\n trie.add(routePath, {\n modulePath: filePath,\n module: routes[filePath] as RouteModule,\n locale: defaultLocale,\n });\n\n // At the moment, all routes are assumed to use the site-wide i18n config.\n // TODO(stevenle): provide routes with a way to override the default\n // i18n serving behavior.\n locales.forEach((locale) => {\n const localeRoutePath = i18nUrlFormat\n .replace('{locale}', locale)\n .replace('{path}', routePath.replace(/^\\/*/, ''));\n if (localeRoutePath !== routePath) {\n trie.add(localeRoutePath, {\n modulePath: filePath,\n module: routes[filePath] as RouteModule,\n locale: locale,\n });\n }\n });\n });\n return trie;\n}\n\nexport async function getAllPathsForRoute(\n urlPathFormat: string,\n route: Route\n): Promise<Array<{urlPath: string; params: Record<string, string>}>> {\n const urlPaths: Array<{urlPath: string; params: Record<string, string>}> = [];\n const routeModule = route.module;\n if (routeModule.getStaticPaths) {\n const staticPaths = await routeModule.getStaticPaths();\n if (staticPaths.paths) {\n staticPaths.paths.forEach(\n (pathParams: {params: Record<string, string>}) => {\n const urlPath = replaceParams(urlPathFormat, pathParams.params || {});\n if (pathContainsPlaceholders(urlPath)) {\n console.warn(\n `path contains placeholders: ${urlPathFormat}, double check getStaticPaths() and ensure all params are returned`\n );\n } else {\n urlPaths.push({\n urlPath: replaceParams(urlPathFormat, pathParams.params),\n params: pathParams.params || {},\n });\n }\n }\n );\n }\n } else if (pathContainsPlaceholders(urlPathFormat)) {\n console.warn(\n `path contains placeholders: ${urlPathFormat}, did you forget to define getStaticPaths()?`\n );\n } else {\n urlPaths.push({urlPath: urlPathFormat, params: {}});\n }\n return urlPaths;\n}\n\nexport function replaceParams(\n urlPathFormat: string,\n params: Record<string, string>\n) {\n const urlPath = urlPathFormat.replaceAll(\n /\\[(\\.\\.\\.)?([\\w\\-_]*)\\]/g,\n (match: string, _wildcard: string, key: string) => {\n const val = params[key];\n if (!val) {\n throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);\n }\n return val;\n }\n );\n return urlPath;\n}\n\nfunction pathContainsPlaceholders(urlPath: string) {\n const segments = urlPath.split('/');\n return segments.some((segment) => {\n return segment.startsWith('[') && segment.endsWith(']');\n });\n}\n","/**\n * A trie data structure that stores routes. The trie supports `:param` and\n * `*wildcard` values.\n */\nexport class RouteTrie<T> {\n private children: Record<string, RouteTrie<T>> = {};\n private paramChild?: ParamChild<T>;\n private wildcardChild?: WildcardChild<T>;\n private route?: T;\n\n /**\n * Adds a route to the trie.\n */\n add(path: string, route: T) {\n path = this.normalizePath(path);\n\n // If the end was reached, save the value to the node.\n if (path === '') {\n this.route = route;\n return;\n }\n\n const [head, tail] = this.splitPath(path);\n if (head.startsWith('[...') && head.endsWith(']')) {\n const paramName = head.slice(4, -1);\n this.wildcardChild = new WildcardChild(paramName, route);\n return;\n }\n\n let nextNode: RouteTrie<T>;\n if (head.startsWith('[') && head.endsWith(']')) {\n if (!this.paramChild) {\n const paramName = head.slice(1, -1);\n this.paramChild = new ParamChild(paramName);\n }\n nextNode = this.paramChild.trie;\n } else {\n nextNode = this.children[head];\n if (!nextNode) {\n nextNode = new RouteTrie();\n this.children[head] = nextNode;\n }\n }\n nextNode.add(tail, route);\n }\n\n /**\n * Returns a route mapped to the given path and any parameter values from the\n * URL.\n */\n get(path: string): [T | undefined, Record<string, string>] {\n const params = {};\n const route = this.getRoute(path, params);\n return [route, params];\n }\n\n /**\n * Walks the route trie and calls a callback function for each route.\n */\n walk(cb: (urlPath: string, route: T) => Promise<void> | void): Promise<void> {\n const promises: Array<Promise<void>> = [];\n const addPromise = (promise: Promise<void> | void) => {\n if (promise) {\n promises.push(promise);\n }\n };\n if (this.route) {\n addPromise(cb('/', this.route));\n }\n if (this.paramChild) {\n const param = `[${this.paramChild.name}]`;\n this.paramChild.trie.walk((childPath: string, route: T) => {\n const paramUrlPath = `/${param}${childPath}`;\n addPromise(cb(paramUrlPath, route));\n });\n }\n if (this.wildcardChild) {\n const wildcardUrlPath = `/[...${this.wildcardChild.name}]`;\n addPromise(cb(wildcardUrlPath, this.wildcardChild.route));\n }\n for (const subpath of Object.keys(this.children)) {\n const childTrie = this.children[subpath];\n childTrie.walk((childPath: string, childRoute: T) => {\n addPromise(cb(`/${subpath}${childPath}`, childRoute));\n });\n }\n return Promise.all(promises).then(() => {});\n }\n\n /**\n * Removes all routes from the trie.\n */\n clear() {\n this.children = {};\n this.paramChild = undefined;\n this.wildcardChild = undefined;\n this.route = undefined;\n }\n\n private getRoute(\n urlPath: string,\n params: Record<string, string>\n ): T | undefined {\n urlPath = this.normalizePath(urlPath);\n if (urlPath === '') {\n return this.route;\n }\n\n const [head, tail] = this.splitPath(urlPath);\n\n const child = this.children[head];\n if (child) {\n const route = child.getRoute(tail, params);\n if (route) {\n return route;\n }\n }\n\n if (this.paramChild) {\n const route = this.paramChild.trie.getRoute(tail, params);\n if (route) {\n params[this.paramChild.name] = head;\n return route;\n }\n }\n\n if (this.wildcardChild) {\n params[this.wildcardChild.name] = urlPath;\n return this.wildcardChild.route;\n }\n\n return undefined;\n }\n\n /**\n * Normalizes a path for inclusion into the route trie.\n */\n private normalizePath(path: string) {\n // Remove leading slashes.\n return path.replace(/^\\/+/g, '');\n }\n\n /**\n * Splits the parent directory from its children, e.g.:\n *\n * splitPath(\"foo/bar/baz\") -> [\"foo\", \"bar/baz\"]\n */\n private splitPath(path: string): [string, string] {\n const i = path.indexOf('/');\n if (i === -1) {\n return [path, ''];\n }\n return [path.slice(0, i), path.slice(i + 1)];\n }\n}\n\n/**\n * A node in the RouteTrie for a :param child.\n */\nclass ParamChild<T> {\n readonly name: string;\n readonly trie: RouteTrie<T> = new RouteTrie();\n\n constructor(name: string) {\n this.name = name;\n }\n}\n\n/**\n * A node in the RouteTrie for a *wildcard child.\n */\nclass WildcardChild<T> {\n readonly name: string;\n readonly route: T;\n\n constructor(name: string, route: T) {\n this.name = name;\n this.route = route;\n }\n}\n","import {Route} from '../../render/router';\n\nconst STYLES = `\nbody {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n}\n\nh1 {\n margin-bottom: 40px;\n}\n\n.route-list {\n display: grid;\n grid-template-columns: auto 1fr;\n align-items: center;\n column-gap: 24px;\n row-gap: 8px;\n padding: 0 40px;\n}\n\n.route-module {\n text-align: right;\n}\n\nhr {\n margin: 60px 0;\n}\n`;\n\ninterface DevNotFoundPageProps {\n sitemap: Record<string, {route: Route; params: Record<string, string>}>;\n}\n\nexport function DevNotFoundPage(props: DevNotFoundPageProps) {\n const routesList: Array<Route & {urlPath: string}> = [];\n Object.keys(props.sitemap).forEach((urlPath) => {\n const route = props.sitemap[urlPath].route;\n routesList.push(Object.assign({}, route, {urlPath}));\n });\n return (\n <>\n <style dangerouslySetInnerHTML={{__html: STYLES}}></style>\n <div>\n <h1>\n <strong>404:</strong> Not Found\n </h1>\n {routesList.length > 0 ? (\n <>\n <h2>Routes found in the project:</h2>\n <div class=\"route-list\">\n {routesList.map((route) => (\n <>\n <div class=\"route-module\">{route.modulePath}</div>\n <a class=\"route-url\" href={route.urlPath}>\n {route.urlPath}\n </a>\n </>\n ))}\n </div>\n </>\n ) : (\n <>\n <h2>No routes found in the project</h2>\n <p>\n Add your first route at <code>/routes/index.tsx</code>\n </p>\n </>\n )}\n <hr />\n <p>\n Note: This page could use some love! If you're interested in helping\n to style this page, please reach out to the root.js developers!\n </p>\n </div>\n </>\n );\n}\n"],"mappings":"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","names":["path","jsx","jsxs"]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blinkk/root",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.11",
|
|
4
4
|
"author": "s@blinkk.com",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=16.0.0"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/*",
|
|
11
|
+
"dist/**/*"
|
|
12
|
+
],
|
|
6
13
|
"bin": {
|
|
7
14
|
"root": "./bin/root.js"
|
|
8
15
|
},
|
|
@@ -11,28 +18,14 @@
|
|
|
11
18
|
"types": "./dist/core.d.ts",
|
|
12
19
|
"exports": {
|
|
13
20
|
".": {
|
|
14
|
-
"
|
|
15
|
-
"import": "./dist/core.js"
|
|
16
|
-
"types": "./dist/core.d.ts"
|
|
17
|
-
},
|
|
18
|
-
"./cli": {
|
|
19
|
-
"default": "./dist/cli.js",
|
|
20
|
-
"import": "./dist/cli.js",
|
|
21
|
-
"types": "./dist/cli.d.ts"
|
|
21
|
+
"types": "./dist/core.d.ts",
|
|
22
|
+
"import": "./dist/core.js"
|
|
22
23
|
},
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"import": "./dist
|
|
26
|
-
"types": "./dist/render.d.ts"
|
|
24
|
+
"./*": {
|
|
25
|
+
"types": "./dist/*.d.ts",
|
|
26
|
+
"import": "./dist/*.js"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
|
-
"files": [
|
|
30
|
-
"bin/*",
|
|
31
|
-
"dist/**/*"
|
|
32
|
-
],
|
|
33
|
-
"engines": {
|
|
34
|
-
"node": ">=16.0.0"
|
|
35
|
-
},
|
|
36
29
|
"dependencies": {
|
|
37
30
|
"bundle-require": "^3.1.0",
|
|
38
31
|
"commander": "^9.4.0",
|
|
@@ -41,6 +34,7 @@
|
|
|
41
34
|
"fs-extra": "^10.1.0",
|
|
42
35
|
"html-minifier-terser": "^7.0.0",
|
|
43
36
|
"joycon": "^3.1.1",
|
|
37
|
+
"kleur": "^4.1.5",
|
|
44
38
|
"sass": "^1.49.9",
|
|
45
39
|
"tiny-glob": "^0.2.9",
|
|
46
40
|
"vite": "^3.1.0"
|
|
@@ -54,17 +48,20 @@
|
|
|
54
48
|
"@types/fs-extra": "^9.0.13",
|
|
55
49
|
"@types/html-minifier-terser": "^7.0.0",
|
|
56
50
|
"@types/node": "^18.7.14",
|
|
51
|
+
"@types/preact-custom-element": "^4.0.1",
|
|
57
52
|
"nodemon": "^2.0.19",
|
|
58
53
|
"preact": "^10.10.6",
|
|
54
|
+
"preact-custom-element": "^4.2.1",
|
|
59
55
|
"preact-render-to-string": "^5.2.3",
|
|
60
56
|
"rollup": "^2.79.0",
|
|
61
|
-
"tsup": "^
|
|
57
|
+
"tsup": "^6.3.0",
|
|
62
58
|
"typescript": "^4.7.4",
|
|
63
59
|
"vitest": "^0.18.1"
|
|
64
60
|
},
|
|
65
61
|
"scripts": {
|
|
66
62
|
"build": "rm -rf dist && tsup-node",
|
|
67
63
|
"dev": "nodemon --watch src -e ts,tsx --exec pnpm build",
|
|
68
|
-
"test": "pnpm build && vitest"
|
|
64
|
+
"test": "pnpm build && vitest run",
|
|
65
|
+
"test:watch": "pnpm build && vitest"
|
|
69
66
|
}
|
|
70
67
|
}
|