webstudio 0.168.0 → 0.174.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.
package/lib/cli.js CHANGED
@@ -45,10 +45,11 @@ var jsonToGlobalConfig = (json) => {
45
45
  return zGlobalConfig.parse(json);
46
46
  };
47
47
  var PROJECT_TEMPALTES = [
48
- "vanilla",
49
- "vercel",
50
- "netlify-functions",
51
- "netlify-edge-functions"
48
+ { value: "vanilla", label: "Vanilla" },
49
+ { value: "vercel", label: "Vercel" },
50
+ { value: "netlify-functions", label: "Netlify Functions" },
51
+ { value: "netlify-edge-functions", label: "Netlify Edge Functions" },
52
+ { value: "ssg", label: "Static Site Generation (SSG)" }
52
53
  ];
53
54
 
54
55
  // src/fs-utils.ts
@@ -258,14 +259,14 @@ import { exit as exit3 } from "node:process";
258
259
  import { log as log3 } from "@clack/prompts";
259
260
 
260
261
  // src/prebuild.ts
261
- import { basename, dirname as dirname2, join as join4, normalize } from "node:path";
262
- import { createWriteStream } from "node:fs";
262
+ import { basename, dirname as dirname2, join as join6, normalize, relative } from "node:path";
263
+ import { createWriteStream, existsSync } from "node:fs";
263
264
  import {
264
- rm,
265
+ rm as rm3,
265
266
  access as access2,
266
267
  rename,
267
268
  cp,
268
- readFile as readFile4,
269
+ readFile as readFile6,
269
270
  writeFile as writeFile4,
270
271
  readdir
271
272
  } from "node:fs/promises";
@@ -279,9 +280,8 @@ import {
279
280
  generateCss,
280
281
  generateWebstudioComponent,
281
282
  getIndexesWithinAncestors,
282
- namespaceMeta,
283
283
  normalizeProps,
284
- generateRemixRoute,
284
+ generateRemixRoute as generateRemixRoute2,
285
285
  generateRemixParams,
286
286
  isCoreComponent
287
287
  } from "@webstudio-is/react-sdk";
@@ -290,15 +290,12 @@ import {
290
290
  findTreeInstanceIds,
291
291
  getPagePath,
292
292
  parseComponentName,
293
- generateFormsProperties,
294
- generateResourcesLoader,
293
+ generateResources,
295
294
  generatePageMeta,
296
- getStaticSiteMapXml
295
+ getStaticSiteMapXml,
296
+ replaceFormActionsWithResources
297
297
  } from "@webstudio-is/sdk";
298
298
  import { createImageLoader } from "@webstudio-is/image";
299
- import * as baseComponentMetas from "@webstudio-is/sdk-components-react/metas";
300
- import * as remixComponentMetas from "@webstudio-is/sdk-components-react-remix/metas";
301
- import * as radixComponentMetas from "@webstudio-is/sdk-components-react-radix/metas";
302
299
 
303
300
  // src/html-to-jsx.ts
304
301
  import {
@@ -414,10 +411,161 @@ var htmlToJsx = (html) => {
414
411
  return result;
415
412
  };
416
413
 
414
+ // src/framework-remix.ts
415
+ import { join as join4 } from "node:path";
416
+ import { readFile as readFile4, rm } from "node:fs/promises";
417
+ import {
418
+ generateRemixRoute,
419
+ namespaceMeta
420
+ } from "@webstudio-is/react-sdk";
421
+ import * as baseComponentMetas from "@webstudio-is/sdk-components-react/metas";
422
+ import * as remixComponentMetas from "@webstudio-is/sdk-components-react-remix/metas";
423
+ import * as radixComponentMetas from "@webstudio-is/sdk-components-react-radix/metas";
424
+ var createFramework = async () => {
425
+ const routeTemplatesDir = join4("app", "route-templates");
426
+ const htmlTemplate = await readFile4(
427
+ join4(routeTemplatesDir, "html.tsx"),
428
+ "utf8"
429
+ );
430
+ const xmlTemplate = await readFile4(
431
+ join4(routeTemplatesDir, "xml.tsx"),
432
+ "utf8"
433
+ );
434
+ const defaultSitemapTemplate = await readFile4(
435
+ join4(routeTemplatesDir, "default-sitemap.tsx"),
436
+ "utf8"
437
+ );
438
+ const redirectTemplate = await readFile4(
439
+ join4(routeTemplatesDir, "redirect.tsx"),
440
+ "utf8"
441
+ );
442
+ await rm(routeTemplatesDir, { recursive: true, force: true });
443
+ const radixComponentNamespacedMetas = {};
444
+ for (const [name, meta] of Object.entries(radixComponentMetas)) {
445
+ const namespace = "@webstudio-is/sdk-components-react-radix";
446
+ radixComponentNamespacedMetas[`${namespace}:${name}`] = namespaceMeta(
447
+ meta,
448
+ namespace,
449
+ new Set(Object.keys(radixComponentMetas))
450
+ );
451
+ }
452
+ return {
453
+ components: [
454
+ {
455
+ source: "@webstudio-is/sdk-components-react",
456
+ metas: baseComponentMetas
457
+ },
458
+ {
459
+ source: "@webstudio-is/sdk-components-react-radix",
460
+ metas: radixComponentNamespacedMetas
461
+ },
462
+ {
463
+ source: "@webstudio-is/sdk-components-react-remix",
464
+ metas: remixComponentMetas
465
+ }
466
+ ],
467
+ html: ({ pagePath }) => [
468
+ {
469
+ file: join4("app", "routes", `${generateRemixRoute(pagePath)}.tsx`),
470
+ template: htmlTemplate
471
+ }
472
+ ],
473
+ xml: ({ pagePath }) => [
474
+ {
475
+ file: join4("app", "routes", `${generateRemixRoute(pagePath)}.tsx`),
476
+ template: xmlTemplate
477
+ }
478
+ ],
479
+ redirect: ({ pagePath }) => [
480
+ {
481
+ file: join4("app", "routes", `${generateRemixRoute(pagePath)}.ts`),
482
+ template: redirectTemplate
483
+ }
484
+ ],
485
+ defaultSitemap: () => [
486
+ {
487
+ file: join4(
488
+ "app",
489
+ "routes",
490
+ `${generateRemixRoute("/sitemap.xml")}.tsx`
491
+ ),
492
+ template: defaultSitemapTemplate
493
+ }
494
+ ]
495
+ };
496
+ };
497
+
498
+ // src/framework-vike-ssg.ts
499
+ import { join as join5 } from "node:path";
500
+ import { readFile as readFile5, rm as rm2 } from "node:fs/promises";
501
+ import { namespaceMeta as namespaceMeta2 } from "@webstudio-is/react-sdk";
502
+ import * as baseComponentMetas2 from "@webstudio-is/sdk-components-react/metas";
503
+ import * as radixComponentMetas2 from "@webstudio-is/sdk-components-react-radix/metas";
504
+ var generateVikeRoute = (pagePath) => {
505
+ if (pagePath === "/") {
506
+ return "index";
507
+ }
508
+ return pagePath;
509
+ };
510
+ var createFramework2 = async () => {
511
+ const routeTemplatesDir = join5("app", "route-templates");
512
+ const htmlPageTemplate = await readFile5(
513
+ join5(routeTemplatesDir, "html", "+Page.tsx"),
514
+ "utf8"
515
+ );
516
+ const htmlHeadTemplate = await readFile5(
517
+ join5(routeTemplatesDir, "html", "+Head.tsx"),
518
+ "utf8"
519
+ );
520
+ const htmlDataTemplate = await readFile5(
521
+ join5(routeTemplatesDir, "html", "+data.ts"),
522
+ "utf8"
523
+ );
524
+ await rm2(routeTemplatesDir, { recursive: true, force: true });
525
+ const radixComponentNamespacedMetas = {};
526
+ for (const [name, meta] of Object.entries(radixComponentMetas2)) {
527
+ const namespace = "@webstudio-is/sdk-components-react-radix";
528
+ radixComponentNamespacedMetas[`${namespace}:${name}`] = namespaceMeta2(
529
+ meta,
530
+ namespace,
531
+ new Set(Object.keys(radixComponentMetas2))
532
+ );
533
+ }
534
+ return {
535
+ components: [
536
+ {
537
+ source: "@webstudio-is/sdk-components-react",
538
+ metas: baseComponentMetas2
539
+ },
540
+ {
541
+ source: "@webstudio-is/sdk-components-react-radix",
542
+ metas: radixComponentNamespacedMetas
543
+ }
544
+ ],
545
+ html: ({ pagePath }) => [
546
+ {
547
+ file: join5("pages", generateVikeRoute(pagePath), "+Page.tsx"),
548
+ template: htmlPageTemplate
549
+ },
550
+ {
551
+ file: join5("pages", generateVikeRoute(pagePath), "+Head.tsx"),
552
+ template: htmlHeadTemplate
553
+ },
554
+ {
555
+ file: join5("pages", generateVikeRoute(pagePath), "+data.ts"),
556
+ template: htmlDataTemplate
557
+ }
558
+ ],
559
+ xml: () => [],
560
+ redirect: () => [],
561
+ defaultSitemap: () => []
562
+ };
563
+ };
564
+
417
565
  // src/prebuild.ts
418
566
  var limit = pLimit(10);
419
567
  var downloadAsset = async (url, name, assetBaseUrl) => {
420
- const assetPath = join4("public", assetBaseUrl, name);
568
+ const assetPath = join6("public", assetBaseUrl, name);
421
569
  const tempAssetPath = `${assetPath}.tmp`;
422
570
  try {
423
571
  await access2(assetPath);
@@ -441,8 +589,8 @@ var downloadAsset = async (url, name, assetBaseUrl) => {
441
589
  }
442
590
  };
443
591
  var mergeJsonInto = async (sourcePath, destinationPath) => {
444
- const sourceJson = await readFile4(sourcePath, "utf8");
445
- const destinationJson = await readFile4(destinationPath, "utf8").catch(
592
+ const sourceJson = await readFile6(sourcePath, "utf8");
593
+ const destinationJson = await readFile6(destinationPath, "utf8").catch(
446
594
  (error) => {
447
595
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
448
596
  return "{}";
@@ -451,7 +599,9 @@ var mergeJsonInto = async (sourcePath, destinationPath) => {
451
599
  }
452
600
  );
453
601
  const content = JSON.stringify(
454
- merge(JSON.parse(destinationJson), JSON.parse(sourceJson)),
602
+ merge(JSON.parse(destinationJson), JSON.parse(sourceJson), {
603
+ arrayMerge: (_target, source) => source
604
+ }),
455
605
  null,
456
606
  " "
457
607
  );
@@ -460,7 +610,7 @@ var mergeJsonInto = async (sourcePath, destinationPath) => {
460
610
  var isCliTemplate = async (template) => {
461
611
  const currentPath = fileURLToPath(new URL(import.meta.url));
462
612
  const templatesPath = normalize(
463
- join4(dirname2(currentPath), "..", "templates")
613
+ join6(dirname2(currentPath), "..", "templates")
464
614
  );
465
615
  const dirents = await readdir(templatesPath, { withFileTypes: true });
466
616
  for (const dirent of dirents) {
@@ -472,23 +622,33 @@ var isCliTemplate = async (template) => {
472
622
  };
473
623
  var getTemplatePath = async (template) => {
474
624
  const currentPath = fileURLToPath(new URL(import.meta.url));
475
- const templatePath = await isCliTemplate(template) ? normalize(join4(dirname2(currentPath), "..", "templates", template)) : template;
625
+ const templatePath = await isCliTemplate(template) ? normalize(join6(dirname2(currentPath), "..", "templates", template)) : template;
476
626
  return templatePath;
477
627
  };
478
- var copyTemplates = async (template = "defaults") => {
628
+ var copyTemplates = async (template) => {
479
629
  const templatePath = await getTemplatePath(template);
480
630
  await cp(templatePath, cwd3(), {
481
631
  recursive: true,
482
632
  filter: (source) => {
483
- return basename(source) !== "package.json";
633
+ const name = basename(source);
634
+ return name !== "package.json" && name !== "tsconfig.json";
484
635
  }
485
636
  });
486
- if (await isFileExists(join4(templatePath, "package.json")) === true) {
637
+ if (existsSync(join6(templatePath, "package.json"))) {
487
638
  await mergeJsonInto(
488
- join4(templatePath, "package.json"),
489
- join4(cwd3(), "package.json")
639
+ join6(templatePath, "package.json"),
640
+ join6(cwd3(), "package.json")
490
641
  );
491
642
  }
643
+ if (existsSync(join6(templatePath, "tsconfig.json"))) {
644
+ await mergeJsonInto(
645
+ join6(templatePath, "tsconfig.json"),
646
+ join6(cwd3(), "tsconfig.json")
647
+ );
648
+ }
649
+ };
650
+ var importFrom = (importee, importer) => {
651
+ return relative(dirname2(importer), importee).replaceAll("\\", "/");
492
652
  };
493
653
  var prebuild = async (options) => {
494
654
  if (options.template.length === 0) {
@@ -499,7 +659,7 @@ Please check webstudio --help for more details`
499
659
  exit2(1);
500
660
  }
501
661
  for (const template of options.template) {
502
- if (template === "vanilla") {
662
+ if (template === "vanilla" || template === "ssg") {
503
663
  continue;
504
664
  }
505
665
  if (template.startsWith(".") || template.startsWith("/")) {
@@ -515,19 +675,25 @@ Please check webstudio --help for more details`
515
675
  }
516
676
  log2.step("Scaffolding the project files");
517
677
  const appRoot = "app";
518
- const generatedDir = join4(appRoot, "__generated__");
519
- await rm(generatedDir, { recursive: true, force: true });
520
- const routesDir = join4(appRoot, "routes");
521
- await rm(routesDir, { recursive: true, force: true });
522
- await copyTemplates();
523
- await writeFile4(join4(cwd3(), ".npmrc"), "force=true");
678
+ const generatedDir = join6(appRoot, "__generated__");
679
+ await rm3(generatedDir, { recursive: true, force: true });
680
+ const routesDir = join6(appRoot, "routes");
681
+ await rm3(routesDir, { recursive: true, force: true });
682
+ await copyTemplates(options.template.includes("ssg") ? "ssg" : "defaults");
683
+ await writeFile4(join6(cwd3(), ".npmrc"), "force=true");
524
684
  for (const template of options.template) {
525
- if (template === "vanilla") {
685
+ if (template === "vanilla" || template === "ssg") {
526
686
  continue;
527
687
  }
528
688
  await copyTemplates(template);
529
689
  }
530
- const constants2 = await import(pathToFileURL(join4(cwd3(), "app/constants.mjs")).href);
690
+ let framework;
691
+ if (options.template.includes("ssg")) {
692
+ framework = await createFramework2();
693
+ } else {
694
+ framework = await createFramework();
695
+ }
696
+ const constants2 = await import(pathToFileURL(join6(cwd3(), "app/constants.mjs")).href);
531
697
  const { assetBaseUrl } = constants2;
532
698
  const siteData = await loadJSONFile(LOCAL_DATA_FILE);
533
699
  if (siteData === null) {
@@ -535,31 +701,14 @@ Please check webstudio --help for more details`
535
701
  `Project data is missing, please make sure you the project is synced.`
536
702
  );
537
703
  }
538
- const domain = siteData.build.deployment?.projectDomain;
539
- if (domain === void 0) {
540
- throw new Error(`Project domain is missing from the project data`);
704
+ const metas = /* @__PURE__ */ new Map();
705
+ const componentSources = /* @__PURE__ */ new Map();
706
+ for (const entry of framework.components) {
707
+ for (const [componentName, meta] of Object.entries(entry.metas)) {
708
+ metas.set(componentName, meta);
709
+ componentSources.set(componentName, entry.source);
710
+ }
541
711
  }
542
- const radixComponentNamespacedMetas = Object.entries(
543
- radixComponentMetas
544
- ).reduce(
545
- (r, [name, meta]) => {
546
- const namespace = "@webstudio-is/sdk-components-react-radix";
547
- r[`${namespace}:${name}`] = namespaceMeta(
548
- meta,
549
- namespace,
550
- new Set(Object.keys(radixComponentMetas))
551
- );
552
- return r;
553
- },
554
- {}
555
- );
556
- const metas = new Map(
557
- Object.entries({
558
- ...baseComponentMetas,
559
- ...radixComponentNamespacedMetas,
560
- ...remixComponentMetas
561
- })
562
- );
563
712
  const projectMetas = /* @__PURE__ */ new Map();
564
713
  const componentsByPage = {};
565
714
  const siteDataByPage = {};
@@ -577,7 +726,9 @@ Please check webstudio --help for more details`
577
726
  props: siteData.build.props.map(([_id, prop]) => prop),
578
727
  assetBaseUrl,
579
728
  assets: new Map(siteData.assets.map((asset) => [asset.id, asset])),
580
- pages: siteData.build.pages
729
+ uploadingImageAssets: [],
730
+ pages: siteData.build.pages,
731
+ source: "prebuild"
581
732
  });
582
733
  const props = [];
583
734
  for (const prop of normalizedProps) {
@@ -648,6 +799,10 @@ Please check webstudio --help for more details`
648
799
  }
649
800
  const assetsToDownload = [];
650
801
  const appDomain = options.preview ? "wstd.work" : "wstd.io";
802
+ const domain = siteData.build.deployment?.destination === "static" ? siteData.build.deployment?.assetsDomain : siteData.build.deployment?.projectDomain;
803
+ if (domain === void 0) {
804
+ throw new Error(`Project domain is missing from the project data`);
805
+ }
651
806
  const assetBuildUrl = `https://${domain}.${appDomain}/cgi/asset/`;
652
807
  const imageLoader = createImageLoader({
653
808
  imageBaseUrl: assetBuildUrl
@@ -677,7 +832,7 @@ Please check webstudio --help for more details`
677
832
  }
678
833
  }
679
834
  const assets = new Map(siteData.assets.map((asset) => [asset.id, asset]));
680
- const { cssText, classesMap } = generateCss({
835
+ const { cssText, classes } = generateCss({
681
836
  instances: new Map(siteData.build.instances),
682
837
  props: new Map(siteData.build.props),
683
838
  assets,
@@ -689,17 +844,7 @@ Please check webstudio --help for more details`
689
844
  assetBaseUrl,
690
845
  atomic: siteData.build.pages.compiler?.atomicStyles ?? true
691
846
  });
692
- await createFileIfNotExists(join4(generatedDir, "index.css"), cssText);
693
- const routeTemplatesDir = join4(cwd3(), "app/route-templates");
694
- const routeTemplatePath = normalize(join4(routeTemplatesDir, "html.tsx"));
695
- const routeXmlTemplatePath = normalize(join4(routeTemplatesDir, "xml.tsx"));
696
- const defaultSiteMapXmlPath = normalize(
697
- join4(routeTemplatesDir, "default-sitemap.tsx")
698
- );
699
- const routeFileTemplate = await readFile4(routeTemplatePath, "utf8");
700
- const routeXmlFileTemplate = await readFile4(routeXmlTemplatePath, "utf8");
701
- const defaultSiteMapTemplate = await readFile4(defaultSiteMapXmlPath, "utf8");
702
- await rm(routeTemplatesDir, { recursive: true, force: true });
847
+ await createFileIfNotExists(join6(generatedDir, "index.css"), cssText);
703
848
  for (const [pageId, pageComponents] of Object.entries(componentsByPage)) {
704
849
  const scope = createScope([
705
850
  // manually maintained list of occupied identifiers
@@ -710,18 +855,10 @@ Please check webstudio --help for more details`
710
855
  "_props"
711
856
  ]);
712
857
  const namespaces = /* @__PURE__ */ new Map();
713
- const BASE_NAMESPACE = "@webstudio-is/sdk-components-react";
714
- const REMIX_NAMESPACE = "@webstudio-is/sdk-components-react-remix";
715
858
  for (const component of pageComponents) {
716
- const parsed = parseComponentName(component);
717
- let [namespace] = parsed;
718
- const [_namespace, shortName] = parsed;
859
+ const namespace = componentSources.get(component);
719
860
  if (namespace === void 0) {
720
- if (shortName in remixComponentMetas) {
721
- namespace = REMIX_NAMESPACE;
722
- } else {
723
- namespace = BASE_NAMESPACE;
724
- }
861
+ continue;
725
862
  }
726
863
  if (namespaces.has(namespace) === false) {
727
864
  namespaces.set(
@@ -729,6 +866,7 @@ Please check webstudio --help for more details`
729
866
  /* @__PURE__ */ new Set()
730
867
  );
731
868
  }
869
+ const [_namespace, shortName] = parseComponentName(component);
732
870
  namespaces.get(namespace)?.add([shortName, component]);
733
871
  }
734
872
  let componentImports = "";
@@ -769,6 +907,11 @@ Please check webstudio --help for more details`
769
907
  const props = new Map(pageData.build.props);
770
908
  const dataSources = new Map(pageData.build.dataSources);
771
909
  const resources = new Map(pageData.build.resources);
910
+ replaceFormActionsWithResources({
911
+ instances,
912
+ resources,
913
+ props
914
+ });
772
915
  const pageComponent = generateWebstudioComponent({
773
916
  scope,
774
917
  name: "Page",
@@ -785,7 +928,7 @@ Please check webstudio --help for more details`
785
928
  instances,
786
929
  props,
787
930
  dataSources,
788
- classesMap,
931
+ classesMap: classes,
789
932
  indexesWithinAncestors: getIndexesWithinAncestors(
790
933
  projectMetas,
791
934
  instances,
@@ -797,12 +940,8 @@ Please check webstudio --help for more details`
797
940
  // fallback to user email when contact email is empty string
798
941
  projectMeta?.contactEmail || siteData.user?.email || void 0
799
942
  );
800
- const pageMeta = pageData.page.meta;
801
943
  const favIconAsset = assets.get(projectMeta?.faviconAssetId ?? "");
802
- const socialImageAsset = assets.get(pageMeta.socialImageAssetId ?? "");
803
944
  const pagePath = getPagePath(pageData.page.id, siteData.build.pages);
804
- const remixRoute = generateRemixRoute(pagePath);
805
- const fileName = `${remixRoute}.tsx`;
806
945
  const pageExports = `/* eslint-disable */
807
946
  /* This is a auto generated file for building the project */
808
947
 
@@ -817,9 +956,6 @@ Please check webstudio --help for more details`
817
956
  export const favIconAsset: ImageAsset | undefined =
818
957
  ${JSON.stringify(favIconAsset)};
819
958
 
820
- export const socialImageAsset: ImageAsset | undefined =
821
- ${JSON.stringify(socialImageAsset)};
822
-
823
959
  // Font assets on current page (can be preloaded)
824
960
  export const pageFontAssets: FontAsset[] =
825
961
  ${JSON.stringify(pageFontAssets)}
@@ -827,7 +963,7 @@ Please check webstudio --help for more details`
827
963
  export const pageBackgroundImageAssets: ImageAsset[] =
828
964
  ${JSON.stringify(pageBackgroundImageAssets)}
829
965
 
830
- ${remixRoute === "_index" ? `
966
+ ${pagePath === "/" ? `
831
967
  ${projectMeta?.code ? `
832
968
  const Script = ({children, ...props}: Record<string, string | boolean>) => {
833
969
  if (children == null) {
@@ -861,47 +997,59 @@ Please check webstudio --help for more details`
861
997
 
862
998
 
863
999
  import type { PageMeta } from "@webstudio-is/sdk";
864
- ${generateResourcesLoader({
1000
+ ${generateResources({
865
1001
  scope,
866
1002
  page: pageData.page,
867
1003
  dataSources,
1004
+ props,
868
1005
  resources
869
1006
  })}
870
1007
 
871
1008
  ${generatePageMeta({
872
1009
  globalScope: scope,
873
1010
  page: pageData.page,
874
- dataSources
1011
+ dataSources,
1012
+ assets
875
1013
  })}
876
1014
 
877
- ${generateFormsProperties(props)}
878
-
879
1015
  ${generateRemixParams(pageData.page.path)}
880
1016
 
881
1017
  export const projectId = "${siteData.build.projectId}";
882
1018
 
883
1019
  export const contactEmail = ${JSON.stringify(contactEmail)};
884
1020
  `;
885
- const routeFileContent = (documentType === "html" ? routeFileTemplate : routeXmlFileTemplate).replace(
886
- /".*\/__generated__\/_index"/,
887
- `"../__generated__/${remixRoute}"`
888
- ).replace(
889
- /".*\/__generated__\/_index.server"/,
890
- `"../__generated__/${remixRoute}.server"`
891
- );
892
- await createFileIfNotExists(join4(routesDir, fileName), routeFileContent);
893
- await createFileIfNotExists(join4(generatedDir, fileName), pageExports);
894
- await createFileIfNotExists(
895
- join4(generatedDir, `${remixRoute}.server.tsx`),
896
- serverExports
1021
+ const generatedBasename = generateRemixRoute2(pagePath);
1022
+ const clientFile = join6(generatedDir, `${generatedBasename}.tsx`);
1023
+ await createFileIfNotExists(clientFile, pageExports);
1024
+ const serverFile = join6(generatedDir, `${generatedBasename}.server.tsx`);
1025
+ await createFileIfNotExists(serverFile, serverExports);
1026
+ const getTemplates = documentType === "html" ? framework.html : framework.xml;
1027
+ for (const { file, template } of getTemplates({ pagePath })) {
1028
+ const content = template.replaceAll("__CONSTANTS__", importFrom("./app/constants.mjs", file)).replaceAll(
1029
+ "__SITEMAP__",
1030
+ importFrom(`./app/__generated__/$resources.sitemap.xml`, file)
1031
+ ).replaceAll(
1032
+ "__CLIENT__",
1033
+ importFrom(`./app/__generated__/${generatedBasename}`, file)
1034
+ ).replaceAll(
1035
+ "__SERVER__",
1036
+ importFrom(`./app/__generated__/${generatedBasename}.server`, file)
1037
+ ).replaceAll(
1038
+ "__CSS__",
1039
+ importFrom(`./app/__generated__/index.css`, file)
1040
+ );
1041
+ await createFileIfNotExists(file, content);
1042
+ }
1043
+ }
1044
+ for (const { file, template } of framework.defaultSitemap()) {
1045
+ const content = template.replaceAll(
1046
+ "__SITEMAP__",
1047
+ importFrom(`./app/__generated__/$resources.sitemap.xml`, file)
897
1048
  );
1049
+ await createFileIfNotExists(file, content);
898
1050
  }
899
1051
  await createFileIfNotExists(
900
- join4(routesDir, "[sitemap.xml]._index.tsx"),
901
- defaultSiteMapTemplate.replace(/".*\/__generated__\//, `"../__generated__/`)
902
- );
903
- await createFileIfNotExists(
904
- join4(generatedDir, "$resources.sitemap.xml.ts"),
1052
+ join6(generatedDir, "$resources.sitemap.xml.ts"),
905
1053
  `
906
1054
  export const sitemap = ${JSON.stringify(
907
1055
  getStaticSiteMapXml(siteData.build.pages, siteData.build.updatedAt),
@@ -913,15 +1061,23 @@ Please check webstudio --help for more details`
913
1061
  const redirects = siteData.build.pages?.redirects;
914
1062
  if (redirects !== void 0 && redirects.length > 0) {
915
1063
  for (const redirect of redirects) {
916
- const redirectPagePath = generateRemixRoute(redirect.old);
917
- const redirectFileName = `${redirectPagePath}.ts`;
918
- const content = `import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
919
-
920
- export const loader = (arg: LoaderFunctionArgs) => {
921
- return redirect("${redirect.new}", ${redirect.status ?? 301});
922
- };
923
- `;
924
- await createFileIfNotExists(join4(routesDir, redirectFileName), content);
1064
+ const generatedBasename = generateRemixRoute2(redirect.old);
1065
+ await createFileIfNotExists(
1066
+ join6(generatedDir, `${generatedBasename}.ts`),
1067
+ `
1068
+ export const url = "${redirect.new}";
1069
+ export const status = ${redirect.status ?? 301};
1070
+ `
1071
+ );
1072
+ for (const { file, template } of framework.redirect({
1073
+ pagePath: redirect.old
1074
+ })) {
1075
+ const content = template.replaceAll(
1076
+ "__REDIRECT__",
1077
+ importFrom(`./app/__generated__/${generatedBasename}`, file)
1078
+ );
1079
+ await createFileIfNotExists(file, content);
1080
+ }
925
1081
  }
926
1082
  }
927
1083
  if (assetsToDownload.length > 0) {
@@ -946,9 +1102,9 @@ var buildOptions = (yargs) => yargs.option("assets", {
946
1102
  type: "array",
947
1103
  string: true,
948
1104
  default: [],
949
- describe: `Template to use for the build [choices: ${PROJECT_TEMPALTES.join(
950
- ", "
951
- )}]`
1105
+ describe: `Template to use for the build [choices: ${PROJECT_TEMPALTES.map(
1106
+ (item) => item.value
1107
+ ).join(", ")}]`
952
1108
  });
953
1109
  var build = async (options) => {
954
1110
  try {
@@ -967,7 +1123,7 @@ var build = async (options) => {
967
1123
 
968
1124
  // src/commands/init-flow.ts
969
1125
  import { chdir, cwd as cwd4 } from "node:process";
970
- import { join as join5 } from "node:path";
1126
+ import { join as join7 } from "node:path";
971
1127
  import pc2 from "picocolors";
972
1128
  import {
973
1129
  cancel as cancel2,
@@ -979,7 +1135,6 @@ import {
979
1135
  text as text2
980
1136
  } from "@clack/prompts";
981
1137
  import { $ } from "execa";
982
- import { titleCase } from "title-case";
983
1138
  var exitIfCancelled = (value) => {
984
1139
  if (isCancel2(value)) {
985
1140
  cancel2("Project initialization is cancelled");
@@ -1010,8 +1165,8 @@ var initFlow = async (options) => {
1010
1165
  }
1011
1166
  })
1012
1167
  );
1013
- await createFolderIfNotExists(join5(cwd4(), folderName));
1014
- chdir(join5(cwd4(), folderName));
1168
+ await createFolderIfNotExists(join7(cwd4(), folderName));
1169
+ chdir(join7(cwd4(), folderName));
1015
1170
  }
1016
1171
  const shareLink = exitIfCancelled(
1017
1172
  await text2({
@@ -1023,10 +1178,7 @@ var initFlow = async (options) => {
1023
1178
  projectTemplate = exitIfCancelled(
1024
1179
  await select({
1025
1180
  message: "Where would you like to deploy your project?",
1026
- options: PROJECT_TEMPALTES.map((template) => ({
1027
- value: template,
1028
- label: titleCase(template)
1029
- }))
1181
+ options: PROJECT_TEMPALTES
1030
1182
  })
1031
1183
  );
1032
1184
  shouldInstallDeps = exitIfCancelled(
@@ -1040,10 +1192,7 @@ var initFlow = async (options) => {
1040
1192
  projectTemplate = exitIfCancelled(
1041
1193
  await select({
1042
1194
  message: "Where would you like to deploy your project?",
1043
- options: PROJECT_TEMPALTES.map((template) => ({
1044
- value: template,
1045
- label: titleCase(template)
1046
- }))
1195
+ options: PROJECT_TEMPALTES
1047
1196
  })
1048
1197
  );
1049
1198
  }
@@ -1093,7 +1242,7 @@ import makeCLI from "yargs";
1093
1242
  // package.json
1094
1243
  var package_default = {
1095
1244
  name: "webstudio",
1096
- version: "0.168.0",
1245
+ version: "0.174.0",
1097
1246
  description: "Webstudio CLI",
1098
1247
  author: "Webstudio <github@webstudio.is>",
1099
1248
  homepage: "https://webstudio.is",
@@ -1116,9 +1265,7 @@ var package_default = {
1116
1265
  ],
1117
1266
  scripts: {
1118
1267
  typecheck: "tsc",
1119
- checks: "pnpm typecheck",
1120
1268
  build: "rm -rf lib && esbuild src/cli.ts --outdir=lib --bundle --format=esm --packages=external",
1121
- dev: "esbuild src/cli.ts --watch --bundle --format=esm --packages=external --outdir=./lib",
1122
1269
  test: "NODE_OPTIONS=--experimental-vm-modules jest"
1123
1270
  },
1124
1271
  license: "AGPL-3.0-or-later",
@@ -1142,7 +1289,6 @@ var package_default = {
1142
1289
  parse5: "7.1.2",
1143
1290
  picocolors: "^1.0.1",
1144
1291
  "strip-indent": "^4.0.0",
1145
- "title-case": "^4.1.0",
1146
1292
  yargs: "^17.7.2",
1147
1293
  zod: "^3.22.4"
1148
1294
  },
@@ -1150,24 +1296,26 @@ var package_default = {
1150
1296
  "@jest/globals": "^29.7.0",
1151
1297
  "@netlify/remix-adapter": "^2.4.0",
1152
1298
  "@netlify/remix-edge-adapter": "3.3.0",
1153
- "@remix-run/cloudflare": "^2.9.2",
1154
- "@remix-run/cloudflare-pages": "^2.9.2",
1155
- "@remix-run/dev": "^2.9.2",
1156
- "@remix-run/node": "^2.9.2",
1157
- "@remix-run/react": "^2.9.2",
1158
- "@remix-run/server-runtime": "^2.9.2",
1299
+ "@remix-run/cloudflare": "^2.10.3",
1300
+ "@remix-run/cloudflare-pages": "^2.10.3",
1301
+ "@remix-run/dev": "^2.10.3",
1302
+ "@remix-run/node": "^2.10.3",
1303
+ "@remix-run/react": "^2.10.3",
1304
+ "@remix-run/server-runtime": "^2.10.3",
1159
1305
  "@types/node": "^20.12.7",
1160
1306
  "@types/react": "^18.2.70",
1161
1307
  "@types/react-dom": "^18.2.25",
1162
1308
  "@types/yargs": "^17.0.32",
1309
+ "@vitejs/plugin-react": "^4.3.1",
1163
1310
  "@webstudio-is/form-handlers": "workspace:*",
1164
1311
  "@webstudio-is/jest-config": "workspace:*",
1165
1312
  "@webstudio-is/tsconfig": "workspace:*",
1166
1313
  react: "18.3.0-canary-14898b6a9-20240318",
1167
1314
  "react-dom": "18.3.0-canary-14898b6a9-20240318",
1168
- typescript: "5.4.5",
1169
- vite: "^5.2.13",
1170
- wrangler: "^3.48.0"
1315
+ typescript: "5.5.2",
1316
+ vike: "^0.4.180",
1317
+ vite: "^5.3.4",
1318
+ wrangler: "^3.63.2"
1171
1319
  }
1172
1320
  };
1173
1321