@blinkk/root 1.0.0-rc.9 → 1.0.0

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-KGPR2CJV.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,14 +399,14 @@ 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",
401
408
  chunkFileNames: "chunks/[hash].min.js",
402
- assetFileNames: "assets/[name].[hash][extname]",
409
+ assetFileNames: "assets/[hash][extname]",
403
410
  sanitizeFileName
404
411
  }
405
412
  },
@@ -410,34 +417,35 @@ 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",
431
- entryFileNames: "assets/[name].[hash].min.js",
432
- assetFileNames: "assets/[name].[hash][extname]",
439
+ entryFileNames: "assets/[hash].min.js",
440
+ assetFileNames: "assets/[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,20 +461,20 @@ 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",
462
- entryFileNames: "assets/[name].[hash].min.js",
463
- assetFileNames: "assets/[name].[hash][extname]",
470
+ entryFileNames: "assets/[hash].min.js",
471
+ assetFileNames: "assets/[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,13 +1079,13 @@ 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);
865
1090
  const server = await createDevServer({ rootDir, port });
866
1091
  const rootConfig = server.get("rootConfig");
@@ -876,31 +1101,41 @@ async function dev(rootProjectDir, options) {
876
1101
  server.listen(port, host);
877
1102
  }
878
1103
  async function createDevServer(options) {
879
- var _a;
880
- const rootDir = path5.resolve((options == null ? void 0 : options.rootDir) || process.cwd());
1104
+ const rootDir = path6.resolve(options?.rootDir || process.cwd());
881
1105
  const rootConfig = await loadRootConfig(rootDir, { command: "dev" });
882
- const port = options == null ? void 0 : options.port;
1106
+ const port = options?.port;
883
1107
  const server = express();
884
1108
  server.set("rootConfig", rootConfig);
885
1109
  server.disable("x-powered-by");
1110
+ const { viteServer, viteMiddleware } = await createViteMiddleware({
1111
+ rootConfig,
1112
+ port
1113
+ });
886
1114
  server.use(rootProjectMiddleware({ rootConfig }));
887
- server.use(await viteServerMiddleware({ rootConfig, port }));
1115
+ server.use(viteMiddleware);
888
1116
  server.use(hooksMiddleware());
889
- const sessionCookieSecret = ((_a = rootConfig.server) == null ? void 0 : _a.sessionCookieSecret) || randString(36);
1117
+ const sessionCookieSecret = rootConfig.server?.sessionCookieSecret || randString(36);
890
1118
  server.use(cookieParser(sessionCookieSecret));
891
1119
  server.use(sessionMiddleware());
892
1120
  const plugins = rootConfig.plugins || [];
893
1121
  await configureServerPlugins(
894
1122
  server,
895
1123
  async () => {
896
- var _a2;
897
- const userMiddlewares = ((_a2 = rootConfig.server) == null ? void 0 : _a2.middlewares) || [];
1124
+ const userMiddlewares = rootConfig.server?.middlewares || [];
898
1125
  for (const middleware of userMiddlewares) {
899
1126
  server.use(middleware);
900
1127
  }
901
- 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");
902
1137
  if (await dirExists(publicDir)) {
903
- server.use(sirv(publicDir, { dev: false }));
1138
+ server.use(rootPublicDirMiddleware({ publicDir, viteServer }));
904
1139
  }
905
1140
  server.use(trailingSlashMiddleware({ rootConfig }));
906
1141
  server.use(rootDevServerMiddleware());
@@ -912,7 +1147,7 @@ async function createDevServer(options) {
912
1147
  );
913
1148
  return server;
914
1149
  }
915
- async function viteServerMiddleware(options) {
1150
+ async function createViteMiddleware(options) {
916
1151
  const rootConfig = options.rootConfig;
917
1152
  const rootDir = rootConfig.rootDir;
918
1153
  let elementGraph = await getElements(rootConfig);
@@ -920,10 +1155,10 @@ async function viteServerMiddleware(options) {
920
1155
  return sourceFile.relPath;
921
1156
  });
922
1157
  const bundleScripts = [];
923
- if (await isDirectory(path5.join(rootDir, "bundles"))) {
1158
+ if (await isDirectory(path6.join(rootDir, "bundles"))) {
924
1159
  const bundleFiles = await glob3("bundles/*", { cwd: rootDir });
925
1160
  bundleFiles.forEach((file) => {
926
- const parts = path5.parse(file);
1161
+ const parts = path6.parse(file);
927
1162
  if (isJsFile(parts.base)) {
928
1163
  bundleScripts.push(file);
929
1164
  }
@@ -935,7 +1170,7 @@ async function viteServerMiddleware(options) {
935
1170
  optimizeDeps
936
1171
  });
937
1172
  function isInElementsDir(changedFilePath) {
938
- const filePath = path5.resolve(changedFilePath);
1173
+ const filePath = path6.resolve(changedFilePath);
939
1174
  const elementsDirs = getElementsDirs(rootConfig);
940
1175
  return elementsDirs.some((dirPath) => filePath.startsWith(dirPath));
941
1176
  }
@@ -951,10 +1186,10 @@ async function viteServerMiddleware(options) {
951
1186
  console.log(`element deleted: ${filePath}`);
952
1187
  }
953
1188
  });
954
- return async (req, res, next) => {
1189
+ const viteMiddleware = async (req, res, next) => {
955
1190
  try {
956
1191
  req.viteServer = viteServer;
957
- const renderModulePath = path5.resolve(__dirname2, "./render.js");
1192
+ const renderModulePath = path6.resolve(__dirname2, "./render.js");
958
1193
  const render = await viteServer.ssrLoadModule(
959
1194
  renderModulePath
960
1195
  );
@@ -968,6 +1203,28 @@ async function viteServerMiddleware(options) {
968
1203
  next(e);
969
1204
  }
970
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
+ };
971
1228
  }
972
1229
  function rootDevServerMiddleware() {
973
1230
  return async (req, res, next) => {
@@ -986,7 +1243,7 @@ function rootDevServer404Middleware() {
986
1243
  console.error(`\u2753 404 ${req.originalUrl}`);
987
1244
  if (req.renderer) {
988
1245
  const url = req.path;
989
- const ext = path5.extname(url);
1246
+ const ext = path6.extname(url);
990
1247
  if (!ext) {
991
1248
  const renderer = req.renderer;
992
1249
  const data = await renderer.renderDevServer404(req);
@@ -1004,7 +1261,7 @@ function rootDevServer500Middleware() {
1004
1261
  console.error(String(err.stack || err));
1005
1262
  if (req.renderer) {
1006
1263
  const url = req.path;
1007
- const ext = path5.extname(url);
1264
+ const ext = path6.extname(url);
1008
1265
  if (!ext) {
1009
1266
  const renderer = req.renderer;
1010
1267
  const data = await renderer.renderDevServer500(req, err);
@@ -1020,9 +1277,16 @@ function testCmsEnabled(rootConfig) {
1020
1277
  const plugins = rootConfig.plugins || [];
1021
1278
  return Boolean(plugins.find((plugin) => plugin.name === "root-cms"));
1022
1279
  }
1280
+ function debounce(fn, timeout) {
1281
+ let timer;
1282
+ return (...args) => {
1283
+ clearTimeout(timer);
1284
+ timer = setTimeout(() => fn(...args), timeout);
1285
+ };
1286
+ }
1023
1287
 
1024
- // src/cli/commands/preview.ts
1025
- import path6 from "node:path";
1288
+ // src/cli/preview.ts
1289
+ import path7 from "node:path";
1026
1290
  import compression from "compression";
1027
1291
  import cookieParser2 from "cookie-parser";
1028
1292
  import { default as express2 } from "express";
@@ -1030,10 +1294,10 @@ import { dim as dim3 } from "kleur/colors";
1030
1294
  import sirv2 from "sirv";
1031
1295
  async function preview(rootProjectDir, options) {
1032
1296
  process.env.NODE_ENV = "development";
1033
- const rootDir = path6.resolve(rootProjectDir || process.cwd());
1297
+ const rootDir = path7.resolve(rootProjectDir || process.cwd());
1034
1298
  const server = await createPreviewServer({ rootDir });
1035
1299
  const port = parseInt(process.env.PORT || "4007");
1036
- const host = (options == null ? void 0 : options.host) || "localhost";
1300
+ const host = options?.host || "localhost";
1037
1301
  console.log();
1038
1302
  console.log(`${dim3("\u2503")} project: ${rootDir}`);
1039
1303
  console.log(`${dim3("\u2503")} server: http://${host}:${port}`);
@@ -1042,29 +1306,35 @@ async function preview(rootProjectDir, options) {
1042
1306
  server.listen(port, host);
1043
1307
  }
1044
1308
  async function createPreviewServer(options) {
1045
- var _a;
1046
1309
  const rootDir = options.rootDir;
1047
- const rootConfig = await loadRootConfig(rootDir, { command: "preview" });
1048
- const distDir = path6.join(rootDir, "dist");
1310
+ const rootConfig = await loadBundledConfig(rootDir, { command: "preview" });
1311
+ const distDir = path7.join(rootDir, "dist");
1049
1312
  const server = express2();
1050
1313
  server.disable("x-powered-by");
1051
1314
  server.use(compression());
1052
1315
  server.use(rootProjectMiddleware({ rootConfig }));
1053
1316
  server.use(await rootPreviewRendererMiddleware({ rootConfig, distDir }));
1054
1317
  server.use(hooksMiddleware());
1055
- const sessionCookieSecret = ((_a = rootConfig.server) == null ? void 0 : _a.sessionCookieSecret) || randString(36);
1318
+ const sessionCookieSecret = rootConfig.server?.sessionCookieSecret || randString(36);
1056
1319
  server.use(cookieParser2(sessionCookieSecret));
1057
1320
  server.use(sessionMiddleware());
1058
1321
  const plugins = rootConfig.plugins || [];
1059
1322
  configureServerPlugins(
1060
1323
  server,
1061
1324
  async () => {
1062
- var _a2;
1063
- const userMiddlewares = ((_a2 = rootConfig.server) == null ? void 0 : _a2.middlewares) || [];
1325
+ const userMiddlewares = rootConfig.server?.middlewares || [];
1064
1326
  userMiddlewares.forEach((middleware) => {
1065
1327
  server.use(middleware);
1066
1328
  });
1067
- 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");
1068
1338
  server.use(sirv2(publicDir, { dev: false }));
1069
1339
  server.use(trailingSlashMiddleware({ rootConfig }));
1070
1340
  server.use(rootPreviewServerMiddleware());
@@ -1078,20 +1348,17 @@ async function createPreviewServer(options) {
1078
1348
  }
1079
1349
  async function rootPreviewRendererMiddleware(options) {
1080
1350
  const { distDir, rootConfig } = options;
1081
- const render = await import(path6.join(distDir, "server/render.js"));
1082
- 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");
1083
1353
  if (!await fileExists(manifestPath)) {
1084
1354
  throw new Error(
1085
1355
  `could not find ${manifestPath}. run \`root build\` before \`root preview\`.`
1086
1356
  );
1087
1357
  }
1088
- const elementGraphJsonPath = path6.join(
1089
- distDir,
1090
- "client/root-element-graph.json"
1091
- );
1358
+ const elementGraphJsonPath = path7.join(distDir, ".root/elements.json");
1092
1359
  if (!await fileExists(elementGraphJsonPath)) {
1093
1360
  throw new Error(
1094
- `could not find ${elementGraphJsonPath}. run \`root build\` before \`root start\`.`
1361
+ `could not find ${elementGraphJsonPath}. run \`root build\` before \`root preview\`.`
1095
1362
  );
1096
1363
  }
1097
1364
  const rootManifest = await loadJson(manifestPath);
@@ -1128,7 +1395,7 @@ function rootPreviewServer404Middleware() {
1128
1395
  console.error(`\u2753 404 ${req.originalUrl}`);
1129
1396
  if (req.renderer) {
1130
1397
  const url = req.path;
1131
- const ext = path6.extname(url);
1398
+ const ext = path7.extname(url);
1132
1399
  if (!ext) {
1133
1400
  const renderer = req.renderer;
1134
1401
  const data = await renderer.render404({ currentPath: url });
@@ -1146,7 +1413,7 @@ function rootPreviewServer500Middleware() {
1146
1413
  console.error(String(err.stack || err));
1147
1414
  if (req.renderer) {
1148
1415
  const url = req.path;
1149
- const ext = path6.extname(url);
1416
+ const ext = path7.extname(url);
1150
1417
  if (!ext) {
1151
1418
  const renderer = req.renderer;
1152
1419
  const data = await renderer.renderDevServer500(req, err);
@@ -1159,8 +1426,8 @@ function rootPreviewServer500Middleware() {
1159
1426
  };
1160
1427
  }
1161
1428
 
1162
- // src/cli/commands/start.ts
1163
- import path7 from "node:path";
1429
+ // src/cli/start.ts
1430
+ import path8 from "node:path";
1164
1431
  import compression2 from "compression";
1165
1432
  import cookieParser3 from "cookie-parser";
1166
1433
  import { default as express3 } from "express";
@@ -1168,10 +1435,10 @@ import { dim as dim4 } from "kleur/colors";
1168
1435
  import sirv3 from "sirv";
1169
1436
  async function start(rootProjectDir, options) {
1170
1437
  process.env.NODE_ENV = "production";
1171
- const rootDir = path7.resolve(rootProjectDir || process.cwd());
1438
+ const rootDir = path8.resolve(rootProjectDir || process.cwd());
1172
1439
  const server = await createProdServer({ rootDir });
1173
1440
  const port = parseInt(process.env.PORT || "4007");
1174
- const host = (options == null ? void 0 : options.host) || "localhost";
1441
+ const host = options?.host || "localhost";
1175
1442
  console.log();
1176
1443
  console.log(`${dim4("\u2503")} project: ${rootDir}`);
1177
1444
  console.log(`${dim4("\u2503")} server: http://${host}:${port}`);
@@ -1180,29 +1447,35 @@ async function start(rootProjectDir, options) {
1180
1447
  server.listen(port, host);
1181
1448
  }
1182
1449
  async function createProdServer(options) {
1183
- var _a;
1184
1450
  const rootDir = options.rootDir;
1185
- const rootConfig = await loadRootConfig(rootDir, { command: "start" });
1186
- const distDir = path7.join(rootDir, "dist");
1451
+ const rootConfig = await loadBundledConfig(rootDir, { command: "start" });
1452
+ const distDir = path8.join(rootDir, "dist");
1187
1453
  const server = express3();
1188
1454
  server.disable("x-powered-by");
1189
1455
  server.use(compression2());
1190
1456
  server.use(rootProjectMiddleware({ rootConfig }));
1191
1457
  server.use(await rootProdRendererMiddleware({ rootConfig, distDir }));
1192
1458
  server.use(hooksMiddleware());
1193
- const sessionCookieSecret = ((_a = rootConfig.server) == null ? void 0 : _a.sessionCookieSecret) || randString(36);
1459
+ const sessionCookieSecret = rootConfig.server?.sessionCookieSecret || randString(36);
1194
1460
  server.use(cookieParser3(sessionCookieSecret));
1195
1461
  server.use(sessionMiddleware());
1196
1462
  const plugins = rootConfig.plugins || [];
1197
1463
  configureServerPlugins(
1198
1464
  server,
1199
1465
  async () => {
1200
- var _a2;
1201
- const userMiddlewares = ((_a2 = rootConfig.server) == null ? void 0 : _a2.middlewares) || [];
1466
+ const userMiddlewares = rootConfig.server?.middlewares || [];
1202
1467
  userMiddlewares.forEach((middleware) => {
1203
1468
  server.use(middleware);
1204
1469
  });
1205
- 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");
1206
1479
  server.use(sirv3(publicDir, { dev: false }));
1207
1480
  server.use(trailingSlashMiddleware({ rootConfig }));
1208
1481
  server.use(rootProdServerMiddleware());
@@ -1216,17 +1489,14 @@ async function createProdServer(options) {
1216
1489
  }
1217
1490
  async function rootProdRendererMiddleware(options) {
1218
1491
  const { distDir, rootConfig } = options;
1219
- const render = await import(path7.join(distDir, "server/render.js"));
1220
- 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");
1221
1494
  if (!await fileExists(manifestPath)) {
1222
1495
  throw new Error(
1223
1496
  `could not find ${manifestPath}. run \`root build\` before \`root start\`.`
1224
1497
  );
1225
1498
  }
1226
- const elementGraphJsonPath = path7.join(
1227
- distDir,
1228
- "client/root-element-graph.json"
1229
- );
1499
+ const elementGraphJsonPath = path8.join(distDir, ".root/elements.json");
1230
1500
  if (!await fileExists(elementGraphJsonPath)) {
1231
1501
  throw new Error(
1232
1502
  `could not find ${elementGraphJsonPath}. run \`root build\` before \`root start\`.`
@@ -1266,7 +1536,7 @@ function rootProdServer404Middleware() {
1266
1536
  console.error(`\u2753 404 ${req.originalUrl}`);
1267
1537
  if (req.renderer) {
1268
1538
  const url = req.path;
1269
- const ext = path7.extname(url);
1539
+ const ext = path8.extname(url);
1270
1540
  if (!ext) {
1271
1541
  const renderer = req.renderer;
1272
1542
  const data = await renderer.render404({ currentPath: url });
@@ -1284,7 +1554,7 @@ function rootProdServer500Middleware() {
1284
1554
  console.error(String(err.stack || err));
1285
1555
  if (req.renderer) {
1286
1556
  const url = req.path;
1287
- const ext = path7.extname(url);
1557
+ const ext = path8.extname(url);
1288
1558
  if (!ext) {
1289
1559
  const renderer = req.renderer;
1290
1560
  const data = await renderer.renderError(err);
@@ -1297,13 +1567,61 @@ function rootProdServer500Middleware() {
1297
1567
  };
1298
1568
  }
1299
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
+
1300
1616
  export {
1301
1617
  build,
1618
+ createPackage,
1302
1619
  dev,
1303
1620
  createDevServer,
1304
1621
  preview,
1305
1622
  createPreviewServer,
1306
1623
  start,
1307
- createProdServer
1624
+ createProdServer,
1625
+ CliRunner
1308
1626
  };
1309
- //# sourceMappingURL=chunk-G7ZCTWGB.js.map
1627
+ //# sourceMappingURL=chunk-RLFKEIOC.js.map