@webtypen/webframez-react 0.0.2 → 0.0.4

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/dist/http.js CHANGED
@@ -198,6 +198,10 @@ function readSearchParams(urlSearchParams) {
198
198
  function escapeHtml(value) {
199
199
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
200
200
  }
201
+ var MANAGED_HEAD_ATTR = "data-webframez-head";
202
+ function createManagedAttributes() {
203
+ return `${MANAGED_HEAD_ATTR}="true"`;
204
+ }
201
205
  function toRouteEntry(pagesDir, filePath) {
202
206
  const normalized = filePath.replace(/\\/g, "/");
203
207
  if (!normalized.endsWith("/index.js")) {
@@ -266,19 +270,21 @@ function renderHeadToString(head) {
266
270
  const tags = [];
267
271
  if (head.description) {
268
272
  tags.push(
269
- `<meta name="description" content="${escapeHtml(head.description)}" />`
273
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
270
274
  );
271
275
  }
272
276
  if (head.favicon) {
273
- tags.push(`<link rel="icon" href="${escapeHtml(head.favicon)}" />`);
277
+ tags.push(
278
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
279
+ );
274
280
  }
275
281
  for (const meta of head.meta ?? []) {
276
282
  const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
277
- tags.push(`<meta ${attrs} />`);
283
+ tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
278
284
  }
279
285
  for (const link of head.links ?? []) {
280
286
  const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
281
- tags.push(`<link ${attrs} />`);
287
+ tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
282
288
  }
283
289
  return tags.join("\n");
284
290
  }
@@ -292,6 +298,12 @@ async function resolveHead(candidate, context) {
292
298
  }
293
299
  return candidate.Head(context);
294
300
  }
301
+ async function resolvePageData(candidate, context) {
302
+ if (!candidate.Data) {
303
+ return void 0;
304
+ }
305
+ return candidate.Data(context);
306
+ }
295
307
  function findBestMatch(entries, pathname) {
296
308
  const matches = [];
297
309
  for (const entry of entries) {
@@ -371,10 +383,11 @@ function createFileRouter(options) {
371
383
  };
372
384
  }
373
385
  const errorModule = resolveModule(errorPath);
374
- const errorNode = errorModule.default(errorProps);
386
+ const errorNode = await errorModule.default(errorProps);
375
387
  const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
376
388
  const errorHead = await resolveHead(errorModule, errorProps);
377
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), errorNode) : errorNode;
389
+ const layoutNode = layoutModule ? await layoutModule.default(context) : null;
390
+ const model = layoutNode ? injectRouteChildren(layoutNode, errorNode) : errorNode;
378
391
  return {
379
392
  statusCode,
380
393
  model,
@@ -406,10 +419,17 @@ function createFileRouter(options) {
406
419
  activeContext = context;
407
420
  const pageModule = resolveModule(match.entry.filePath);
408
421
  const layoutModule = fs.existsSync(layoutPath) ? resolveModule(layoutPath) : null;
409
- const pageNode = pageModule.default(context);
410
- const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
411
- const pageHead = await resolveHead(pageModule, context);
412
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), pageNode) : pageNode;
422
+ const pageData = await resolvePageData(pageModule, context);
423
+ const pageContext = {
424
+ ...context,
425
+ data: pageData
426
+ };
427
+ activeContext = pageContext;
428
+ const pageNode = await pageModule.default(pageContext);
429
+ const layoutHead = layoutModule ? await resolveHead(layoutModule, pageContext) : void 0;
430
+ const pageHead = await resolveHead(pageModule, pageContext);
431
+ const layoutNode = layoutModule ? await layoutModule.default(pageContext) : null;
432
+ const model = layoutNode ? injectRouteChildren(layoutNode, pageNode) : pageNode;
413
433
  return {
414
434
  statusCode: 200,
415
435
  model,
@@ -454,14 +474,26 @@ function stripBasePath(pathname, basePath) {
454
474
  }
455
475
  function runNodeCommand(args) {
456
476
  return new Promise((resolve, reject) => {
457
- execFile(process.execPath, args, { timeout: 1e4, maxBuffer: 1024 * 1024 * 5 }, (error, stdout, stderr) => {
458
- if (error) {
459
- const out = stderr && stderr.trim() !== "" ? stderr : stdout;
460
- reject(new Error(out || error.message));
461
- return;
477
+ const execArgs = [
478
+ "--conditions",
479
+ "react-server",
480
+ "-r",
481
+ "@webtypen/webframez-react/register",
482
+ ...args
483
+ ];
484
+ execFile(
485
+ process.execPath,
486
+ execArgs,
487
+ { timeout: 1e4, maxBuffer: 1024 * 1024 * 5 },
488
+ (error, stdout, stderr) => {
489
+ if (error) {
490
+ const out = stderr && stderr.trim() !== "" ? stderr : stdout;
491
+ reject(new Error(out || error.message));
492
+ return;
493
+ }
494
+ resolve({ stdout, stderr });
462
495
  }
463
- resolve({ stdout, stderr });
464
- });
496
+ );
465
497
  });
466
498
  }
467
499
  async function renderInitialHtmlInWorker(options) {
@@ -485,7 +517,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
485
517
  }
486
518
  return originalResolveFilename.call(this, request, parent, isMain, options);
487
519
  };
488
- const { createFileRouter } = require("webframez-react/router");
520
+ const { createFileRouter } = require("@webtypen/webframez-react/router");
489
521
  const reactDomPkg = require.resolve("react-dom/package.json", {
490
522
  paths: [process.cwd(), input.pagesDir]
491
523
  });
@@ -624,7 +656,11 @@ function createNodeRequestHandler(options) {
624
656
  cookies: requestCookies
625
657
  })
626
658
  );
627
- sendRSC(res, resolved2.model, {
659
+ const payload = {
660
+ model: resolved2.model,
661
+ head: resolved2.head
662
+ };
663
+ sendRSC(res, payload, {
628
664
  moduleMap,
629
665
  statusCode: resolved2.statusCode
630
666
  });
package/dist/index.cjs CHANGED
@@ -257,6 +257,10 @@ function readSearchParams(urlSearchParams) {
257
257
  function escapeHtml(value) {
258
258
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
259
259
  }
260
+ var MANAGED_HEAD_ATTR = "data-webframez-head";
261
+ function createManagedAttributes() {
262
+ return `${MANAGED_HEAD_ATTR}="true"`;
263
+ }
260
264
  function toRouteEntry(pagesDir, filePath) {
261
265
  const normalized = filePath.replace(/\\/g, "/");
262
266
  if (!normalized.endsWith("/index.js")) {
@@ -325,19 +329,21 @@ function renderHeadToString(head) {
325
329
  const tags = [];
326
330
  if (head.description) {
327
331
  tags.push(
328
- `<meta name="description" content="${escapeHtml(head.description)}" />`
332
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
329
333
  );
330
334
  }
331
335
  if (head.favicon) {
332
- tags.push(`<link rel="icon" href="${escapeHtml(head.favicon)}" />`);
336
+ tags.push(
337
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
338
+ );
333
339
  }
334
340
  for (const meta of head.meta ?? []) {
335
341
  const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
336
- tags.push(`<meta ${attrs} />`);
342
+ tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
337
343
  }
338
344
  for (const link of head.links ?? []) {
339
345
  const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
340
- tags.push(`<link ${attrs} />`);
346
+ tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
341
347
  }
342
348
  return tags.join("\n");
343
349
  }
@@ -351,6 +357,12 @@ async function resolveHead(candidate, context) {
351
357
  }
352
358
  return candidate.Head(context);
353
359
  }
360
+ async function resolvePageData(candidate, context) {
361
+ if (!candidate.Data) {
362
+ return void 0;
363
+ }
364
+ return candidate.Data(context);
365
+ }
354
366
  function findBestMatch(entries, pathname) {
355
367
  const matches = [];
356
368
  for (const entry of entries) {
@@ -430,10 +442,11 @@ function createFileRouter(options) {
430
442
  };
431
443
  }
432
444
  const errorModule = resolveModule(errorPath);
433
- const errorNode = errorModule.default(errorProps);
445
+ const errorNode = await errorModule.default(errorProps);
434
446
  const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
435
447
  const errorHead = await resolveHead(errorModule, errorProps);
436
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), errorNode) : errorNode;
448
+ const layoutNode = layoutModule ? await layoutModule.default(context) : null;
449
+ const model = layoutNode ? injectRouteChildren(layoutNode, errorNode) : errorNode;
437
450
  return {
438
451
  statusCode,
439
452
  model,
@@ -465,10 +478,17 @@ function createFileRouter(options) {
465
478
  activeContext = context;
466
479
  const pageModule = resolveModule(match.entry.filePath);
467
480
  const layoutModule = import_node_fs.default.existsSync(layoutPath) ? resolveModule(layoutPath) : null;
468
- const pageNode = pageModule.default(context);
469
- const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
470
- const pageHead = await resolveHead(pageModule, context);
471
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), pageNode) : pageNode;
481
+ const pageData = await resolvePageData(pageModule, context);
482
+ const pageContext = {
483
+ ...context,
484
+ data: pageData
485
+ };
486
+ activeContext = pageContext;
487
+ const pageNode = await pageModule.default(pageContext);
488
+ const layoutHead = layoutModule ? await resolveHead(layoutModule, pageContext) : void 0;
489
+ const pageHead = await resolveHead(pageModule, pageContext);
490
+ const layoutNode = layoutModule ? await layoutModule.default(pageContext) : null;
491
+ const model = layoutNode ? injectRouteChildren(layoutNode, pageNode) : pageNode;
472
492
  return {
473
493
  statusCode: 200,
474
494
  model,
@@ -516,14 +536,26 @@ function stripBasePath(pathname, basePath) {
516
536
  }
517
537
  function runNodeCommand(args) {
518
538
  return new Promise((resolve, reject) => {
519
- (0, import_node_child_process.execFile)(process.execPath, args, { timeout: 1e4, maxBuffer: 1024 * 1024 * 5 }, (error, stdout, stderr) => {
520
- if (error) {
521
- const out = stderr && stderr.trim() !== "" ? stderr : stdout;
522
- reject(new Error(out || error.message));
523
- return;
539
+ const execArgs = [
540
+ "--conditions",
541
+ "react-server",
542
+ "-r",
543
+ "@webtypen/webframez-react/register",
544
+ ...args
545
+ ];
546
+ (0, import_node_child_process.execFile)(
547
+ process.execPath,
548
+ execArgs,
549
+ { timeout: 1e4, maxBuffer: 1024 * 1024 * 5 },
550
+ (error, stdout, stderr) => {
551
+ if (error) {
552
+ const out = stderr && stderr.trim() !== "" ? stderr : stdout;
553
+ reject(new Error(out || error.message));
554
+ return;
555
+ }
556
+ resolve({ stdout, stderr });
524
557
  }
525
- resolve({ stdout, stderr });
526
- });
558
+ );
527
559
  });
528
560
  }
529
561
  async function renderInitialHtmlInWorker(options) {
@@ -547,7 +579,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
547
579
  }
548
580
  return originalResolveFilename.call(this, request, parent, isMain, options);
549
581
  };
550
- const { createFileRouter } = require("webframez-react/router");
582
+ const { createFileRouter } = require("@webtypen/webframez-react/router");
551
583
  const reactDomPkg = require.resolve("react-dom/package.json", {
552
584
  paths: [process.cwd(), input.pagesDir]
553
585
  });
@@ -686,7 +718,11 @@ function createNodeRequestHandler(options) {
686
718
  cookies: requestCookies
687
719
  })
688
720
  );
689
- sendRSC(res, resolved2.model, {
721
+ const payload = {
722
+ model: resolved2.model,
723
+ head: resolved2.head
724
+ };
725
+ sendRSC(res, payload, {
690
726
  moduleMap,
691
727
  statusCode: resolved2.statusCode
692
728
  });
package/dist/index.d.ts CHANGED
@@ -1,15 +1,12 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
2
  import type { CreateHtmlShellOptions, SendRSCOptions } from "./types";
3
3
  import type { CreateNodeHandlerOptions } from "./http";
4
+ import "./webframez-core";
4
5
 
5
6
  export * from "./types";
6
7
  export { createFileRouter, parseSearchParams, renderHeadToString, RouteChildren } from "./router";
7
8
  export type { ResolvedRoute } from "./router";
8
- export { initWebframezReact, setupWebframezCoreReactRoute } from "./webframez-core";
9
- export type {
10
- WebframezCoreRouteMethod,
11
- WebframezCoreReactRenderRouteOptions,
12
- } from "./webframez-core";
9
+ export * from "./webframez-core";
13
10
 
14
11
  export function createHTMLShell(options?: CreateHtmlShellOptions): string;
15
12
  export function sendRSC(
package/dist/index.js CHANGED
@@ -221,6 +221,10 @@ function readSearchParams(urlSearchParams) {
221
221
  function escapeHtml(value) {
222
222
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
223
223
  }
224
+ var MANAGED_HEAD_ATTR = "data-webframez-head";
225
+ function createManagedAttributes() {
226
+ return `${MANAGED_HEAD_ATTR}="true"`;
227
+ }
224
228
  function toRouteEntry(pagesDir, filePath) {
225
229
  const normalized = filePath.replace(/\\/g, "/");
226
230
  if (!normalized.endsWith("/index.js")) {
@@ -289,19 +293,21 @@ function renderHeadToString(head) {
289
293
  const tags = [];
290
294
  if (head.description) {
291
295
  tags.push(
292
- `<meta name="description" content="${escapeHtml(head.description)}" />`
296
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
293
297
  );
294
298
  }
295
299
  if (head.favicon) {
296
- tags.push(`<link rel="icon" href="${escapeHtml(head.favicon)}" />`);
300
+ tags.push(
301
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
302
+ );
297
303
  }
298
304
  for (const meta of head.meta ?? []) {
299
305
  const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
300
- tags.push(`<meta ${attrs} />`);
306
+ tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
301
307
  }
302
308
  for (const link of head.links ?? []) {
303
309
  const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
304
- tags.push(`<link ${attrs} />`);
310
+ tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
305
311
  }
306
312
  return tags.join("\n");
307
313
  }
@@ -315,6 +321,12 @@ async function resolveHead(candidate, context) {
315
321
  }
316
322
  return candidate.Head(context);
317
323
  }
324
+ async function resolvePageData(candidate, context) {
325
+ if (!candidate.Data) {
326
+ return void 0;
327
+ }
328
+ return candidate.Data(context);
329
+ }
318
330
  function findBestMatch(entries, pathname) {
319
331
  const matches = [];
320
332
  for (const entry of entries) {
@@ -394,10 +406,11 @@ function createFileRouter(options) {
394
406
  };
395
407
  }
396
408
  const errorModule = resolveModule(errorPath);
397
- const errorNode = errorModule.default(errorProps);
409
+ const errorNode = await errorModule.default(errorProps);
398
410
  const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
399
411
  const errorHead = await resolveHead(errorModule, errorProps);
400
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), errorNode) : errorNode;
412
+ const layoutNode = layoutModule ? await layoutModule.default(context) : null;
413
+ const model = layoutNode ? injectRouteChildren(layoutNode, errorNode) : errorNode;
401
414
  return {
402
415
  statusCode,
403
416
  model,
@@ -429,10 +442,17 @@ function createFileRouter(options) {
429
442
  activeContext = context;
430
443
  const pageModule = resolveModule(match.entry.filePath);
431
444
  const layoutModule = fs.existsSync(layoutPath) ? resolveModule(layoutPath) : null;
432
- const pageNode = pageModule.default(context);
433
- const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
434
- const pageHead = await resolveHead(pageModule, context);
435
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), pageNode) : pageNode;
445
+ const pageData = await resolvePageData(pageModule, context);
446
+ const pageContext = {
447
+ ...context,
448
+ data: pageData
449
+ };
450
+ activeContext = pageContext;
451
+ const pageNode = await pageModule.default(pageContext);
452
+ const layoutHead = layoutModule ? await resolveHead(layoutModule, pageContext) : void 0;
453
+ const pageHead = await resolveHead(pageModule, pageContext);
454
+ const layoutNode = layoutModule ? await layoutModule.default(pageContext) : null;
455
+ const model = layoutNode ? injectRouteChildren(layoutNode, pageNode) : pageNode;
436
456
  return {
437
457
  statusCode: 200,
438
458
  model,
@@ -480,14 +500,26 @@ function stripBasePath(pathname, basePath) {
480
500
  }
481
501
  function runNodeCommand(args) {
482
502
  return new Promise((resolve, reject) => {
483
- execFile(process.execPath, args, { timeout: 1e4, maxBuffer: 1024 * 1024 * 5 }, (error, stdout, stderr) => {
484
- if (error) {
485
- const out = stderr && stderr.trim() !== "" ? stderr : stdout;
486
- reject(new Error(out || error.message));
487
- return;
503
+ const execArgs = [
504
+ "--conditions",
505
+ "react-server",
506
+ "-r",
507
+ "@webtypen/webframez-react/register",
508
+ ...args
509
+ ];
510
+ execFile(
511
+ process.execPath,
512
+ execArgs,
513
+ { timeout: 1e4, maxBuffer: 1024 * 1024 * 5 },
514
+ (error, stdout, stderr) => {
515
+ if (error) {
516
+ const out = stderr && stderr.trim() !== "" ? stderr : stdout;
517
+ reject(new Error(out || error.message));
518
+ return;
519
+ }
520
+ resolve({ stdout, stderr });
488
521
  }
489
- resolve({ stdout, stderr });
490
- });
522
+ );
491
523
  });
492
524
  }
493
525
  async function renderInitialHtmlInWorker(options) {
@@ -511,7 +543,7 @@ Module._resolveFilename = function(request, parent, isMain, options) {
511
543
  }
512
544
  return originalResolveFilename.call(this, request, parent, isMain, options);
513
545
  };
514
- const { createFileRouter } = require("webframez-react/router");
546
+ const { createFileRouter } = require("@webtypen/webframez-react/router");
515
547
  const reactDomPkg = require.resolve("react-dom/package.json", {
516
548
  paths: [process.cwd(), input.pagesDir]
517
549
  });
@@ -650,7 +682,11 @@ function createNodeRequestHandler(options) {
650
682
  cookies: requestCookies
651
683
  })
652
684
  );
653
- sendRSC(res, resolved2.model, {
685
+ const payload = {
686
+ model: resolved2.model,
687
+ head: resolved2.head
688
+ };
689
+ sendRSC(res, payload, {
654
690
  moduleMap,
655
691
  statusCode: resolved2.statusCode
656
692
  });
package/dist/router.cjs CHANGED
@@ -144,6 +144,10 @@ function readSearchParams(urlSearchParams) {
144
144
  function escapeHtml(value) {
145
145
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
146
146
  }
147
+ var MANAGED_HEAD_ATTR = "data-webframez-head";
148
+ function createManagedAttributes() {
149
+ return `${MANAGED_HEAD_ATTR}="true"`;
150
+ }
147
151
  function toRouteEntry(pagesDir, filePath) {
148
152
  const normalized = filePath.replace(/\\/g, "/");
149
153
  if (!normalized.endsWith("/index.js")) {
@@ -212,19 +216,21 @@ function renderHeadToString(head) {
212
216
  const tags = [];
213
217
  if (head.description) {
214
218
  tags.push(
215
- `<meta name="description" content="${escapeHtml(head.description)}" />`
219
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
216
220
  );
217
221
  }
218
222
  if (head.favicon) {
219
- tags.push(`<link rel="icon" href="${escapeHtml(head.favicon)}" />`);
223
+ tags.push(
224
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
225
+ );
220
226
  }
221
227
  for (const meta of head.meta ?? []) {
222
228
  const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
223
- tags.push(`<meta ${attrs} />`);
229
+ tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
224
230
  }
225
231
  for (const link of head.links ?? []) {
226
232
  const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
227
- tags.push(`<link ${attrs} />`);
233
+ tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
228
234
  }
229
235
  return tags.join("\n");
230
236
  }
@@ -238,6 +244,12 @@ async function resolveHead(candidate, context) {
238
244
  }
239
245
  return candidate.Head(context);
240
246
  }
247
+ async function resolvePageData(candidate, context) {
248
+ if (!candidate.Data) {
249
+ return void 0;
250
+ }
251
+ return candidate.Data(context);
252
+ }
241
253
  function findBestMatch(entries, pathname) {
242
254
  const matches = [];
243
255
  for (const entry of entries) {
@@ -317,10 +329,11 @@ function createFileRouter(options) {
317
329
  };
318
330
  }
319
331
  const errorModule = resolveModule(errorPath);
320
- const errorNode = errorModule.default(errorProps);
332
+ const errorNode = await errorModule.default(errorProps);
321
333
  const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
322
334
  const errorHead = await resolveHead(errorModule, errorProps);
323
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), errorNode) : errorNode;
335
+ const layoutNode = layoutModule ? await layoutModule.default(context) : null;
336
+ const model = layoutNode ? injectRouteChildren(layoutNode, errorNode) : errorNode;
324
337
  return {
325
338
  statusCode,
326
339
  model,
@@ -352,10 +365,17 @@ function createFileRouter(options) {
352
365
  activeContext = context;
353
366
  const pageModule = resolveModule(match.entry.filePath);
354
367
  const layoutModule = import_node_fs.default.existsSync(layoutPath) ? resolveModule(layoutPath) : null;
355
- const pageNode = pageModule.default(context);
356
- const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
357
- const pageHead = await resolveHead(pageModule, context);
358
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), pageNode) : pageNode;
368
+ const pageData = await resolvePageData(pageModule, context);
369
+ const pageContext = {
370
+ ...context,
371
+ data: pageData
372
+ };
373
+ activeContext = pageContext;
374
+ const pageNode = await pageModule.default(pageContext);
375
+ const layoutHead = layoutModule ? await resolveHead(layoutModule, pageContext) : void 0;
376
+ const pageHead = await resolveHead(pageModule, pageContext);
377
+ const layoutNode = layoutModule ? await layoutModule.default(pageContext) : null;
378
+ const model = layoutNode ? injectRouteChildren(layoutNode, pageNode) : pageNode;
359
379
  return {
360
380
  statusCode: 200,
361
381
  model,
package/dist/router.js CHANGED
@@ -114,6 +114,10 @@ function readSearchParams(urlSearchParams) {
114
114
  function escapeHtml(value) {
115
115
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
116
116
  }
117
+ var MANAGED_HEAD_ATTR = "data-webframez-head";
118
+ function createManagedAttributes() {
119
+ return `${MANAGED_HEAD_ATTR}="true"`;
120
+ }
117
121
  function toRouteEntry(pagesDir, filePath) {
118
122
  const normalized = filePath.replace(/\\/g, "/");
119
123
  if (!normalized.endsWith("/index.js")) {
@@ -182,19 +186,21 @@ function renderHeadToString(head) {
182
186
  const tags = [];
183
187
  if (head.description) {
184
188
  tags.push(
185
- `<meta name="description" content="${escapeHtml(head.description)}" />`
189
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
186
190
  );
187
191
  }
188
192
  if (head.favicon) {
189
- tags.push(`<link rel="icon" href="${escapeHtml(head.favicon)}" />`);
193
+ tags.push(
194
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
195
+ );
190
196
  }
191
197
  for (const meta of head.meta ?? []) {
192
198
  const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
193
- tags.push(`<meta ${attrs} />`);
199
+ tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
194
200
  }
195
201
  for (const link of head.links ?? []) {
196
202
  const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
197
- tags.push(`<link ${attrs} />`);
203
+ tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
198
204
  }
199
205
  return tags.join("\n");
200
206
  }
@@ -208,6 +214,12 @@ async function resolveHead(candidate, context) {
208
214
  }
209
215
  return candidate.Head(context);
210
216
  }
217
+ async function resolvePageData(candidate, context) {
218
+ if (!candidate.Data) {
219
+ return void 0;
220
+ }
221
+ return candidate.Data(context);
222
+ }
211
223
  function findBestMatch(entries, pathname) {
212
224
  const matches = [];
213
225
  for (const entry of entries) {
@@ -287,10 +299,11 @@ function createFileRouter(options) {
287
299
  };
288
300
  }
289
301
  const errorModule = resolveModule(errorPath);
290
- const errorNode = errorModule.default(errorProps);
302
+ const errorNode = await errorModule.default(errorProps);
291
303
  const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
292
304
  const errorHead = await resolveHead(errorModule, errorProps);
293
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), errorNode) : errorNode;
305
+ const layoutNode = layoutModule ? await layoutModule.default(context) : null;
306
+ const model = layoutNode ? injectRouteChildren(layoutNode, errorNode) : errorNode;
294
307
  return {
295
308
  statusCode,
296
309
  model,
@@ -322,10 +335,17 @@ function createFileRouter(options) {
322
335
  activeContext = context;
323
336
  const pageModule = resolveModule(match.entry.filePath);
324
337
  const layoutModule = fs.existsSync(layoutPath) ? resolveModule(layoutPath) : null;
325
- const pageNode = pageModule.default(context);
326
- const layoutHead = layoutModule ? await resolveHead(layoutModule, context) : void 0;
327
- const pageHead = await resolveHead(pageModule, context);
328
- const model = layoutModule ? injectRouteChildren(layoutModule.default(context), pageNode) : pageNode;
338
+ const pageData = await resolvePageData(pageModule, context);
339
+ const pageContext = {
340
+ ...context,
341
+ data: pageData
342
+ };
343
+ activeContext = pageContext;
344
+ const pageNode = await pageModule.default(pageContext);
345
+ const layoutHead = layoutModule ? await resolveHead(layoutModule, pageContext) : void 0;
346
+ const pageHead = await resolveHead(pageModule, pageContext);
347
+ const layoutNode = layoutModule ? await layoutModule.default(pageContext) : null;
348
+ const model = layoutNode ? injectRouteChildren(layoutNode, pageNode) : pageNode;
329
349
  return {
330
350
  statusCode: 200,
331
351
  model,