@blinkk/root 1.0.0-rc.4 → 1.0.0-rc.41

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.
@@ -1,9 +1,12 @@
1
1
  import {
2
+ headersMiddleware,
2
3
  rootProjectMiddleware,
3
4
  sessionMiddleware,
4
5
  trailingSlashMiddleware
5
- } from "./chunk-WNXIRMFF.js";
6
+ } from "./chunk-TZAHHHA4.js";
6
7
  import {
8
+ bundleRootConfig,
9
+ copyDir,
7
10
  copyGlob,
8
11
  createViteServer,
9
12
  dirExists,
@@ -11,24 +14,31 @@ import {
11
14
  fileExists,
12
15
  isDirectory,
13
16
  isJsFile,
17
+ loadBundledConfig,
14
18
  loadJson,
15
19
  loadRootConfig,
16
20
  makeDir,
17
21
  rmDir,
18
- writeFile
19
- } from "./chunk-J2ANSYAE.js";
22
+ writeFile,
23
+ writeJson
24
+ } from "./chunk-UYHD775U.js";
20
25
  import {
21
26
  configureServerPlugins,
22
27
  getVitePlugins
23
28
  } from "./chunk-QKBMWK5B.js";
24
29
  import {
30
+ RouteTrie,
25
31
  htmlMinify,
26
32
  htmlPretty,
27
33
  isValidTagName,
28
34
  parseTagNames
29
- } from "./chunk-DFBTOMQF.js";
35
+ } from "./chunk-IUQLRDFW.js";
30
36
 
31
- // src/cli/commands/build.ts
37
+ // src/cli/cli.ts
38
+ import { Command } from "commander";
39
+ import { bgGreen, black } from "kleur/colors";
40
+
41
+ // src/cli/build.ts
32
42
  import path3 from "node:path";
33
43
  import { fileURLToPath } from "node:url";
34
44
  import fsExtra from "fs-extra";
@@ -102,10 +112,9 @@ var ElementGraph = class _ElementGraph {
102
112
  }
103
113
  };
104
114
  async function getElements(rootConfig) {
105
- var _a;
106
115
  const rootDir = rootConfig.rootDir;
107
116
  const elementsDirs = getElementsDirs(rootConfig);
108
- const excludePatterns = ((_a = rootConfig.elements) == null ? void 0 : _a.exclude) || [];
117
+ const excludePatterns = rootConfig.elements?.exclude || [];
109
118
  const excludeElement = (moduleId) => {
110
119
  return excludePatterns.some((pattern) => Boolean(moduleId.match(pattern)));
111
120
  };
@@ -130,11 +139,10 @@ async function getElements(rootConfig) {
130
139
  return graph;
131
140
  }
132
141
  function getElementsDirs(rootConfig) {
133
- var _a;
134
142
  const rootDir = rootConfig.rootDir;
135
143
  const workspaceRoot = searchForWorkspaceRoot(rootDir);
136
144
  const elementsDirs = [path.join(rootDir, "elements")];
137
- const elementsInclude = ((_a = rootConfig.elements) == null ? void 0 : _a.include) || [];
145
+ const elementsInclude = rootConfig.elements?.include || [];
138
146
  for (const dirPath of elementsInclude) {
139
147
  const elementsDir = path.resolve(rootDir, dirPath);
140
148
  if (!directoryContains(rootDir, elementsDir)) {
@@ -312,16 +320,15 @@ async function batchAsyncCalls(data, batchSize, asyncFunction) {
312
320
  return result;
313
321
  }
314
322
 
315
- // src/cli/commands/build.ts
323
+ // src/cli/build.ts
316
324
  var __dirname = path3.dirname(fileURLToPath(import.meta.url));
317
325
  async function build(rootProjectDir, options) {
318
- var _a, _b, _c, _d, _e, _f, _g, _h;
319
- const mode = (options == null ? void 0 : options.mode) || "production";
326
+ const mode = options?.mode || "production";
320
327
  process.env.NODE_ENV = mode;
321
328
  const rootDir = path3.resolve(rootProjectDir || process.cwd());
322
329
  const rootConfig = await loadRootConfig(rootDir, { command: "build" });
323
330
  const distDir = path3.join(rootDir, "dist");
324
- const ssrOnly = (options == null ? void 0 : options.ssrOnly) || false;
331
+ const ssrOnly = options?.ssrOnly || false;
325
332
  console.log();
326
333
  console.log(`${dim("\u2503")} project: ${rootDir}`);
327
334
  console.log(`${dim("\u2503")} output: ${distDir}/html`);
@@ -379,7 +386,7 @@ async function build(rootProjectDir, options) {
379
386
  Object.assign(ssrInput, plugin.ssrInput());
380
387
  }
381
388
  });
382
- const noExternalConfig = (_a = viteConfig.ssr) == null ? void 0 : _a.noExternal;
389
+ const noExternalConfig = viteConfig.ssr?.noExternal;
383
390
  const noExternal = [];
384
391
  if (noExternalConfig) {
385
392
  if (Array.isArray(noExternalConfig)) {
@@ -392,9 +399,9 @@ async function build(rootProjectDir, options) {
392
399
  ...baseConfig,
393
400
  publicDir: false,
394
401
  build: {
395
- ...viteConfig == null ? void 0 : viteConfig.build,
402
+ ...viteConfig?.build,
396
403
  rollupOptions: {
397
- ...(_b = viteConfig == null ? void 0 : viteConfig.build) == null ? void 0 : _b.rollupOptions,
404
+ ...viteConfig?.build?.rollupOptions,
398
405
  input: ssrInput,
399
406
  output: {
400
407
  format: "esm",
@@ -410,21 +417,22 @@ async function build(rootProjectDir, options) {
410
417
  target: "esnext",
411
418
  minify: false,
412
419
  modulePreload: { polyfill: false },
413
- reportCompressedSize: false
420
+ reportCompressedSize: false,
421
+ sourcemap: "inline"
414
422
  },
415
423
  ssr: {
416
424
  ...viteConfig.ssr,
417
425
  target: "node",
418
- noExternal: ["@blinkk/root", ...noExternal]
426
+ noExternal: ["@blinkk/root", "@blinkk/root-cms/richtext", ...noExternal]
419
427
  }
420
428
  });
421
429
  await viteBuild({
422
430
  ...baseConfig,
423
431
  publicDir: false,
424
432
  build: {
425
- ...viteConfig == null ? void 0 : viteConfig.build,
433
+ ...viteConfig?.build,
426
434
  rollupOptions: {
427
- ...(_c = viteConfig == null ? void 0 : viteConfig.build) == null ? void 0 : _c.rollupOptions,
435
+ ...viteConfig?.build?.rollupOptions,
428
436
  input: [...routeFiles],
429
437
  output: {
430
438
  format: "esm",
@@ -432,12 +440,12 @@ async function build(rootProjectDir, options) {
432
440
  assetFileNames: "assets/[name].[hash][extname]",
433
441
  chunkFileNames: "chunks/[hash].min.js",
434
442
  sanitizeFileName,
435
- ...(_e = (_d = viteConfig == null ? void 0 : viteConfig.build) == null ? void 0 : _d.rollupOptions) == null ? void 0 : _e.output
443
+ ...viteConfig?.build?.rollupOptions?.output
436
444
  }
437
445
  },
438
- outDir: path3.join(distDir, "routes"),
446
+ outDir: path3.join(distDir, ".build/routes"),
439
447
  ssr: true,
440
- ssrManifest: true,
448
+ ssrManifest: false,
441
449
  ssrEmitAssets: true,
442
450
  manifest: true,
443
451
  cssCodeSplit: true,
@@ -453,9 +461,9 @@ async function build(rootProjectDir, options) {
453
461
  ...baseConfig,
454
462
  publicDir: false,
455
463
  build: {
456
- ...viteConfig == null ? void 0 : viteConfig.build,
464
+ ...viteConfig?.build,
457
465
  rollupOptions: {
458
- ...(_f = viteConfig == null ? void 0 : viteConfig.build) == null ? void 0 : _f.rollupOptions,
466
+ ...viteConfig?.build?.rollupOptions,
459
467
  input: [...elements, ...bundleScripts],
460
468
  output: {
461
469
  format: "esm",
@@ -463,10 +471,10 @@ async function build(rootProjectDir, options) {
463
471
  assetFileNames: "assets/[name].[hash][extname]",
464
472
  chunkFileNames: "chunks/[hash].min.js",
465
473
  sanitizeFileName,
466
- ...(_h = (_g = viteConfig == null ? void 0 : viteConfig.build) == null ? void 0 : _g.rollupOptions) == null ? void 0 : _h.output
474
+ ...viteConfig?.build?.rollupOptions?.output
467
475
  }
468
476
  },
469
- outDir: path3.join(distDir, "client"),
477
+ outDir: path3.join(distDir, ".build/client"),
470
478
  ssr: false,
471
479
  ssrManifest: false,
472
480
  manifest: true,
@@ -478,18 +486,22 @@ async function build(rootProjectDir, options) {
478
486
  }
479
487
  });
480
488
  } else {
481
- await writeFile(path3.join(distDir, "client/manifest.json"), "{}");
489
+ await writeFile(
490
+ path3.join(distDir, ".build/client/.vite/manifest.json"),
491
+ "{}"
492
+ );
482
493
  }
494
+ await bundleRootConfig(rootDir, path3.join(distDir, "root.config.js"));
483
495
  await copyGlob(
484
496
  "**/*.css",
485
- path3.join(distDir, "routes"),
486
- path3.join(distDir, "client")
497
+ path3.join(distDir, ".build/routes"),
498
+ path3.join(distDir, ".build/client")
487
499
  );
488
500
  const routesManifest = await loadJson(
489
- path3.join(distDir, "routes/manifest.json")
501
+ path3.join(distDir, ".build/routes/.vite/manifest.json")
490
502
  );
491
503
  const clientManifest = await loadJson(
492
- path3.join(distDir, "client/manifest.json")
504
+ path3.join(distDir, ".build/client/.vite/manifest.json")
493
505
  );
494
506
  function collectRouteCss(asset, cssDeps, visited) {
495
507
  if (!asset || !asset.file || visited.has(asset.file)) {
@@ -525,12 +537,12 @@ async function build(rootProjectDir, options) {
525
537
  );
526
538
  const rootManifest = assetMap.toJson();
527
539
  await writeFile(
528
- path3.join(distDir, "client/root-manifest.json"),
540
+ path3.join(distDir, ".root/manifest.json"),
529
541
  JSON.stringify(rootManifest, null, 2)
530
542
  );
531
543
  const elementGraphJson = elementGraph.toJson();
532
544
  await writeFile(
533
- path3.join(distDir, "client/root-element-graph.json"),
545
+ path3.join(distDir, ".root/elements.json"),
534
546
  JSON.stringify(elementGraphJson, null, 2)
535
547
  );
536
548
  const buildDir = path3.join(distDir, "html");
@@ -540,25 +552,37 @@ async function build(rootProjectDir, options) {
540
552
  } else {
541
553
  await makeDir(buildDir);
542
554
  }
555
+ const seenAssets = /* @__PURE__ */ new Set();
556
+ async function copyAssetToDistHtml(assetUrl) {
557
+ if (seenAssets.has(assetUrl)) {
558
+ return;
559
+ }
560
+ seenAssets.add(assetUrl);
561
+ const assetRelPath = assetUrl.slice(1);
562
+ const assetFrom = path3.join(distDir, ".build/client", assetRelPath);
563
+ const assetTo = path3.join(buildDir, assetRelPath);
564
+ if (!await fileExists(assetFrom)) {
565
+ console.log(`${assetFrom} does not exist`);
566
+ return;
567
+ }
568
+ await fsExtra.copy(assetFrom, assetTo);
569
+ printFileOutput(fileSize(assetTo), "dist/html/", assetRelPath);
570
+ }
543
571
  console.log("\njs/css output:");
544
572
  await Promise.all(
545
573
  Object.keys(rootManifest).map(async (src) => {
574
+ const assetData = rootManifest[src];
546
575
  if (isRouteFile(src)) {
576
+ const importedCss = assetData.importedCss || [];
577
+ for (const cssAssetUrl of importedCss) {
578
+ await copyAssetToDistHtml(cssAssetUrl);
579
+ }
547
580
  return;
548
581
  }
549
- const assetData = rootManifest[src];
550
582
  if (!assetData.assetUrl) {
551
583
  return;
552
584
  }
553
- const assetRelPath = assetData.assetUrl.slice(1);
554
- const assetFrom = path3.join(distDir, "client", assetRelPath);
555
- const assetTo = path3.join(buildDir, assetRelPath);
556
- if (!await fileExists(assetFrom)) {
557
- console.log(`${assetFrom} does not exist`);
558
- return;
559
- }
560
- await fsExtra.copy(assetFrom, assetTo);
561
- printFileOutput(fileSize(assetTo), "dist/html/", assetRelPath);
585
+ await copyAssetToDistHtml(assetData.assetUrl);
562
586
  })
563
587
  );
564
588
  if (!ssrOnly) {
@@ -566,7 +590,7 @@ async function build(rootProjectDir, options) {
566
590
  const renderer = new render.Renderer(rootConfig, { assetMap, elementGraph });
567
591
  const sitemap = await renderer.getSitemap();
568
592
  console.log("\nhtml output:");
569
- const batchSize = Number((options == null ? void 0 : options.concurrency) || 10);
593
+ const batchSize = Number(options?.concurrency || 10);
570
594
  await batchAsyncCalls(Object.keys(sitemap), batchSize, async (urlPath) => {
571
595
  const { route, params } = sitemap[urlPath];
572
596
  try {
@@ -651,8 +675,164 @@ function formatParams(params) {
651
675
  }).join("\n");
652
676
  }
653
677
 
654
- // src/cli/commands/dev.ts
655
- import path5 from "node:path";
678
+ // src/cli/create-package.ts
679
+ import { promises as fs3 } from "node:fs";
680
+ import path4 from "node:path";
681
+ import { build as esbuild } from "esbuild";
682
+ async function createPackage(rootProjectDir, options) {
683
+ const mode = options?.mode || "production";
684
+ process.env.NODE_ENV = mode;
685
+ const rootDir = path4.resolve(rootProjectDir || process.cwd());
686
+ const distDir = path4.join(rootDir, "dist");
687
+ const target = options?.target || await getDefaultTarget(rootDir);
688
+ const outDir = path4.resolve(options?.out || target || "out");
689
+ await build(rootProjectDir, { ssrOnly: true, mode });
690
+ await rmDir(outDir);
691
+ await makeDir(outDir);
692
+ await copyDir(distDir, path4.resolve(outDir, "dist"));
693
+ const collectionsDir = path4.resolve(rootDir, "collections");
694
+ if (await dirExists(collectionsDir)) {
695
+ await copyDir(collectionsDir, path4.join(outDir, "collections"));
696
+ }
697
+ const packageJson = await generatePackageJson(rootDir);
698
+ if (target === "appengine") {
699
+ await onAppEngine({ rootDir, packageJson, outDir });
700
+ } else if (target === "firebase") {
701
+ await onFirebase({ rootDir, packageJson, outDir });
702
+ }
703
+ await writeJson(path4.resolve(outDir, "package.json"), packageJson);
704
+ console.log("done!");
705
+ console.log(`saved package to ${outDir}`);
706
+ }
707
+ async function getDefaultTarget(rootDir) {
708
+ const firebaseConfigPath = path4.resolve(rootDir, "firebase.json");
709
+ if (await fileExists(firebaseConfigPath)) {
710
+ return "firebase";
711
+ }
712
+ const appEngineConfigPath = path4.resolve(rootDir, "app.yaml");
713
+ if (await fileExists(appEngineConfigPath)) {
714
+ return "appengine";
715
+ }
716
+ return null;
717
+ }
718
+ async function generatePackageJson(rootDir) {
719
+ const packageJson = await loadJson(
720
+ path4.resolve(rootDir, "package.json")
721
+ );
722
+ if (packageJson.peerDependencies) {
723
+ await updatePeerDepsFromWorkspace(rootDir, packageJson);
724
+ }
725
+ return packageJson;
726
+ }
727
+ async function updatePeerDepsFromWorkspace(rootDir, packageJson) {
728
+ const requiredPeerDeps = getRequiredPeerDeps(packageJson);
729
+ if (requiredPeerDeps.length === 0) {
730
+ return;
731
+ }
732
+ const workspaceRoot = await findWorkspaceRoot(rootDir);
733
+ if (!workspaceRoot) {
734
+ return;
735
+ }
736
+ const workspacePackageJsonPath = path4.resolve(workspaceRoot, "package.json");
737
+ const workspacePackageJson = await loadJson(
738
+ workspacePackageJsonPath
739
+ );
740
+ const workspaceDeps = workspacePackageJson.dependencies || {};
741
+ function setDep(name, value) {
742
+ if (!packageJson.dependencies) {
743
+ packageJson.dependencies = {};
744
+ }
745
+ packageJson.dependencies[name] = value;
746
+ }
747
+ for (const peerDep of requiredPeerDeps) {
748
+ const workspaceDepVersion = workspaceDeps[peerDep];
749
+ if (workspaceDepVersion) {
750
+ setDep(peerDep, workspaceDepVersion);
751
+ } else {
752
+ console.warn(
753
+ `could not find peer dep "${peerDep}" in workspace "${workspacePackageJsonPath}"`
754
+ );
755
+ }
756
+ }
757
+ }
758
+ async function findWorkspaceRoot(rootDir) {
759
+ const parentDir = path4.dirname(rootDir);
760
+ if (parentDir === "/") {
761
+ return null;
762
+ }
763
+ const pnpmWorkspaceFile = path4.resolve(parentDir, "pnpm-workspace.yaml");
764
+ if (await fileExists(pnpmWorkspaceFile)) {
765
+ return parentDir;
766
+ }
767
+ const packageJsonPath = path4.resolve(parentDir, "package.json");
768
+ if (await fileExists(packageJsonPath)) {
769
+ const parentPackageJson = await loadJson(packageJsonPath);
770
+ if (parentPackageJson && parentPackageJson.workspaces) {
771
+ return parentDir;
772
+ }
773
+ }
774
+ return findWorkspaceRoot(parentDir);
775
+ }
776
+ function getRequiredPeerDeps(packageJson) {
777
+ const requiredPeerDeps = [];
778
+ const peerDeps = packageJson.peerDependencies || {};
779
+ const peerDepsMeta = packageJson.peerDependenciesMeta || {};
780
+ for (const key in peerDeps) {
781
+ const meta = peerDepsMeta[key];
782
+ if (!meta?.optional) {
783
+ requiredPeerDeps.push(key);
784
+ }
785
+ }
786
+ return requiredPeerDeps;
787
+ }
788
+ async function onAppEngine(options) {
789
+ const { rootDir, outDir } = options;
790
+ const configPath = path4.resolve(rootDir, "app.yaml");
791
+ if (await fileExists(configPath)) {
792
+ await fs3.copyFile(configPath, path4.resolve(outDir, "app.yaml"));
793
+ }
794
+ }
795
+ async function onFirebase(options) {
796
+ const { rootDir, outDir } = options;
797
+ const outBasename = path4.basename(outDir);
798
+ if (outBasename === "functions") {
799
+ const indexTsFile = path4.resolve(rootDir, "index.ts");
800
+ if (await fileExists(indexTsFile)) {
801
+ await bundleTsFile(indexTsFile, path4.resolve(outDir, "index.js"));
802
+ }
803
+ }
804
+ }
805
+ async function bundleTsFile(srcPath, outPath) {
806
+ await esbuild({
807
+ entryPoints: [srcPath],
808
+ bundle: true,
809
+ minify: true,
810
+ platform: "node",
811
+ outfile: outPath,
812
+ sourcemap: "inline",
813
+ metafile: true,
814
+ format: "esm",
815
+ plugins: [
816
+ {
817
+ name: "externalize-deps",
818
+ setup(build2) {
819
+ build2.onResolve({ filter: /.*/ }, (args) => {
820
+ const id = args.path;
821
+ if (id[0] !== "." && !path4.isAbsolute(id)) {
822
+ return {
823
+ external: true
824
+ };
825
+ }
826
+ return null;
827
+ });
828
+ }
829
+ }
830
+ ]
831
+ });
832
+ }
833
+
834
+ // src/cli/dev.ts
835
+ import path6 from "node:path";
656
836
  import { fileURLToPath as fileURLToPath2 } from "node:url";
657
837
  import cookieParser from "cookie-parser";
658
838
  import { default as express } from "express";
@@ -683,8 +863,53 @@ var Hooks = class {
683
863
  }
684
864
  };
685
865
 
866
+ // src/middleware/redirects.ts
867
+ function redirectsMiddleware(options) {
868
+ const routeTrie = new RouteTrie();
869
+ const redirects = options.redirects || [];
870
+ redirects.forEach((redirect) => {
871
+ if (!verifyRedirectConfig(redirect)) {
872
+ console.warn("ignoring invalid redirect config:", redirect);
873
+ return;
874
+ }
875
+ routeTrie.add(redirect.source, redirect);
876
+ });
877
+ return (req, res, next) => {
878
+ const [redirect, params] = routeTrie.get(req.path);
879
+ if (redirect) {
880
+ const destination = replaceParams(redirect.destination, params);
881
+ const code = redirect.type || 302;
882
+ res.redirect(code, destination);
883
+ return;
884
+ }
885
+ next();
886
+ };
887
+ }
888
+ function verifyRedirectConfig(redirect) {
889
+ if (!redirect.source) {
890
+ return false;
891
+ }
892
+ if (!redirect.destination) {
893
+ return false;
894
+ }
895
+ return true;
896
+ }
897
+ function replaceParams(urlPathFormat, params) {
898
+ const urlPath = urlPathFormat.replaceAll(
899
+ /\[\[?(\.\.\.)?([\w\-_]*)\]?\]/g,
900
+ (match, _wildcard, key) => {
901
+ const val = params[key];
902
+ if (!val) {
903
+ throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);
904
+ }
905
+ return val;
906
+ }
907
+ );
908
+ return urlPath;
909
+ }
910
+
686
911
  // src/render/asset-map/dev-asset-map.ts
687
- import path4 from "node:path";
912
+ import path5 from "node:path";
688
913
  import { searchForWorkspaceRoot as searchForWorkspaceRoot2 } from "vite";
689
914
  var DevServerAssetMap = class {
690
915
  constructor(rootConfig, moduleGraph) {
@@ -692,7 +917,7 @@ var DevServerAssetMap = class {
692
917
  this.moduleGraph = moduleGraph;
693
918
  }
694
919
  async get(src) {
695
- const file = path4.resolve(this.rootConfig.rootDir, src);
920
+ const file = path5.resolve(this.rootConfig.rootDir, src);
696
921
  const viteModules = this.moduleGraph.getModulesByFile(file);
697
922
  if (viteModules && viteModules.size > 0) {
698
923
  const [viteModule] = viteModules;
@@ -724,7 +949,7 @@ var DevServerAssetMap = class {
724
949
  return null;
725
950
  }
726
951
  filePathToSrc(file) {
727
- return path4.relative(this.rootConfig.rootDir, file);
952
+ return path5.relative(this.rootConfig.rootDir, file);
728
953
  }
729
954
  };
730
955
  var DevServerAsset = class _DevServerAsset {
@@ -761,7 +986,7 @@ var DevServerAsset = class _DevServerAsset {
761
986
  return;
762
987
  }
763
988
  visited.add(asset.moduleId);
764
- const parts = path4.parse(asset.assetUrl);
989
+ const parts = path5.parse(asset.assetUrl);
765
990
  if ([".js", ".jsx", ".ts", ".tsx"].includes(parts.ext) && asset.moduleId.includes("/elements/")) {
766
991
  urls.add(asset.assetUrl);
767
992
  }
@@ -788,7 +1013,7 @@ var DevServerAsset = class _DevServerAsset {
788
1013
  }
789
1014
  visited.add(asset.assetUrl);
790
1015
  if (asset.src.endsWith(".scss")) {
791
- const parts = path4.parse(asset.src);
1016
+ const parts = path5.parse(asset.src);
792
1017
  if (!parts.name.startsWith("_")) {
793
1018
  urls.add(asset.assetUrl);
794
1019
  }
@@ -854,47 +1079,63 @@ function randString(len) {
854
1079
  return result.join("");
855
1080
  }
856
1081
 
857
- // src/cli/commands/dev.ts
858
- var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
1082
+ // src/cli/dev.ts
1083
+ var __dirname2 = path6.dirname(fileURLToPath2(import.meta.url));
859
1084
  async function dev(rootProjectDir, options) {
860
1085
  process.env.NODE_ENV = "development";
861
- const rootDir = path5.resolve(rootProjectDir || process.cwd());
1086
+ const rootDir = path6.resolve(rootProjectDir || process.cwd());
862
1087
  const defaultPort = parseInt(process.env.PORT || "4007");
863
- const host = (options == null ? void 0 : options.host) || "localhost";
1088
+ const host = options?.host || "localhost";
864
1089
  const port = await findOpenPort(defaultPort, defaultPort + 10);
1090
+ const server = await createDevServer({ rootDir, port });
1091
+ const rootConfig = server.get("rootConfig");
1092
+ const basePath = rootConfig.base || "";
865
1093
  console.log();
866
1094
  console.log(`${dim2("\u2503")} project: ${rootDir}`);
867
- console.log(`${dim2("\u2503")} server: http://${host}:${port}`);
1095
+ console.log(`${dim2("\u2503")} server: http://${host}:${port}${basePath}`);
1096
+ if (testCmsEnabled(rootConfig)) {
1097
+ console.log(`${dim2("\u2503")} cms: http://${host}:${port}/cms/`);
1098
+ }
868
1099
  console.log(`${dim2("\u2503")} mode: development`);
869
1100
  console.log();
870
- const server = await createDevServer({ rootDir, port });
871
1101
  server.listen(port, host);
872
1102
  }
873
1103
  async function createDevServer(options) {
874
- var _a;
875
- const rootDir = path5.resolve((options == null ? void 0 : options.rootDir) || process.cwd());
1104
+ const rootDir = path6.resolve(options?.rootDir || process.cwd());
876
1105
  const rootConfig = await loadRootConfig(rootDir, { command: "dev" });
877
- const port = options == null ? void 0 : options.port;
1106
+ const port = options?.port;
878
1107
  const server = express();
1108
+ server.set("rootConfig", rootConfig);
879
1109
  server.disable("x-powered-by");
1110
+ const { viteServer, viteMiddleware } = await createViteMiddleware({
1111
+ rootConfig,
1112
+ port
1113
+ });
880
1114
  server.use(rootProjectMiddleware({ rootConfig }));
881
- server.use(await viteServerMiddleware({ rootConfig, port }));
1115
+ server.use(viteMiddleware);
882
1116
  server.use(hooksMiddleware());
883
- const sessionCookieSecret = ((_a = rootConfig.server) == null ? void 0 : _a.sessionCookieSecret) || randString(36);
1117
+ const sessionCookieSecret = rootConfig.server?.sessionCookieSecret || randString(36);
884
1118
  server.use(cookieParser(sessionCookieSecret));
885
1119
  server.use(sessionMiddleware());
886
1120
  const plugins = rootConfig.plugins || [];
887
1121
  await configureServerPlugins(
888
1122
  server,
889
1123
  async () => {
890
- var _a2;
891
- const userMiddlewares = ((_a2 = rootConfig.server) == null ? void 0 : _a2.middlewares) || [];
1124
+ const userMiddlewares = rootConfig.server?.middlewares || [];
892
1125
  for (const middleware of userMiddlewares) {
893
1126
  server.use(middleware);
894
1127
  }
895
- const publicDir = path5.join(rootDir, "public");
1128
+ if (rootConfig.server?.redirects) {
1129
+ server.use(
1130
+ redirectsMiddleware({ redirects: rootConfig.server.redirects })
1131
+ );
1132
+ }
1133
+ if (rootConfig.server?.headers) {
1134
+ server.use(headersMiddleware({ rootConfig }));
1135
+ }
1136
+ const publicDir = path6.join(rootDir, "public");
896
1137
  if (await dirExists(publicDir)) {
897
- server.use(sirv(publicDir, { dev: false }));
1138
+ server.use(rootPublicDirMiddleware({ publicDir, viteServer }));
898
1139
  }
899
1140
  server.use(trailingSlashMiddleware({ rootConfig }));
900
1141
  server.use(rootDevServerMiddleware());
@@ -906,7 +1147,7 @@ async function createDevServer(options) {
906
1147
  );
907
1148
  return server;
908
1149
  }
909
- async function viteServerMiddleware(options) {
1150
+ async function createViteMiddleware(options) {
910
1151
  const rootConfig = options.rootConfig;
911
1152
  const rootDir = rootConfig.rootDir;
912
1153
  let elementGraph = await getElements(rootConfig);
@@ -914,10 +1155,10 @@ async function viteServerMiddleware(options) {
914
1155
  return sourceFile.relPath;
915
1156
  });
916
1157
  const bundleScripts = [];
917
- if (await isDirectory(path5.join(rootDir, "bundles"))) {
1158
+ if (await isDirectory(path6.join(rootDir, "bundles"))) {
918
1159
  const bundleFiles = await glob3("bundles/*", { cwd: rootDir });
919
1160
  bundleFiles.forEach((file) => {
920
- const parts = path5.parse(file);
1161
+ const parts = path6.parse(file);
921
1162
  if (isJsFile(parts.base)) {
922
1163
  bundleScripts.push(file);
923
1164
  }
@@ -929,7 +1170,7 @@ async function viteServerMiddleware(options) {
929
1170
  optimizeDeps
930
1171
  });
931
1172
  function isInElementsDir(changedFilePath) {
932
- const filePath = path5.resolve(changedFilePath);
1173
+ const filePath = path6.resolve(changedFilePath);
933
1174
  const elementsDirs = getElementsDirs(rootConfig);
934
1175
  return elementsDirs.some((dirPath) => filePath.startsWith(dirPath));
935
1176
  }
@@ -945,10 +1186,10 @@ async function viteServerMiddleware(options) {
945
1186
  console.log(`element deleted: ${filePath}`);
946
1187
  }
947
1188
  });
948
- return async (req, res, next) => {
1189
+ const viteMiddleware = async (req, res, next) => {
949
1190
  try {
950
1191
  req.viteServer = viteServer;
951
- const renderModulePath = path5.resolve(__dirname2, "./render.js");
1192
+ const renderModulePath = path6.resolve(__dirname2, "./render.js");
952
1193
  const render = await viteServer.ssrLoadModule(
953
1194
  renderModulePath
954
1195
  );
@@ -962,6 +1203,28 @@ async function viteServerMiddleware(options) {
962
1203
  next(e);
963
1204
  }
964
1205
  };
1206
+ return { viteServer, viteMiddleware };
1207
+ }
1208
+ function rootPublicDirMiddleware(options) {
1209
+ const publicDir = options.publicDir;
1210
+ const sirvOptions = { dev: false };
1211
+ let handler = sirv(publicDir, sirvOptions);
1212
+ const reloadPublicDirCache = debounce(() => {
1213
+ handler = sirv(publicDir, sirvOptions);
1214
+ }, 1e3);
1215
+ function isInPublicDir(changedFilePath) {
1216
+ const filePath = path6.resolve(changedFilePath);
1217
+ return filePath.startsWith(publicDir);
1218
+ }
1219
+ const watcher = options.viteServer.watcher;
1220
+ watcher.on("all", (event, filepath) => {
1221
+ if (isInPublicDir(filepath)) {
1222
+ reloadPublicDirCache();
1223
+ }
1224
+ });
1225
+ return (req, res, next) => {
1226
+ handler(req, res, next);
1227
+ };
965
1228
  }
966
1229
  function rootDevServerMiddleware() {
967
1230
  return async (req, res, next) => {
@@ -980,7 +1243,7 @@ function rootDevServer404Middleware() {
980
1243
  console.error(`\u2753 404 ${req.originalUrl}`);
981
1244
  if (req.renderer) {
982
1245
  const url = req.path;
983
- const ext = path5.extname(url);
1246
+ const ext = path6.extname(url);
984
1247
  if (!ext) {
985
1248
  const renderer = req.renderer;
986
1249
  const data = await renderer.renderDevServer404(req);
@@ -998,7 +1261,7 @@ function rootDevServer500Middleware() {
998
1261
  console.error(String(err.stack || err));
999
1262
  if (req.renderer) {
1000
1263
  const url = req.path;
1001
- const ext = path5.extname(url);
1264
+ const ext = path6.extname(url);
1002
1265
  if (!ext) {
1003
1266
  const renderer = req.renderer;
1004
1267
  const data = await renderer.renderDevServer500(req, err);
@@ -1010,9 +1273,20 @@ function rootDevServer500Middleware() {
1010
1273
  next(err);
1011
1274
  };
1012
1275
  }
1276
+ function testCmsEnabled(rootConfig) {
1277
+ const plugins = rootConfig.plugins || [];
1278
+ return Boolean(plugins.find((plugin) => plugin.name === "root-cms"));
1279
+ }
1280
+ function debounce(fn, timeout) {
1281
+ let timer;
1282
+ return (...args) => {
1283
+ clearTimeout(timer);
1284
+ timer = setTimeout(() => fn(...args), timeout);
1285
+ };
1286
+ }
1013
1287
 
1014
- // src/cli/commands/preview.ts
1015
- import path6 from "node:path";
1288
+ // src/cli/preview.ts
1289
+ import path7 from "node:path";
1016
1290
  import compression from "compression";
1017
1291
  import cookieParser2 from "cookie-parser";
1018
1292
  import { default as express2 } from "express";
@@ -1020,10 +1294,10 @@ import { dim as dim3 } from "kleur/colors";
1020
1294
  import sirv2 from "sirv";
1021
1295
  async function preview(rootProjectDir, options) {
1022
1296
  process.env.NODE_ENV = "development";
1023
- const rootDir = path6.resolve(rootProjectDir || process.cwd());
1297
+ const rootDir = path7.resolve(rootProjectDir || process.cwd());
1024
1298
  const server = await createPreviewServer({ rootDir });
1025
1299
  const port = parseInt(process.env.PORT || "4007");
1026
- const host = (options == null ? void 0 : options.host) || "localhost";
1300
+ const host = options?.host || "localhost";
1027
1301
  console.log();
1028
1302
  console.log(`${dim3("\u2503")} project: ${rootDir}`);
1029
1303
  console.log(`${dim3("\u2503")} server: http://${host}:${port}`);
@@ -1032,29 +1306,35 @@ async function preview(rootProjectDir, options) {
1032
1306
  server.listen(port, host);
1033
1307
  }
1034
1308
  async function createPreviewServer(options) {
1035
- var _a;
1036
1309
  const rootDir = options.rootDir;
1037
- const rootConfig = await loadRootConfig(rootDir, { command: "preview" });
1038
- const distDir = path6.join(rootDir, "dist");
1310
+ const rootConfig = await loadBundledConfig(rootDir, { command: "preview" });
1311
+ const distDir = path7.join(rootDir, "dist");
1039
1312
  const server = express2();
1040
1313
  server.disable("x-powered-by");
1041
1314
  server.use(compression());
1042
1315
  server.use(rootProjectMiddleware({ rootConfig }));
1043
1316
  server.use(await rootPreviewRendererMiddleware({ rootConfig, distDir }));
1044
1317
  server.use(hooksMiddleware());
1045
- const sessionCookieSecret = ((_a = rootConfig.server) == null ? void 0 : _a.sessionCookieSecret) || randString(36);
1318
+ const sessionCookieSecret = rootConfig.server?.sessionCookieSecret || randString(36);
1046
1319
  server.use(cookieParser2(sessionCookieSecret));
1047
1320
  server.use(sessionMiddleware());
1048
1321
  const plugins = rootConfig.plugins || [];
1049
1322
  configureServerPlugins(
1050
1323
  server,
1051
1324
  async () => {
1052
- var _a2;
1053
- const userMiddlewares = ((_a2 = rootConfig.server) == null ? void 0 : _a2.middlewares) || [];
1325
+ const userMiddlewares = rootConfig.server?.middlewares || [];
1054
1326
  userMiddlewares.forEach((middleware) => {
1055
1327
  server.use(middleware);
1056
1328
  });
1057
- const publicDir = path6.join(distDir, "html");
1329
+ if (rootConfig.server?.redirects) {
1330
+ server.use(
1331
+ redirectsMiddleware({ redirects: rootConfig.server.redirects })
1332
+ );
1333
+ }
1334
+ if (rootConfig.server?.headers) {
1335
+ server.use(headersMiddleware({ rootConfig }));
1336
+ }
1337
+ const publicDir = path7.join(distDir, "html");
1058
1338
  server.use(sirv2(publicDir, { dev: false }));
1059
1339
  server.use(trailingSlashMiddleware({ rootConfig }));
1060
1340
  server.use(rootPreviewServerMiddleware());
@@ -1068,20 +1348,17 @@ async function createPreviewServer(options) {
1068
1348
  }
1069
1349
  async function rootPreviewRendererMiddleware(options) {
1070
1350
  const { distDir, rootConfig } = options;
1071
- const render = await import(path6.join(distDir, "server/render.js"));
1072
- const manifestPath = path6.join(distDir, "client/root-manifest.json");
1351
+ const render = await import(path7.join(distDir, "server/render.js"));
1352
+ const manifestPath = path7.join(distDir, ".root/manifest.json");
1073
1353
  if (!await fileExists(manifestPath)) {
1074
1354
  throw new Error(
1075
1355
  `could not find ${manifestPath}. run \`root build\` before \`root preview\`.`
1076
1356
  );
1077
1357
  }
1078
- const elementGraphJsonPath = path6.join(
1079
- distDir,
1080
- "client/root-element-graph.json"
1081
- );
1358
+ const elementGraphJsonPath = path7.join(distDir, ".root/elements.json");
1082
1359
  if (!await fileExists(elementGraphJsonPath)) {
1083
1360
  throw new Error(
1084
- `could not find ${elementGraphJsonPath}. run \`root build\` before \`root start\`.`
1361
+ `could not find ${elementGraphJsonPath}. run \`root build\` before \`root preview\`.`
1085
1362
  );
1086
1363
  }
1087
1364
  const rootManifest = await loadJson(manifestPath);
@@ -1103,7 +1380,7 @@ function rootPreviewServerMiddleware() {
1103
1380
  try {
1104
1381
  console.error(`error rendering ${req.originalUrl}`);
1105
1382
  console.error(e.stack || e);
1106
- const { html } = await renderer.renderError(e);
1383
+ const { html } = await renderer.renderDevServer500(req, e);
1107
1384
  res.status(500).set({ "Content-Type": "text/html" }).end(html);
1108
1385
  } catch (e2) {
1109
1386
  console.error("failed to render custom error");
@@ -1118,7 +1395,7 @@ function rootPreviewServer404Middleware() {
1118
1395
  console.error(`\u2753 404 ${req.originalUrl}`);
1119
1396
  if (req.renderer) {
1120
1397
  const url = req.path;
1121
- const ext = path6.extname(url);
1398
+ const ext = path7.extname(url);
1122
1399
  if (!ext) {
1123
1400
  const renderer = req.renderer;
1124
1401
  const data = await renderer.render404({ currentPath: url });
@@ -1136,7 +1413,7 @@ function rootPreviewServer500Middleware() {
1136
1413
  console.error(String(err.stack || err));
1137
1414
  if (req.renderer) {
1138
1415
  const url = req.path;
1139
- const ext = path6.extname(url);
1416
+ const ext = path7.extname(url);
1140
1417
  if (!ext) {
1141
1418
  const renderer = req.renderer;
1142
1419
  const data = await renderer.renderDevServer500(req, err);
@@ -1149,8 +1426,8 @@ function rootPreviewServer500Middleware() {
1149
1426
  };
1150
1427
  }
1151
1428
 
1152
- // src/cli/commands/start.ts
1153
- import path7 from "node:path";
1429
+ // src/cli/start.ts
1430
+ import path8 from "node:path";
1154
1431
  import compression2 from "compression";
1155
1432
  import cookieParser3 from "cookie-parser";
1156
1433
  import { default as express3 } from "express";
@@ -1158,10 +1435,10 @@ import { dim as dim4 } from "kleur/colors";
1158
1435
  import sirv3 from "sirv";
1159
1436
  async function start(rootProjectDir, options) {
1160
1437
  process.env.NODE_ENV = "production";
1161
- const rootDir = path7.resolve(rootProjectDir || process.cwd());
1438
+ const rootDir = path8.resolve(rootProjectDir || process.cwd());
1162
1439
  const server = await createProdServer({ rootDir });
1163
1440
  const port = parseInt(process.env.PORT || "4007");
1164
- const host = (options == null ? void 0 : options.host) || "localhost";
1441
+ const host = options?.host || "localhost";
1165
1442
  console.log();
1166
1443
  console.log(`${dim4("\u2503")} project: ${rootDir}`);
1167
1444
  console.log(`${dim4("\u2503")} server: http://${host}:${port}`);
@@ -1170,29 +1447,35 @@ async function start(rootProjectDir, options) {
1170
1447
  server.listen(port, host);
1171
1448
  }
1172
1449
  async function createProdServer(options) {
1173
- var _a;
1174
1450
  const rootDir = options.rootDir;
1175
- const rootConfig = await loadRootConfig(rootDir, { command: "start" });
1176
- const distDir = path7.join(rootDir, "dist");
1451
+ const rootConfig = await loadBundledConfig(rootDir, { command: "start" });
1452
+ const distDir = path8.join(rootDir, "dist");
1177
1453
  const server = express3();
1178
1454
  server.disable("x-powered-by");
1179
1455
  server.use(compression2());
1180
1456
  server.use(rootProjectMiddleware({ rootConfig }));
1181
1457
  server.use(await rootProdRendererMiddleware({ rootConfig, distDir }));
1182
1458
  server.use(hooksMiddleware());
1183
- const sessionCookieSecret = ((_a = rootConfig.server) == null ? void 0 : _a.sessionCookieSecret) || randString(36);
1459
+ const sessionCookieSecret = rootConfig.server?.sessionCookieSecret || randString(36);
1184
1460
  server.use(cookieParser3(sessionCookieSecret));
1185
1461
  server.use(sessionMiddleware());
1186
1462
  const plugins = rootConfig.plugins || [];
1187
1463
  configureServerPlugins(
1188
1464
  server,
1189
1465
  async () => {
1190
- var _a2;
1191
- const userMiddlewares = ((_a2 = rootConfig.server) == null ? void 0 : _a2.middlewares) || [];
1466
+ const userMiddlewares = rootConfig.server?.middlewares || [];
1192
1467
  userMiddlewares.forEach((middleware) => {
1193
1468
  server.use(middleware);
1194
1469
  });
1195
- const publicDir = path7.join(distDir, "html");
1470
+ if (rootConfig.server?.redirects) {
1471
+ server.use(
1472
+ redirectsMiddleware({ redirects: rootConfig.server.redirects })
1473
+ );
1474
+ }
1475
+ if (rootConfig.server?.headers) {
1476
+ server.use(headersMiddleware({ rootConfig }));
1477
+ }
1478
+ const publicDir = path8.join(distDir, "html");
1196
1479
  server.use(sirv3(publicDir, { dev: false }));
1197
1480
  server.use(trailingSlashMiddleware({ rootConfig }));
1198
1481
  server.use(rootProdServerMiddleware());
@@ -1206,17 +1489,14 @@ async function createProdServer(options) {
1206
1489
  }
1207
1490
  async function rootProdRendererMiddleware(options) {
1208
1491
  const { distDir, rootConfig } = options;
1209
- const render = await import(path7.join(distDir, "server/render.js"));
1210
- const manifestPath = path7.join(distDir, "client/root-manifest.json");
1492
+ const render = await import(path8.join(distDir, "server/render.js"));
1493
+ const manifestPath = path8.join(distDir, ".root/manifest.json");
1211
1494
  if (!await fileExists(manifestPath)) {
1212
1495
  throw new Error(
1213
1496
  `could not find ${manifestPath}. run \`root build\` before \`root start\`.`
1214
1497
  );
1215
1498
  }
1216
- const elementGraphJsonPath = path7.join(
1217
- distDir,
1218
- "client/root-element-graph.json"
1219
- );
1499
+ const elementGraphJsonPath = path8.join(distDir, ".root/elements.json");
1220
1500
  if (!await fileExists(elementGraphJsonPath)) {
1221
1501
  throw new Error(
1222
1502
  `could not find ${elementGraphJsonPath}. run \`root build\` before \`root start\`.`
@@ -1256,7 +1536,7 @@ function rootProdServer404Middleware() {
1256
1536
  console.error(`\u2753 404 ${req.originalUrl}`);
1257
1537
  if (req.renderer) {
1258
1538
  const url = req.path;
1259
- const ext = path7.extname(url);
1539
+ const ext = path8.extname(url);
1260
1540
  if (!ext) {
1261
1541
  const renderer = req.renderer;
1262
1542
  const data = await renderer.render404({ currentPath: url });
@@ -1274,7 +1554,7 @@ function rootProdServer500Middleware() {
1274
1554
  console.error(String(err.stack || err));
1275
1555
  if (req.renderer) {
1276
1556
  const url = req.path;
1277
- const ext = path7.extname(url);
1557
+ const ext = path8.extname(url);
1278
1558
  if (!ext) {
1279
1559
  const renderer = req.renderer;
1280
1560
  const data = await renderer.renderError(err);
@@ -1287,13 +1567,61 @@ function rootProdServer500Middleware() {
1287
1567
  };
1288
1568
  }
1289
1569
 
1570
+ // src/cli/cli.ts
1571
+ var CliRunner = class {
1572
+ constructor(name, version) {
1573
+ this.name = name;
1574
+ this.version = version;
1575
+ }
1576
+ async run(argv) {
1577
+ const program = new Command("root");
1578
+ program.version(this.version);
1579
+ program.option("-q, --quiet", "quiet");
1580
+ program.hook("preAction", (cmd) => {
1581
+ if (!cmd.opts().quiet) {
1582
+ console.log(
1583
+ `\u{1F955} ${bgGreen(black(` ${this.name} `))} v${this.version}
1584
+ `
1585
+ );
1586
+ }
1587
+ });
1588
+ program.command("build [path]").description("generates a static build").option("--ssr-only", "produce a ssr-only build").option(
1589
+ "--mode <mode>",
1590
+ "see: https://vitejs.dev/guide/env-and-mode.html#modes",
1591
+ "production"
1592
+ ).option(
1593
+ "-c, --concurrency <num>",
1594
+ "number of files to build concurrently",
1595
+ "10"
1596
+ ).action(build);
1597
+ program.command("create-package [path]").alias("package").description(
1598
+ "creates a standalone npm package for deployment to various hosting services"
1599
+ ).option("--target <target>", "hosting target, i.e. appengine or firebase").option("--out <outdir>", "output dir").option("--mode <mode>", "deployment mode, i.e. production or preview").action(createPackage);
1600
+ program.command("dev [path]").description("starts the server in development mode").option(
1601
+ "--host <host>",
1602
+ "network address the server should listen on, e.g. 127.0.0.1"
1603
+ ).action(dev);
1604
+ program.command("preview [path]").description("starts the server in preview mode").option(
1605
+ "--host <host>",
1606
+ "network address the server should listen on, e.g. 127.0.0.1"
1607
+ ).action(preview);
1608
+ program.command("start [path]").description("starts the server in production mode").option(
1609
+ "--host <host>",
1610
+ "network address the server should listen on, e.g. 127.0.0.1"
1611
+ ).action(start);
1612
+ await program.parseAsync(argv);
1613
+ }
1614
+ };
1615
+
1290
1616
  export {
1291
1617
  build,
1618
+ createPackage,
1292
1619
  dev,
1293
1620
  createDevServer,
1294
1621
  preview,
1295
1622
  createPreviewServer,
1296
1623
  start,
1297
- createProdServer
1624
+ createProdServer,
1625
+ CliRunner
1298
1626
  };
1299
- //# sourceMappingURL=chunk-CY3DVKXO.js.map
1627
+ //# sourceMappingURL=chunk-XOOP364R.js.map