@webtypen/webframez-react 0.0.35 → 0.0.36

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.
@@ -4,16 +4,18 @@ import fs from "node:fs";
4
4
  import fsp from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { spawn } from "node:child_process";
7
+ import { createRequire } from "node:module";
7
8
  import { fileURLToPath, pathToFileURL } from "node:url";
8
9
 
9
10
  const binFilePath = fileURLToPath(import.meta.url);
10
11
  const packageRoot = path.resolve(path.dirname(binFilePath), "..");
11
12
  const projectRoot = process.cwd();
13
+ const require = createRequire(import.meta.url);
12
14
 
13
15
  const command = process.argv[2];
14
16
  const passthroughStart = process.argv[3] === "--" ? 4 : 3;
15
17
  const passthroughArgs = process.argv.slice(passthroughStart);
16
- const customArgPrefixes = ["--client-entry", "--server-entry"];
18
+ const customArgPrefixes = ["--client-entry", "--server-entry", "--routes", "--out-dir", "--runtime-out-dir"];
17
19
 
18
20
  function printHelp() {
19
21
  console.log(
@@ -25,6 +27,8 @@ function printHelp() {
25
27
  " webframez-react watch:server",
26
28
  " webframez-react build:client",
27
29
  " webframez-react watch:client",
30
+ " webframez-react build:routes --routes=dist/app/routes.js --out-dir=dist",
31
+ " webframez-react watch:routes --routes=dist/app/routes.js --out-dir=dist",
28
32
  " webframez-react build:server:webpack",
29
33
  " webframez-react watch:server:webpack",
30
34
  " webframez-react exec -- <command> [args...]",
@@ -44,6 +48,9 @@ function printHelp() {
44
48
  "Optional CLI overrides:",
45
49
  " --client-entry=src/client.tsx",
46
50
  " --server-entry=src/server.ts",
51
+ " --routes=dist/app/routes.js",
52
+ " --out-dir=dist",
53
+ " --runtime-out-dir=dist",
47
54
  ].join("\n"),
48
55
  );
49
56
  }
@@ -70,6 +77,14 @@ function readCustomArg(name) {
70
77
  return null;
71
78
  }
72
79
 
80
+ function requireCustomArg(name, description) {
81
+ const value = readCustomArg(name);
82
+ if (!value) {
83
+ throw new Error(`Missing ${description || name}.`);
84
+ }
85
+ return value;
86
+ }
87
+
73
88
  function stripCustomArgs(args) {
74
89
  const filtered = [];
75
90
  for (let index = 0; index < args.length; index += 1) {
@@ -121,6 +136,55 @@ function buildReactServerNodeOptions() {
121
136
  return `${existing}--conditions react-server -r @webtypen/webframez-react/register`.trim();
122
137
  }
123
138
 
139
+ function hasReactServerCondition() {
140
+ if (process.execArgv.includes("--conditions=react-server")) {
141
+ return true;
142
+ }
143
+
144
+ for (let index = 0; index < process.execArgv.length; index += 1) {
145
+ if (process.execArgv[index] === "--conditions" && process.execArgv[index + 1] === "react-server") {
146
+ return true;
147
+ }
148
+ }
149
+
150
+ return /\b--conditions(?:=|\s+)react-server\b/.test(process.env.NODE_OPTIONS || "");
151
+ }
152
+
153
+ async function reexecWithReactServerConditionIfNeeded() {
154
+ if (
155
+ (command !== "build:routes" && command !== "watch:routes") ||
156
+ hasReactServerCondition() ||
157
+ process.env.WEBFRAMEZ_REACT_CLI_REEXEC === "1"
158
+ ) {
159
+ return false;
160
+ }
161
+
162
+ const child = spawn(process.execPath, [
163
+ "--conditions",
164
+ "react-server",
165
+ "--require",
166
+ path.resolve(packageRoot, "register.cjs"),
167
+ binFilePath,
168
+ ...process.argv.slice(2),
169
+ ], {
170
+ cwd: projectRoot,
171
+ stdio: "inherit",
172
+ shell: false,
173
+ env: {
174
+ ...process.env,
175
+ WEBFRAMEZ_REACT_CLI_REEXEC: "1",
176
+ },
177
+ });
178
+
179
+ const code = await new Promise((resolve, reject) => {
180
+ child.on("error", reject);
181
+ child.on("close", (exitCode) => resolve(exitCode || 0));
182
+ });
183
+
184
+ process.exit(code);
185
+ return true;
186
+ }
187
+
124
188
  async function loadProjectConfig() {
125
189
  const configFiles = [
126
190
  "webframez-react.config.mjs",
@@ -216,12 +280,270 @@ function run(binaryName, args, envAdditions = {}) {
216
280
  });
217
281
  }
218
282
 
283
+ function start(binaryName, args, envAdditions = {}) {
284
+ const binary = resolveBinary(binaryName);
285
+
286
+ return spawn(binary, args, {
287
+ cwd: projectRoot,
288
+ stdio: "inherit",
289
+ shell: false,
290
+ env: {
291
+ ...process.env,
292
+ ...envAdditions,
293
+ },
294
+ });
295
+ }
296
+
297
+ function fileExists(filePath) {
298
+ return fs.existsSync(filePath);
299
+ }
300
+
301
+ function mapTargetPath(value, fromRoot, toRoot) {
302
+ if (!value) {
303
+ return value;
304
+ }
305
+
306
+ const relative = path.relative(fromRoot, value);
307
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
308
+ return value;
309
+ }
310
+
311
+ return path.resolve(toRoot, relative);
312
+ }
313
+
314
+ async function loadRouteBuildTargets(routesPath, outDir, runtimeOutDir) {
315
+ const coreModulePath = path.resolve(packageRoot, "dist", "webframez-core.cjs");
316
+ const core = require(coreModulePath);
317
+ const Module = require("node:module");
318
+ const originalLoad = Module._load;
319
+ const previousOutDir = process.env.WEBFRAMEZ_REACT_OUT_DIR;
320
+ const previousCaptureRoutes = process.env.WEBFRAMEZ_REACT_CAPTURE_ROUTES;
321
+ const fakeRoute = {
322
+ extend(name, factory) {
323
+ this[name] = factory(this);
324
+ return this;
325
+ },
326
+ group(_options, callback) {
327
+ if (typeof callback === "function") {
328
+ callback();
329
+ }
330
+ },
331
+ get() {},
332
+ post() {},
333
+ put() {},
334
+ delete() {},
335
+ };
336
+
337
+ process.env.WEBFRAMEZ_REACT_OUT_DIR = runtimeOutDir;
338
+ process.env.WEBFRAMEZ_REACT_CAPTURE_ROUTES = "1";
339
+ core.clearRegisteredReactBuildTargets();
340
+ Module._load = function webframezReactCaptureModuleLoad(request, parent, isMain) {
341
+ if (request === "@webtypen/webframez-react") {
342
+ return require(path.resolve(packageRoot, "dist", "index.cjs"));
343
+ }
344
+ if (request === "@webtypen/webframez-react/http") {
345
+ return require(path.resolve(packageRoot, "dist", "http.cjs"));
346
+ }
347
+ if (request === "@webtypen/webframez-react/webframez-core") {
348
+ return require(path.resolve(packageRoot, "dist", "webframez-core.cjs"));
349
+ }
350
+ if (request === "@webtypen/webframez-react/navigation") {
351
+ return require(path.resolve(packageRoot, "dist", "navigation.cjs"));
352
+ }
353
+ if (request === "@webtypen/webframez-react/route-slot") {
354
+ return require(path.resolve(packageRoot, "dist", "route-slot.cjs"));
355
+ }
356
+ if (request === "@webtypen/webframez-react/client") {
357
+ return require(path.resolve(packageRoot, "dist", "client.cjs"));
358
+ }
359
+
360
+ if (
361
+ request === "@webtypen/webframez-core" ||
362
+ request === "webframez-core" ||
363
+ request === "@webtypen/webframez-core/dist/Router/Route" ||
364
+ request === "webframez-core/dist/Router/Route"
365
+ ) {
366
+ return {
367
+ Route: fakeRoute,
368
+ };
369
+ }
370
+
371
+ return originalLoad.call(this, request, parent, isMain);
372
+ };
373
+
374
+ try {
375
+ const resolvedRoutesPath = path.resolve(projectRoot, routesPath);
376
+ await import(pathToFileURL(resolvedRoutesPath).href);
377
+ return core.getRegisteredReactBuildTargets().map((target) => ({
378
+ ...target,
379
+ runtimeDistRootDir: target.distRootDir,
380
+ runtimePagesDir: target.pagesDir,
381
+ runtimeManifestPath: target.manifestPath,
382
+ distRootDir: mapTargetPath(target.distRootDir, runtimeOutDir, outDir),
383
+ pagesDir: mapTargetPath(target.pagesDir, runtimeOutDir, outDir),
384
+ manifestPath: mapTargetPath(target.manifestPath, runtimeOutDir, outDir),
385
+ }));
386
+ } finally {
387
+ Module._load = originalLoad;
388
+ if (previousOutDir === undefined) {
389
+ delete process.env.WEBFRAMEZ_REACT_OUT_DIR;
390
+ } else {
391
+ process.env.WEBFRAMEZ_REACT_OUT_DIR = previousOutDir;
392
+ }
393
+ if (previousCaptureRoutes === undefined) {
394
+ delete process.env.WEBFRAMEZ_REACT_CAPTURE_ROUTES;
395
+ } else {
396
+ process.env.WEBFRAMEZ_REACT_CAPTURE_ROUTES = previousCaptureRoutes;
397
+ }
398
+ }
399
+ }
400
+
401
+ async function waitForFile(filePath) {
402
+ const startedAt = Date.now();
403
+
404
+ while (!fileExists(filePath)) {
405
+ if (Date.now() - startedAt > 30000) {
406
+ throw new Error(`Timed out waiting for ${filePath}.`);
407
+ }
408
+
409
+ console.log(`[webframez-react] waiting for routes file: ${filePath}`);
410
+ await new Promise((resolve) => setTimeout(resolve, 1000));
411
+ }
412
+ }
413
+
414
+ async function buildRouteStyles(target) {
415
+ if (!target.styleSrcPath || !fileExists(target.styleSrcPath)) {
416
+ return 0;
417
+ }
418
+
419
+ const outputDir = path.join(target.distRootDir, "scss");
420
+ await fsp.mkdir(outputDir, { recursive: true });
421
+ console.log(`[webframez-react] sass: ${target.styleSrcPath} -> ${outputDir}`);
422
+
423
+ return run("sass", ["--no-source-map", `${target.styleSrcPath}:${outputDir}`]);
424
+ }
425
+
426
+ async function buildRouteClient(target, passthroughArgsClean) {
427
+ const config = {
428
+ path: path.resolve(packageRoot, "defaults", "webpack.client.cjs"),
429
+ source: "package",
430
+ };
431
+ const clientEntry = target.clientEntryPath || path.resolve(packageRoot, "defaults", "default-client.js");
432
+
433
+ console.log(`[webframez-react] route: ${target.path}`);
434
+ console.log(`[webframez-react] webpack config (${config.source}): ${config.path}`);
435
+ console.log(`[webframez-react] pages: ${target.pagesDir}`);
436
+ console.log(`[webframez-react] dist: ${target.distRootDir}`);
437
+ console.log(`[webframez-react] client entry: ${clientEntry}`);
438
+
439
+ return run(
440
+ "webpack",
441
+ ["--config", config.path, ...passthroughArgsClean],
442
+ {
443
+ WEBFRAMEZ_REACT_CLIENT_ENTRY: clientEntry,
444
+ WEBFRAMEZ_REACT_DIST_ROOT_DIR: target.distRootDir,
445
+ WEBFRAMEZ_REACT_PAGES_DIR: target.pagesDir,
446
+ WEBFRAMEZ_REACT_RUNTIME_DIST_ROOT_DIR: target.runtimeDistRootDir || target.distRootDir,
447
+ WEBFRAMEZ_REACT_RUNTIME_PAGES_DIR: target.runtimePagesDir || target.pagesDir,
448
+ },
449
+ );
450
+ }
451
+
452
+ function watchRouteStyles(target) {
453
+ if (!target.styleSrcPath || !fileExists(target.styleSrcPath)) {
454
+ return null;
455
+ }
456
+
457
+ const outputDir = path.join(target.distRootDir, "scss");
458
+ fs.mkdirSync(outputDir, { recursive: true });
459
+ console.log(`[webframez-react] sass watch: ${target.styleSrcPath} -> ${outputDir}`);
460
+
461
+ return start("sass", ["--watch", "--poll", "--no-source-map", `${target.styleSrcPath}:${outputDir}`]);
462
+ }
463
+
464
+ function watchRouteClient(target, passthroughArgsClean) {
465
+ const config = {
466
+ path: path.resolve(packageRoot, "defaults", "webpack.client.cjs"),
467
+ source: "package",
468
+ };
469
+ const clientEntry = target.clientEntryPath || path.resolve(packageRoot, "defaults", "default-client.js");
470
+ const args = ["--config", config.path, ...passthroughArgsClean];
471
+
472
+ if (!args.includes("--watch")) {
473
+ args.push("--watch");
474
+ }
475
+
476
+ console.log(`[webframez-react] route watch: ${target.path}`);
477
+ console.log(`[webframez-react] webpack config (${config.source}): ${config.path}`);
478
+ console.log(`[webframez-react] pages: ${target.pagesDir}`);
479
+ console.log(`[webframez-react] dist: ${target.distRootDir}`);
480
+ console.log(`[webframez-react] client entry: ${clientEntry}`);
481
+
482
+ return start("webpack", args, {
483
+ WEBFRAMEZ_REACT_CLIENT_ENTRY: clientEntry,
484
+ WEBFRAMEZ_REACT_DIST_ROOT_DIR: target.distRootDir,
485
+ WEBFRAMEZ_REACT_PAGES_DIR: target.pagesDir,
486
+ WEBFRAMEZ_REACT_RUNTIME_DIST_ROOT_DIR: target.runtimeDistRootDir || target.distRootDir,
487
+ WEBFRAMEZ_REACT_RUNTIME_PAGES_DIR: target.runtimePagesDir || target.pagesDir,
488
+ });
489
+ }
490
+
491
+ async function watchRouteTargets(targets, passthroughArgsClean) {
492
+ const children = [];
493
+
494
+ for (const target of targets) {
495
+ const styleChild = watchRouteStyles(target);
496
+ if (styleChild) {
497
+ children.push(styleChild);
498
+ }
499
+
500
+ children.push(watchRouteClient(target, passthroughArgsClean));
501
+ }
502
+
503
+ if (children.length === 0) {
504
+ return;
505
+ }
506
+
507
+ await new Promise((resolve, reject) => {
508
+ for (const child of children) {
509
+ child.on("error", reject);
510
+ child.on("close", (code) => {
511
+ if (code && code !== 0) {
512
+ reject(new Error(`[webframez-react] watch child exited with code ${code}.`));
513
+ return;
514
+ }
515
+
516
+ resolve();
517
+ });
518
+ }
519
+ });
520
+ }
521
+
522
+ async function validateRouteBuild(target) {
523
+ const requiredFiles = [
524
+ path.join(target.distRootDir, "client.js"),
525
+ path.join(target.distRootDir, "react-client-manifest.json"),
526
+ path.join(target.distRootDir, "react-ssr-manifest.json"),
527
+ ];
528
+
529
+ const missing = requiredFiles.filter((filePath) => !fileExists(filePath));
530
+ if (missing.length > 0) {
531
+ throw new Error(
532
+ `Route ${target.path} build is incomplete. Missing: ${missing.join(", ")}`,
533
+ );
534
+ }
535
+ }
536
+
219
537
  async function main() {
220
538
  if (!command || command === "--help" || command === "-h") {
221
539
  printHelp();
222
540
  return;
223
541
  }
224
542
 
543
+ if (await reexecWithReactServerConditionIfNeeded()) {
544
+ return;
545
+ }
546
+
225
547
  const projectConfig = await loadProjectConfig();
226
548
  const customClientEntry = readCustomArg("--client-entry");
227
549
  const customServerEntry = readCustomArg("--server-entry");
@@ -280,6 +602,41 @@ async function main() {
280
602
  return;
281
603
  }
282
604
 
605
+ if (command === "build:routes" || command === "watch:routes") {
606
+ const routesPath = requireCustomArg("--routes", "--routes=<compiled routes file>");
607
+ const outDir = path.resolve(projectRoot, readCustomArg("--out-dir") || "dist");
608
+ const runtimeOutDir = path.resolve(projectRoot, readCustomArg("--runtime-out-dir") || outDir);
609
+ await waitForFile(path.resolve(projectRoot, routesPath));
610
+ const targets = await loadRouteBuildTargets(routesPath, outDir, runtimeOutDir);
611
+
612
+ if (targets.length === 0) {
613
+ throw new Error(`[webframez-react] No React routes were registered by ${routesPath}.`);
614
+ }
615
+
616
+ if (command === "watch:routes") {
617
+ await watchRouteTargets(targets, passthroughArgsClean);
618
+ return;
619
+ }
620
+
621
+ for (const target of targets) {
622
+ const sassCode = await buildRouteStyles(target);
623
+ if (sassCode !== 0) {
624
+ process.exit(sassCode);
625
+ return;
626
+ }
627
+
628
+ const webpackCode = await buildRouteClient(target, passthroughArgsClean);
629
+ if (webpackCode !== 0) {
630
+ process.exit(webpackCode);
631
+ return;
632
+ }
633
+
634
+ await validateRouteBuild(target);
635
+ }
636
+
637
+ return;
638
+ }
639
+
283
640
  if (command === "build:client" || command === "watch:client") {
284
641
  const config = resolveConfig("webpack.client.cjs", "webpack.client.cjs");
285
642
  console.log(`[webframez-react] webpack config (${config.source}): ${config.path}`);
@@ -0,0 +1,3 @@
1
+ import { mountWebframezClient } from "@webtypen/webframez-react/client";
2
+
3
+ mountWebframezClient();
@@ -1,30 +1,201 @@
1
+ const fs = require("fs");
1
2
  const path = require("path");
2
3
  const ReactFlightWebpackPlugin = require("react-server-dom-webpack/plugin");
4
+ const { fileURLToPath, pathToFileURL } = require("url");
3
5
 
4
6
  const projectRoot = process.cwd();
5
7
  const frameworkDistDir = path.resolve(__dirname, "..", "dist");
6
8
  const clientEntry = process.env.WEBFRAMEZ_REACT_CLIENT_ENTRY
7
9
  ? path.resolve(projectRoot, process.env.WEBFRAMEZ_REACT_CLIENT_ENTRY)
8
- : path.resolve(projectRoot, "src/client.tsx");
10
+ : path.resolve(__dirname, "default-client.js");
11
+ const pagesDir = process.env.WEBFRAMEZ_REACT_PAGES_DIR
12
+ ? path.resolve(projectRoot, process.env.WEBFRAMEZ_REACT_PAGES_DIR)
13
+ : path.resolve(projectRoot, "dist/pages");
14
+ const distDir = process.env.WEBFRAMEZ_REACT_DIST_ROOT_DIR
15
+ ? path.resolve(projectRoot, process.env.WEBFRAMEZ_REACT_DIST_ROOT_DIR)
16
+ : path.resolve(projectRoot, "dist");
17
+ const runtimePagesDir = process.env.WEBFRAMEZ_REACT_RUNTIME_PAGES_DIR
18
+ ? path.resolve(projectRoot, process.env.WEBFRAMEZ_REACT_RUNTIME_PAGES_DIR)
19
+ : pagesDir;
9
20
  const isWatchMode = process.argv.includes("--watch");
10
21
  const mode =
11
22
  process.env.NODE_ENV === "production" || (typeof process.env.NODE_ENV === "undefined" && !isWatchMode)
12
23
  ? "production"
13
24
  : "development";
25
+ const frameworkCacheFiles = [
26
+ path.join(frameworkDistDir, "client.js"),
27
+ path.join(frameworkDistDir, "route-slot.js"),
28
+ path.join(frameworkDistDir, "navigation.js"),
29
+ ].filter((filePath) => fs.existsSync(filePath));
30
+ const frameworkCacheVersion = frameworkCacheFiles
31
+ .map((filePath) => `${path.basename(filePath)}:${fs.statSync(filePath).mtimeMs}:${fs.statSync(filePath).size}`)
32
+ .join("|");
33
+
34
+ fs.mkdirSync(distDir, { recursive: true });
35
+ fs.mkdirSync(pagesDir, { recursive: true });
36
+
37
+ class ClientManifestExportAliasesPlugin {
38
+ apply(compiler) {
39
+ compiler.hooks.done.tap("ClientManifestExportAliasesPlugin", () => {
40
+ const manifestPath = path.join(distDir, "react-client-manifest.json");
41
+ if (!fs.existsSync(manifestPath)) {
42
+ return;
43
+ }
44
+
45
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
46
+ let changed = false;
47
+
48
+ for (const [key, value] of Object.entries(manifest)) {
49
+ if (!key.startsWith("file://")) {
50
+ continue;
51
+ }
52
+
53
+ let absolutePath = null;
54
+ try {
55
+ absolutePath = fileURLToPath(key);
56
+ } catch (error) {
57
+ absolutePath = null;
58
+ }
59
+
60
+ if (!absolutePath || !fs.existsSync(absolutePath)) {
61
+ continue;
62
+ }
63
+
64
+ const relativeToProject = path.relative(projectRoot, absolutePath).split(path.sep).join("/");
65
+ const relativeAlias = relativeToProject.startsWith(".") ? relativeToProject : `./${relativeToProject}`;
66
+ const aliases = [
67
+ { key, force: false },
68
+ { key: absolutePath, force: false },
69
+ { key: relativeAlias, force: false },
70
+ { key: relativeToProject, force: false },
71
+ ];
72
+ const relativeToPagesDir = path.relative(pagesDir, absolutePath);
73
+
74
+ if (!relativeToPagesDir.startsWith("..") && !path.isAbsolute(relativeToPagesDir)) {
75
+ const runtimeAbsolutePath = path.resolve(runtimePagesDir, relativeToPagesDir);
76
+ const runtimeRelativeToProject = path.relative(projectRoot, runtimeAbsolutePath).split(path.sep).join("/");
77
+ const runtimeRelativeAlias = runtimeRelativeToProject.startsWith(".")
78
+ ? runtimeRelativeToProject
79
+ : `./${runtimeRelativeToProject}`;
80
+ aliases.push(
81
+ { key: pathToFileURL(runtimeAbsolutePath).href, force: false },
82
+ { key: runtimeAbsolutePath, force: false },
83
+ { key: runtimeRelativeAlias, force: false },
84
+ { key: runtimeRelativeToProject, force: false },
85
+ );
86
+ }
87
+
88
+ const relativeToFrameworkDist = path.relative(frameworkDistDir, absolutePath);
89
+ if (
90
+ !relativeToFrameworkDist.startsWith("..") &&
91
+ !path.isAbsolute(relativeToFrameworkDist) &&
92
+ /\.(js)$/.test(relativeToFrameworkDist) &&
93
+ /^(navigation|route-slot)\.js$/.test(relativeToFrameworkDist)
94
+ ) {
95
+ const cjsAbsolutePath = absolutePath.replace(/\.js$/, ".cjs");
96
+ if (fs.existsSync(cjsAbsolutePath)) {
97
+ const cjsRelativeToProject = path.relative(projectRoot, cjsAbsolutePath).split(path.sep).join("/");
98
+ const cjsRelativeAlias = cjsRelativeToProject.startsWith(".")
99
+ ? cjsRelativeToProject
100
+ : `./${cjsRelativeToProject}`;
101
+ aliases.push(
102
+ { key: pathToFileURL(cjsAbsolutePath).href, force: true },
103
+ { key: cjsAbsolutePath, force: true },
104
+ { key: cjsRelativeAlias, force: true },
105
+ { key: cjsRelativeToProject, force: true },
106
+ );
107
+ }
108
+ }
109
+
110
+ for (const alias of aliases) {
111
+ if (alias.force || !(alias.key in manifest)) {
112
+ manifest[alias.key] = value;
113
+ changed = true;
114
+ }
115
+ }
116
+
117
+ const source = fs.readFileSync(absolutePath, "utf-8");
118
+ const exportNames = new Set();
119
+ const exportPattern = /exports\.([A-Za-z0-9_$]+)\s*=/g;
120
+ let match = null;
121
+ while ((match = exportPattern.exec(source)) !== null) {
122
+ if (match[1] && match[1] !== "__esModule") {
123
+ exportNames.add(match[1]);
124
+ }
125
+ }
126
+
127
+ for (const exportName of exportNames) {
128
+ const exportValue =
129
+ value && typeof value === "object"
130
+ ? {
131
+ ...value,
132
+ name: exportName,
133
+ }
134
+ : value;
135
+ for (const alias of aliases) {
136
+ const aliasKey = `${alias.key}#${exportName}`;
137
+ if (alias.force || !(aliasKey in manifest)) {
138
+ manifest[aliasKey] = exportValue;
139
+ changed = true;
140
+ }
141
+ }
142
+
143
+ if (exportName === "default") {
144
+ for (const alias of aliases) {
145
+ const aliasKey = `${alias.key}#`;
146
+ if (alias.force || !(aliasKey in manifest)) {
147
+ manifest[aliasKey] = exportValue;
148
+ changed = true;
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ if (changed) {
156
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
157
+ }
158
+ });
159
+ }
160
+ }
14
161
 
15
162
  module.exports = {
16
163
  mode,
164
+ cache: {
165
+ type: "filesystem",
166
+ version: frameworkCacheVersion,
167
+ buildDependencies: {
168
+ config: [__filename, ...frameworkCacheFiles],
169
+ },
170
+ },
17
171
  entry: {
18
172
  client: clientEntry,
19
173
  },
20
174
  output: {
21
- path: path.resolve(projectRoot, "dist"),
22
- filename: "[name].js",
175
+ path: distDir,
176
+ filename: "client.js",
23
177
  chunkFilename: "chunks/[name]-[contenthash].js",
24
178
  publicPath: "auto",
25
179
  },
26
180
  resolve: {
27
181
  extensions: [".tsx", ".ts", ".js"],
182
+ modules: [path.resolve(projectRoot, "node_modules"), "node_modules"],
183
+ alias: {
184
+ react: path.resolve(projectRoot, "node_modules", "react"),
185
+ "react-dom": path.resolve(projectRoot, "node_modules", "react-dom"),
186
+ "react/jsx-runtime": path.resolve(projectRoot, "node_modules", "react", "jsx-runtime.js"),
187
+ "react/jsx-dev-runtime": path.resolve(projectRoot, "node_modules", "react", "jsx-dev-runtime.js"),
188
+ scheduler: path.resolve(projectRoot, "node_modules", "scheduler"),
189
+ },
190
+ },
191
+ watchOptions: {
192
+ aggregateTimeout: 150,
193
+ poll: Number(process.env.WEBFRAMEZ_REACT_WATCH_POLL || 1000),
194
+ ignored: [
195
+ path.resolve(projectRoot, "node_modules", "**"),
196
+ path.resolve(distDir, "**"),
197
+ path.resolve(projectRoot, "build", "node_modules", "**"),
198
+ ],
28
199
  },
29
200
  module: {
30
201
  rules: [
@@ -51,21 +222,17 @@ module.exports = {
51
222
  isServer: false,
52
223
  clientReferences: [
53
224
  {
54
- directory: path.resolve(projectRoot, "dist/pages"),
55
- recursive: true,
56
- include: /\.js$/,
57
- },
58
- {
59
- directory: path.resolve(projectRoot, "dist/src/components"),
225
+ directory: pagesDir,
60
226
  recursive: true,
61
227
  include: /\.js$/,
62
228
  },
63
229
  {
64
230
  directory: frameworkDistDir,
65
231
  recursive: false,
66
- include: /navigation\.(js|cjs)$/,
232
+ include: /(navigation|route-slot)\.js$/,
67
233
  },
68
234
  ],
69
235
  }),
236
+ new ClientManifestExportAliasesPlugin(),
70
237
  ],
71
238
  };