webstudio 0.145.0 → 0.163.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 +114 -80
- package/package.json +21 -19
- package/templates/cloudflare/functions/[[path]].ts +0 -1
- package/templates/cloudflare/package.json +2 -6
- package/templates/cloudflare/tsconfig.json +0 -3
- package/templates/cloudflare/vite.config.ts +0 -2
- package/templates/defaults/app/{routes/[sitemap.xml].tsx → route-templates/default-sitemap.tsx} +2 -2
- package/templates/defaults/{__templates__/route-template.tsx → app/route-templates/html.tsx} +92 -70
- package/templates/defaults/app/route-templates/xml.tsx +61 -0
- package/templates/defaults/package.json +13 -13
- package/templates/defaults/tsconfig.json +0 -5
- package/templates/defaults/vite.config.ts +0 -9
- package/templates/internal/tsconfig.json +25 -0
- package/templates/netlify-edge-functions/package.json +2 -2
- package/templates/netlify-edge-functions/vite.config.ts +0 -9
- package/templates/netlify-functions/package.json +1 -1
- package/templates/netlify-functions/vite.config.ts +0 -9
- package/templates/saas-helpers/tsconfig.json +34 -0
- package/templates/defaults/app/__generated__/[sitemap.xml].ts +0 -11
package/lib/cli.js
CHANGED
|
@@ -68,16 +68,16 @@ var isFileExists = async (filePath) => {
|
|
|
68
68
|
return false;
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
|
-
var
|
|
71
|
+
var createFileIfNotExists = async (filePath, content) => {
|
|
72
72
|
const dir = dirname(filePath);
|
|
73
|
-
await
|
|
73
|
+
await createFolderIfNotExists(dir);
|
|
74
74
|
try {
|
|
75
75
|
await access(filePath, constants.F_OK);
|
|
76
76
|
} catch {
|
|
77
77
|
await writeFile(filePath, content || "", "utf8");
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
|
-
var
|
|
80
|
+
var createFolderIfNotExists = async (folderPath) => {
|
|
81
81
|
try {
|
|
82
82
|
await access(folderPath, constants.F_OK);
|
|
83
83
|
} catch {
|
|
@@ -142,7 +142,7 @@ var link = async (options) => {
|
|
|
142
142
|
const localConfig = {
|
|
143
143
|
projectId
|
|
144
144
|
};
|
|
145
|
-
await
|
|
145
|
+
await createFileIfNotExists(
|
|
146
146
|
join2(cwd(), LOCAL_CONFIG_FILE),
|
|
147
147
|
JSON.stringify(localConfig, null, 2)
|
|
148
148
|
);
|
|
@@ -231,7 +231,7 @@ var sync = async (options) => {
|
|
|
231
231
|
project;
|
|
232
232
|
spinner.text = "Saving project data to config file";
|
|
233
233
|
const localBuildFilePath = join3(cwd2(), LOCAL_DATA_FILE);
|
|
234
|
-
await
|
|
234
|
+
await createFileIfNotExists(localBuildFilePath);
|
|
235
235
|
await writeFile3(localBuildFilePath, JSON.stringify(project, null, 2), "utf8");
|
|
236
236
|
spinner.succeed("Project data synced successfully");
|
|
237
237
|
};
|
|
@@ -265,17 +265,17 @@ import {
|
|
|
265
265
|
normalizeProps,
|
|
266
266
|
generateRemixRoute,
|
|
267
267
|
generateRemixParams,
|
|
268
|
-
|
|
268
|
+
isCoreComponent
|
|
269
269
|
} from "@webstudio-is/react-sdk";
|
|
270
270
|
import {
|
|
271
271
|
createScope,
|
|
272
272
|
findTreeInstanceIds,
|
|
273
273
|
getPagePath,
|
|
274
274
|
parseComponentName,
|
|
275
|
-
executeExpression,
|
|
276
275
|
generateFormsProperties,
|
|
277
276
|
generateResourcesLoader,
|
|
278
|
-
generatePageMeta
|
|
277
|
+
generatePageMeta,
|
|
278
|
+
getStaticSiteMapXml
|
|
279
279
|
} from "@webstudio-is/sdk";
|
|
280
280
|
import { createImageLoader } from "@webstudio-is/image";
|
|
281
281
|
import * as baseComponentMetas from "@webstudio-is/sdk-components-react/metas";
|
|
@@ -288,7 +288,7 @@ var downloadAsset = async (url, name, assetBaseUrl) => {
|
|
|
288
288
|
try {
|
|
289
289
|
await access2(assetPath);
|
|
290
290
|
} catch {
|
|
291
|
-
await
|
|
291
|
+
await createFolderIfNotExists(dirname2(assetPath));
|
|
292
292
|
try {
|
|
293
293
|
const response = await fetch(url);
|
|
294
294
|
if (!response.ok) {
|
|
@@ -480,7 +480,7 @@ var prebuild = async (options) => {
|
|
|
480
480
|
};
|
|
481
481
|
componentsByPage[page.id] = /* @__PURE__ */ new Set();
|
|
482
482
|
for (const [_instanceId, instance] of instances) {
|
|
483
|
-
if (instance.component
|
|
483
|
+
if (isCoreComponent(instance.component)) {
|
|
484
484
|
continue;
|
|
485
485
|
}
|
|
486
486
|
componentsByPage[page.id].add(instance.component);
|
|
@@ -546,6 +546,8 @@ var prebuild = async (options) => {
|
|
|
546
546
|
const assets = new Map(siteData.assets.map((asset) => [asset.id, asset]));
|
|
547
547
|
spinner.text = "Generating css file";
|
|
548
548
|
const { cssText, classesMap } = generateCss({
|
|
549
|
+
instances: new Map(siteData.build.instances),
|
|
550
|
+
props: new Map(siteData.build.props),
|
|
549
551
|
assets,
|
|
550
552
|
breakpoints: new Map(siteData.build?.breakpoints),
|
|
551
553
|
styles: new Map(siteData.build?.styles),
|
|
@@ -555,13 +557,18 @@ var prebuild = async (options) => {
|
|
|
555
557
|
assetBaseUrl,
|
|
556
558
|
atomic: siteData.build.pages.compiler?.atomicStyles ?? true
|
|
557
559
|
});
|
|
558
|
-
await
|
|
560
|
+
await createFileIfNotExists(join4(generatedDir, "index.css"), cssText);
|
|
559
561
|
spinner.text = "Generating routes and pages";
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
+
const routeTemplatesDir = join4(cwd3(), "app/route-templates");
|
|
563
|
+
const routeTemplatePath = normalize(join4(routeTemplatesDir, "html.tsx"));
|
|
564
|
+
const routeXmlTemplatePath = normalize(join4(routeTemplatesDir, "xml.tsx"));
|
|
565
|
+
const defaultSiteMapXmlPath = normalize(
|
|
566
|
+
join4(routeTemplatesDir, "default-sitemap.tsx")
|
|
562
567
|
);
|
|
563
568
|
const routeFileTemplate = await readFile4(routeTemplatePath, "utf8");
|
|
564
|
-
await
|
|
569
|
+
const routeXmlFileTemplate = await readFile4(routeXmlTemplatePath, "utf8");
|
|
570
|
+
const defaultSiteMapTemplate = await readFile4(defaultSiteMapXmlPath, "utf8");
|
|
571
|
+
await rm(routeTemplatesDir, { recursive: true, force: true });
|
|
565
572
|
for (const [pageId, pageComponents] of Object.entries(componentsByPage)) {
|
|
566
573
|
const scope = createScope([
|
|
567
574
|
// manually maintained list of occupied identifiers
|
|
@@ -594,14 +601,36 @@ var prebuild = async (options) => {
|
|
|
594
601
|
namespaces.get(namespace)?.add([shortName, component]);
|
|
595
602
|
}
|
|
596
603
|
let componentImports = "";
|
|
604
|
+
let xmlPresentationComponents = "";
|
|
605
|
+
const pageData = siteDataByPage[pageId];
|
|
606
|
+
const documentType = pageData.page.meta.documentType ?? "html";
|
|
597
607
|
for (const [namespace, componentsSet] of namespaces.entries()) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
608
|
+
switch (documentType) {
|
|
609
|
+
case "html":
|
|
610
|
+
{
|
|
611
|
+
const specifiers = Array.from(componentsSet).map(
|
|
612
|
+
([shortName, component]) => `${shortName} as ${scope.getName(component, shortName)}`
|
|
613
|
+
).join(", ");
|
|
614
|
+
componentImports += `import { ${specifiers} } from "${namespace}";
|
|
615
|
+
`;
|
|
616
|
+
}
|
|
617
|
+
break;
|
|
618
|
+
case "xml":
|
|
619
|
+
{
|
|
620
|
+
componentImports = `import { XmlNode } from "@webstudio-is/sdk-components-react";
|
|
602
621
|
`;
|
|
622
|
+
xmlPresentationComponents += Array.from(componentsSet).map(
|
|
623
|
+
([shortName, component]) => scope.getName(component, shortName)
|
|
624
|
+
).filter((scopedName) => scopedName !== "XmlNode").map(
|
|
625
|
+
(scopedName) => scopedName === "Body" ? `const ${scopedName} = (props: any) => props.children;` : `const ${scopedName} = () => null;`
|
|
626
|
+
).join("\n");
|
|
627
|
+
}
|
|
628
|
+
break;
|
|
629
|
+
default: {
|
|
630
|
+
documentType;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
603
633
|
}
|
|
604
|
-
const pageData = siteDataByPage[pageId];
|
|
605
634
|
const pageFontAssets = fontAssetsByPage[pageId];
|
|
606
635
|
const pageBackgroundImageAssets = backgroundImageAssetsByPage[pageId];
|
|
607
636
|
const rootInstanceId = pageData.page.rootInstanceId;
|
|
@@ -633,96 +662,99 @@ var prebuild = async (options) => {
|
|
|
633
662
|
)
|
|
634
663
|
});
|
|
635
664
|
const projectMeta = siteData.build.pages.meta;
|
|
665
|
+
const contactEmail = (
|
|
666
|
+
// fallback to user email when contact email is empty string
|
|
667
|
+
projectMeta?.contactEmail || siteData.user?.email || void 0
|
|
668
|
+
);
|
|
636
669
|
const pageMeta = pageData.page.meta;
|
|
637
670
|
const favIconAsset = assets.get(projectMeta?.faviconAssetId ?? "");
|
|
638
671
|
const socialImageAsset = assets.get(pageMeta.socialImageAssetId ?? "");
|
|
639
672
|
const pageExports = `/* eslint-disable */
|
|
640
|
-
/* This is a auto generated file for building the project */
|
|
673
|
+
/* This is a auto generated file for building the project */
|
|
641
674
|
|
|
642
675
|
|
|
643
|
-
import { Fragment, useState } from "react";
|
|
644
|
-
import type { FontAsset, ImageAsset } from "@webstudio-is/sdk";
|
|
645
|
-
import { useResource } from "@webstudio-is/react-sdk";
|
|
646
|
-
${componentImports}
|
|
676
|
+
import { Fragment, useState } from "react";
|
|
677
|
+
import type { FontAsset, ImageAsset } from "@webstudio-is/sdk";
|
|
678
|
+
import { useResource } from "@webstudio-is/react-sdk";
|
|
679
|
+
${componentImports}
|
|
647
680
|
|
|
648
|
-
export const
|
|
649
|
-
${JSON.stringify(favIconAsset)};
|
|
681
|
+
export const siteName = ${JSON.stringify(projectMeta?.siteName)};
|
|
650
682
|
|
|
651
|
-
export const
|
|
652
|
-
|
|
683
|
+
export const favIconAsset: ImageAsset | undefined =
|
|
684
|
+
${JSON.stringify(favIconAsset)};
|
|
653
685
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
${JSON.stringify(pageFontAssets)}
|
|
686
|
+
export const socialImageAsset: ImageAsset | undefined =
|
|
687
|
+
${JSON.stringify(socialImageAsset)};
|
|
657
688
|
|
|
658
|
-
|
|
659
|
-
|
|
689
|
+
// Font assets on current page (can be preloaded)
|
|
690
|
+
export const pageFontAssets: FontAsset[] =
|
|
691
|
+
${JSON.stringify(pageFontAssets)}
|
|
660
692
|
|
|
693
|
+
export const pageBackgroundImageAssets: ImageAsset[] =
|
|
694
|
+
${JSON.stringify(pageBackgroundImageAssets)}
|
|
661
695
|
|
|
696
|
+
${xmlPresentationComponents}
|
|
662
697
|
|
|
663
|
-
${pageComponent}
|
|
698
|
+
${pageComponent}
|
|
664
699
|
|
|
665
|
-
export { Page }
|
|
666
|
-
`;
|
|
700
|
+
export { Page }
|
|
701
|
+
`;
|
|
667
702
|
const serverExports = `/* eslint-disable */
|
|
668
|
-
/* This is a auto generated file for building the project */
|
|
703
|
+
/* This is a auto generated file for building the project */
|
|
669
704
|
|
|
670
705
|
|
|
671
|
-
import type {
|
|
672
|
-
${generateResourcesLoader({
|
|
706
|
+
import type { PageMeta } from "@webstudio-is/sdk";
|
|
707
|
+
${generateResourcesLoader({
|
|
673
708
|
scope,
|
|
674
709
|
page: pageData.page,
|
|
675
710
|
dataSources,
|
|
676
711
|
resources
|
|
677
712
|
})}
|
|
678
713
|
|
|
679
|
-
${generatePageMeta({
|
|
714
|
+
${generatePageMeta({
|
|
680
715
|
globalScope: scope,
|
|
681
716
|
page: pageData.page,
|
|
682
717
|
dataSources
|
|
683
718
|
})}
|
|
684
719
|
|
|
685
|
-
${generateFormsProperties(props)}
|
|
720
|
+
${generateFormsProperties(props)}
|
|
686
721
|
|
|
687
|
-
${generateRemixParams(pageData.page.path)}
|
|
722
|
+
${generateRemixParams(pageData.page.path)}
|
|
688
723
|
|
|
689
|
-
export const projectId = "${siteData.build.projectId}";
|
|
724
|
+
export const projectId = "${siteData.build.projectId}";
|
|
690
725
|
|
|
691
|
-
export const
|
|
692
|
-
${JSON.stringify(siteData.user)};
|
|
726
|
+
export const contactEmail = ${JSON.stringify(contactEmail)};
|
|
693
727
|
|
|
694
|
-
export const
|
|
695
|
-
|
|
696
|
-
|
|
728
|
+
export const customCode = ${JSON.stringify(
|
|
729
|
+
projectMeta?.code?.trim() ?? ""
|
|
730
|
+
)};
|
|
731
|
+
`;
|
|
697
732
|
const pagePath = getPagePath(pageData.page.id, siteData.build.pages);
|
|
698
733
|
const remixRoute = generateRemixRoute(pagePath);
|
|
699
734
|
const fileName = `${remixRoute}.tsx`;
|
|
700
|
-
const routeFileContent = routeFileTemplate.replace(
|
|
735
|
+
const routeFileContent = (documentType === "html" ? routeFileTemplate : routeXmlFileTemplate).replace(
|
|
701
736
|
/".*\/__generated__\/_index"/,
|
|
702
737
|
`"../__generated__/${remixRoute}"`
|
|
703
738
|
).replace(
|
|
704
739
|
/".*\/__generated__\/_index.server"/,
|
|
705
740
|
`"../__generated__/${remixRoute}.server"`
|
|
706
741
|
);
|
|
707
|
-
await
|
|
708
|
-
await
|
|
709
|
-
await
|
|
742
|
+
await createFileIfNotExists(join4(routesDir, fileName), routeFileContent);
|
|
743
|
+
await createFileIfNotExists(join4(generatedDir, fileName), pageExports);
|
|
744
|
+
await createFileIfNotExists(
|
|
710
745
|
join4(generatedDir, `${remixRoute}.server.tsx`),
|
|
711
746
|
serverExports
|
|
712
747
|
);
|
|
713
748
|
}
|
|
714
|
-
await
|
|
715
|
-
join4(
|
|
749
|
+
await createFileIfNotExists(
|
|
750
|
+
join4(routesDir, "[sitemap.xml]._index.tsx"),
|
|
751
|
+
defaultSiteMapTemplate.replace(/".*\/__generated__\//, `"../__generated__/`)
|
|
752
|
+
);
|
|
753
|
+
await createFileIfNotExists(
|
|
754
|
+
join4(generatedDir, "$resources.sitemap.xml.ts"),
|
|
716
755
|
`
|
|
717
756
|
export const sitemap = ${JSON.stringify(
|
|
718
|
-
|
|
719
|
-
pages: siteData.pages.filter(
|
|
720
|
-
(page) => executeExpression(page.meta.excludePageFromSearch) !== true
|
|
721
|
-
).map((page) => ({
|
|
722
|
-
path: page.path,
|
|
723
|
-
lastModified: siteData.build.updatedAt
|
|
724
|
-
}))
|
|
725
|
-
},
|
|
757
|
+
getStaticSiteMapXml(siteData.build.pages, siteData.build.updatedAt),
|
|
726
758
|
null,
|
|
727
759
|
2
|
|
728
760
|
)};
|
|
@@ -736,11 +768,11 @@ export const projectMeta: ProjectMeta =
|
|
|
736
768
|
const redirectFileName = `${redirectPagePath}.ts`;
|
|
737
769
|
const content = `import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
|
|
738
770
|
|
|
739
|
-
export const loader = (arg: LoaderFunctionArgs) => {
|
|
740
|
-
|
|
741
|
-
};
|
|
742
|
-
`;
|
|
743
|
-
await
|
|
771
|
+
export const loader = (arg: LoaderFunctionArgs) => {
|
|
772
|
+
return redirect("${redirect.new}", ${redirect.status ?? 301});
|
|
773
|
+
};
|
|
774
|
+
`;
|
|
775
|
+
await createFileIfNotExists(join4(routesDir, redirectFileName), content);
|
|
744
776
|
}
|
|
745
777
|
}
|
|
746
778
|
spinner.text = "Downloading fonts and images";
|
|
@@ -825,7 +857,7 @@ var initFlow = async (options) => {
|
|
|
825
857
|
if (folderName === void 0) {
|
|
826
858
|
throw new Error("Folder name is required");
|
|
827
859
|
}
|
|
828
|
-
await
|
|
860
|
+
await createFolderIfNotExists(join5(cwd4(), folderName));
|
|
829
861
|
chdir(join5(cwd4(), folderName));
|
|
830
862
|
}
|
|
831
863
|
const { projectLink } = await prompt({
|
|
@@ -917,7 +949,7 @@ import makeCLI from "yargs";
|
|
|
917
949
|
// package.json
|
|
918
950
|
var package_default = {
|
|
919
951
|
name: "webstudio",
|
|
920
|
-
version: "0.
|
|
952
|
+
version: "0.163.0",
|
|
921
953
|
description: "Webstudio CLI",
|
|
922
954
|
author: "Webstudio <github@webstudio.is>",
|
|
923
955
|
homepage: "https://webstudio.is",
|
|
@@ -961,24 +993,26 @@ var package_default = {
|
|
|
961
993
|
zod: "^3.22.4"
|
|
962
994
|
},
|
|
963
995
|
devDependencies: {
|
|
964
|
-
"@netlify/remix-adapter": "^2.3.
|
|
965
|
-
"@netlify/remix-edge-adapter": "3.2.
|
|
966
|
-
"@remix-run/cloudflare": "^2.
|
|
967
|
-
"@remix-run/cloudflare-pages": "^2.
|
|
968
|
-
"@remix-run/dev": "^2.
|
|
969
|
-
"@remix-run/node": "^2.
|
|
970
|
-
"@remix-run/react": "^2.
|
|
971
|
-
"@remix-run/server-runtime": "^2.
|
|
972
|
-
"@types/node": "^
|
|
996
|
+
"@netlify/remix-adapter": "^2.3.1",
|
|
997
|
+
"@netlify/remix-edge-adapter": "3.2.2",
|
|
998
|
+
"@remix-run/cloudflare": "^2.9.1",
|
|
999
|
+
"@remix-run/cloudflare-pages": "^2.9.1",
|
|
1000
|
+
"@remix-run/dev": "^2.9.1",
|
|
1001
|
+
"@remix-run/node": "^2.9.1",
|
|
1002
|
+
"@remix-run/react": "^2.9.1",
|
|
1003
|
+
"@remix-run/server-runtime": "^2.9.1",
|
|
1004
|
+
"@types/node": "^20.12.7",
|
|
973
1005
|
"@types/prompts": "^2.4.5",
|
|
974
1006
|
"@types/react": "^18.2.70",
|
|
975
1007
|
"@types/react-dom": "^18.2.25",
|
|
976
1008
|
"@types/yargs": "^17.0.32",
|
|
977
1009
|
"@webstudio-is/form-handlers": "workspace:*",
|
|
978
1010
|
"@webstudio-is/tsconfig": "workspace:*",
|
|
1011
|
+
react: "18.3.0-canary-14898b6a9-20240318",
|
|
1012
|
+
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|
|
979
1013
|
tsx: "^4.7.2",
|
|
980
1014
|
typescript: "5.4.5",
|
|
981
|
-
|
|
1015
|
+
vite: "^5.2.11",
|
|
982
1016
|
wrangler: "^3.48.0"
|
|
983
1017
|
}
|
|
984
1018
|
};
|
|
@@ -986,7 +1020,7 @@ var package_default = {
|
|
|
986
1020
|
// src/cli.ts
|
|
987
1021
|
var main = async () => {
|
|
988
1022
|
try {
|
|
989
|
-
await
|
|
1023
|
+
await createFileIfNotExists(GLOBAL_CONFIG_FILE, "{}");
|
|
990
1024
|
const cmd = makeCLI(hideBin(argv)).strict().fail(function(msg, err, yargs) {
|
|
991
1025
|
if (err) {
|
|
992
1026
|
throw err;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webstudio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.163.0",
|
|
4
4
|
"description": "Webstudio CLI",
|
|
5
5
|
"author": "Webstudio <github@webstudio.is>",
|
|
6
6
|
"homepage": "https://webstudio.is",
|
|
@@ -28,33 +28,35 @@
|
|
|
28
28
|
"title-case": "^4.1.0",
|
|
29
29
|
"yargs": "^17.7.2",
|
|
30
30
|
"zod": "^3.22.4",
|
|
31
|
-
"@webstudio-is/http-client": "0.
|
|
32
|
-
"@webstudio-is/
|
|
33
|
-
"@webstudio-is/
|
|
34
|
-
"@webstudio-is/
|
|
35
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
36
|
-
"@webstudio-is/sdk-components-react
|
|
37
|
-
"@webstudio-is/sdk-components-react-remix": "0.
|
|
31
|
+
"@webstudio-is/http-client": "0.163.0",
|
|
32
|
+
"@webstudio-is/react-sdk": "0.163.0",
|
|
33
|
+
"@webstudio-is/image": "0.163.0",
|
|
34
|
+
"@webstudio-is/sdk": "0.163.0",
|
|
35
|
+
"@webstudio-is/sdk-components-react-radix": "0.163.0",
|
|
36
|
+
"@webstudio-is/sdk-components-react": "0.163.0",
|
|
37
|
+
"@webstudio-is/sdk-components-react-remix": "0.163.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@netlify/remix-adapter": "^2.3.
|
|
41
|
-
"@netlify/remix-edge-adapter": "3.2.
|
|
42
|
-
"@remix-run/cloudflare": "^2.
|
|
43
|
-
"@remix-run/cloudflare-pages": "^2.
|
|
44
|
-
"@remix-run/dev": "^2.
|
|
45
|
-
"@remix-run/node": "^2.
|
|
46
|
-
"@remix-run/react": "^2.
|
|
47
|
-
"@remix-run/server-runtime": "^2.
|
|
48
|
-
"@types/node": "^
|
|
40
|
+
"@netlify/remix-adapter": "^2.3.1",
|
|
41
|
+
"@netlify/remix-edge-adapter": "3.2.2",
|
|
42
|
+
"@remix-run/cloudflare": "^2.9.1",
|
|
43
|
+
"@remix-run/cloudflare-pages": "^2.9.1",
|
|
44
|
+
"@remix-run/dev": "^2.9.1",
|
|
45
|
+
"@remix-run/node": "^2.9.1",
|
|
46
|
+
"@remix-run/react": "^2.9.1",
|
|
47
|
+
"@remix-run/server-runtime": "^2.9.1",
|
|
48
|
+
"@types/node": "^20.12.7",
|
|
49
49
|
"@types/prompts": "^2.4.5",
|
|
50
50
|
"@types/react": "^18.2.70",
|
|
51
51
|
"@types/react-dom": "^18.2.25",
|
|
52
52
|
"@types/yargs": "^17.0.32",
|
|
53
|
+
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
54
|
+
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|
|
53
55
|
"tsx": "^4.7.2",
|
|
54
56
|
"typescript": "5.4.5",
|
|
55
|
-
"vite
|
|
57
|
+
"vite": "^5.2.11",
|
|
56
58
|
"wrangler": "^3.48.0",
|
|
57
|
-
"@webstudio-is/form-handlers": "0.
|
|
59
|
+
"@webstudio-is/form-handlers": "0.163.0",
|
|
58
60
|
"@webstudio-is/tsconfig": "1.0.7"
|
|
59
61
|
},
|
|
60
62
|
"scripts": {
|
|
@@ -2,7 +2,6 @@ import { createPagesFunctionHandler } from "@remix-run/cloudflare-pages";
|
|
|
2
2
|
|
|
3
3
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
4
4
|
// @ts-ignore - the server build file is generated by `remix vite:build`
|
|
5
|
-
// eslint-disable-next-line import/no-unresolved
|
|
6
5
|
import * as build from "../build/server";
|
|
7
6
|
|
|
8
7
|
export const onRequest = createPagesFunctionHandler({ build });
|
|
@@ -12,17 +12,13 @@
|
|
|
12
12
|
"build-cf-types": "wrangler types"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@remix-run/cloudflare": "
|
|
16
|
-
"@remix-run/cloudflare-pages": "
|
|
15
|
+
"@remix-run/cloudflare": "2.9.1",
|
|
16
|
+
"@remix-run/cloudflare-pages": "2.9.1",
|
|
17
17
|
"isbot": "^4.1.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@cloudflare/workers-types": "^4.20240405.0",
|
|
21
|
-
"vite-tsconfig-paths": "^4.2.1",
|
|
22
21
|
"wrangler": "^3.48.0",
|
|
23
22
|
"miniflare": "^3.20231030.4"
|
|
24
|
-
},
|
|
25
|
-
"engines": {
|
|
26
|
-
"node": ">=18.0.0"
|
|
27
23
|
}
|
|
28
24
|
}
|
|
@@ -3,13 +3,11 @@ import {
|
|
|
3
3
|
cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
|
|
4
4
|
} from "@remix-run/dev";
|
|
5
5
|
import { defineConfig } from "vite";
|
|
6
|
-
import tsconfigPaths from "vite-tsconfig-paths";
|
|
7
6
|
|
|
8
7
|
export default defineConfig(({ mode }) => ({
|
|
9
8
|
plugins: [
|
|
10
9
|
// without this, remixCloudflareDevProxy trying to load workerd even for production (it's not needed for production)
|
|
11
10
|
mode === "production" ? undefined : remixCloudflareDevProxy(),
|
|
12
11
|
remix(),
|
|
13
|
-
tsconfigPaths(),
|
|
14
12
|
].filter(Boolean),
|
|
15
13
|
}));
|
package/templates/defaults/app/{routes/[sitemap.xml].tsx → route-templates/default-sitemap.tsx}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LoaderFunctionArgs } from "@remix-run/server-runtime";
|
|
2
|
-
import { sitemap } from "
|
|
2
|
+
import { sitemap } from "../../../../__generated__/$resources.sitemap.xml";
|
|
3
3
|
|
|
4
4
|
export const loader = (arg: LoaderFunctionArgs) => {
|
|
5
5
|
const host =
|
|
@@ -7,7 +7,7 @@ export const loader = (arg: LoaderFunctionArgs) => {
|
|
|
7
7
|
arg.request.headers.get("host") ||
|
|
8
8
|
"";
|
|
9
9
|
|
|
10
|
-
const urls = sitemap.
|
|
10
|
+
const urls = sitemap.map((page) => {
|
|
11
11
|
const url = new URL(`https://${host}${page.path}`);
|
|
12
12
|
|
|
13
13
|
return `
|
package/templates/defaults/{__templates__/route-template.tsx → app/route-templates/html.tsx}
RENAMED
|
@@ -11,34 +11,47 @@ import {
|
|
|
11
11
|
} from "@remix-run/server-runtime";
|
|
12
12
|
import { useLoaderData } from "@remix-run/react";
|
|
13
13
|
import { ReactSdkContext } from "@webstudio-is/react-sdk";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
n8nHandler,
|
|
16
|
+
formIdFieldName,
|
|
17
|
+
formBotFieldName,
|
|
18
|
+
} from "@webstudio-is/form-handlers";
|
|
15
19
|
import {
|
|
16
20
|
Page,
|
|
21
|
+
siteName,
|
|
17
22
|
favIconAsset,
|
|
18
23
|
socialImageAsset,
|
|
19
24
|
pageFontAssets,
|
|
20
25
|
pageBackgroundImageAssets,
|
|
21
|
-
} from "
|
|
26
|
+
} from "../../../../__generated__/_index";
|
|
22
27
|
import {
|
|
23
28
|
formsProperties,
|
|
24
29
|
loadResources,
|
|
25
30
|
getPageMeta,
|
|
26
31
|
getRemixParams,
|
|
27
32
|
projectId,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} from "../../../__generated__/_index.server";
|
|
33
|
+
contactEmail,
|
|
34
|
+
} from "../../../../__generated__/_index.server";
|
|
31
35
|
|
|
32
36
|
import css from "../__generated__/index.css?url";
|
|
33
|
-
import { assetBaseUrl, imageBaseUrl, imageLoader } from "
|
|
37
|
+
import { assetBaseUrl, imageBaseUrl, imageLoader } from "../constants.mjs";
|
|
34
38
|
|
|
35
39
|
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
36
40
|
const url = new URL(arg.request.url);
|
|
41
|
+
const host =
|
|
42
|
+
arg.request.headers.get("x-forwarded-host") ||
|
|
43
|
+
arg.request.headers.get("host") ||
|
|
44
|
+
"";
|
|
45
|
+
url.host = host;
|
|
46
|
+
url.protocol = "https";
|
|
47
|
+
|
|
37
48
|
const params = getRemixParams(arg.params);
|
|
38
49
|
const system = {
|
|
39
50
|
params,
|
|
40
51
|
search: Object.fromEntries(url.searchParams),
|
|
52
|
+
origin: url.origin,
|
|
41
53
|
};
|
|
54
|
+
|
|
42
55
|
const resources = await loadResources({ system });
|
|
43
56
|
const pageMeta = getPageMeta({ system, resources });
|
|
44
57
|
|
|
@@ -50,14 +63,6 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
50
63
|
return redirect(pageMeta.redirect, status);
|
|
51
64
|
}
|
|
52
65
|
|
|
53
|
-
const host =
|
|
54
|
-
arg.request.headers.get("x-forwarded-host") ||
|
|
55
|
-
arg.request.headers.get("host") ||
|
|
56
|
-
"";
|
|
57
|
-
|
|
58
|
-
url.host = host;
|
|
59
|
-
url.protocol = "https";
|
|
60
|
-
|
|
61
66
|
// typecheck
|
|
62
67
|
arg.context.EXCLUDE_FROM_SEARCH satisfies boolean;
|
|
63
68
|
|
|
@@ -69,7 +74,6 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
69
74
|
system,
|
|
70
75
|
resources,
|
|
71
76
|
pageMeta,
|
|
72
|
-
projectMeta,
|
|
73
77
|
},
|
|
74
78
|
// No way for current information to change, so add cache for 10 minutes
|
|
75
79
|
// In case of CRM Data, this should be set to 0
|
|
@@ -95,7 +99,7 @@ export const meta: MetaFunction<typeof loader> = ({ data }) => {
|
|
|
95
99
|
if (data === undefined) {
|
|
96
100
|
return metas;
|
|
97
101
|
}
|
|
98
|
-
const { pageMeta
|
|
102
|
+
const { pageMeta } = data;
|
|
99
103
|
|
|
100
104
|
if (data.url) {
|
|
101
105
|
metas.push({
|
|
@@ -117,16 +121,16 @@ export const meta: MetaFunction<typeof loader> = ({ data }) => {
|
|
|
117
121
|
|
|
118
122
|
const origin = `https://${data.host}`;
|
|
119
123
|
|
|
120
|
-
if (
|
|
124
|
+
if (siteName) {
|
|
121
125
|
metas.push({
|
|
122
126
|
property: "og:site_name",
|
|
123
|
-
content:
|
|
127
|
+
content: siteName,
|
|
124
128
|
});
|
|
125
129
|
metas.push({
|
|
126
130
|
"script:ld+json": {
|
|
127
131
|
"@context": "https://schema.org",
|
|
128
132
|
"@type": "WebSite",
|
|
129
|
-
name:
|
|
133
|
+
name: siteName,
|
|
130
134
|
url: origin,
|
|
131
135
|
},
|
|
132
136
|
});
|
|
@@ -240,68 +244,86 @@ const getMethod = (value: string | undefined) => {
|
|
|
240
244
|
}
|
|
241
245
|
};
|
|
242
246
|
|
|
243
|
-
export const action = async ({
|
|
244
|
-
|
|
247
|
+
export const action = async ({
|
|
248
|
+
request,
|
|
249
|
+
context,
|
|
250
|
+
}: ActionFunctionArgs): Promise<
|
|
251
|
+
{ success: true } | { success: false; errors: string[] }
|
|
252
|
+
> => {
|
|
253
|
+
try {
|
|
254
|
+
const formData = await request.formData();
|
|
245
255
|
|
|
246
|
-
|
|
247
|
-
if (formId === undefined) {
|
|
248
|
-
// We're throwing rather than returning { success: false }
|
|
249
|
-
// because this isn't supposed to happen normally: bug or malicious user
|
|
250
|
-
throw json("Form not found", { status: 404 });
|
|
251
|
-
}
|
|
256
|
+
const formId = formData.get(formIdFieldName);
|
|
252
257
|
|
|
253
|
-
|
|
258
|
+
if (formId == null || typeof formId !== "string") {
|
|
259
|
+
throw new Error("No form id in FormData");
|
|
260
|
+
}
|
|
254
261
|
|
|
255
|
-
|
|
256
|
-
const { action, method } = formProperties ?? {};
|
|
262
|
+
const formBotValue = formData.get(formBotFieldName);
|
|
257
263
|
|
|
258
|
-
|
|
264
|
+
if (formBotValue == null || typeof formBotValue !== "string") {
|
|
265
|
+
throw new Error("Form bot field not found");
|
|
266
|
+
}
|
|
259
267
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
268
|
+
const submitTime = parseInt(formBotValue, 16);
|
|
269
|
+
// Assumes that the difference between the server time and the form submission time,
|
|
270
|
+
// including any client-server time drift, is within a 5-minute range.
|
|
271
|
+
// Note: submitTime might be NaN because formBotValue can be any string used for logging purposes.
|
|
272
|
+
// Example: `formBotValue: jsdom`, or `formBotValue: headless-env`
|
|
273
|
+
if (
|
|
274
|
+
Number.isNaN(submitTime) ||
|
|
275
|
+
Math.abs(Date.now() - submitTime) > 1000 * 60 * 5
|
|
276
|
+
) {
|
|
277
|
+
throw new Error(`Form bot value invalid ${formBotValue}`);
|
|
278
|
+
}
|
|
263
279
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
280
|
+
const formProperties = formsProperties.get(formId);
|
|
281
|
+
|
|
282
|
+
// form properties are not defined when defaults are used
|
|
283
|
+
const { action, method } = formProperties ?? {};
|
|
284
|
+
|
|
285
|
+
if (contactEmail === undefined) {
|
|
286
|
+
throw new Error("Contact email not found");
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const pageUrl = new URL(request.url);
|
|
269
290
|
pageUrl.host = getRequestHost(request);
|
|
270
|
-
} catch {
|
|
271
|
-
return { success: false };
|
|
272
|
-
}
|
|
273
291
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
},
|
|
284
|
-
{ status: 200 }
|
|
285
|
-
);
|
|
292
|
+
if (action !== undefined) {
|
|
293
|
+
try {
|
|
294
|
+
// Test that action is full URL
|
|
295
|
+
new URL(action);
|
|
296
|
+
} catch {
|
|
297
|
+
throw new Error(
|
|
298
|
+
"Invalid action URL, must be valid http/https protocol"
|
|
299
|
+
);
|
|
300
|
+
}
|
|
286
301
|
}
|
|
287
|
-
}
|
|
288
302
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
+
const formInfo = {
|
|
304
|
+
formData,
|
|
305
|
+
projectId,
|
|
306
|
+
action: action ?? null,
|
|
307
|
+
method: getMethod(method),
|
|
308
|
+
pageUrl: pageUrl.toString(),
|
|
309
|
+
toEmail: contactEmail,
|
|
310
|
+
fromEmail: pageUrl.hostname + "@webstudio.email",
|
|
311
|
+
} as const;
|
|
312
|
+
|
|
313
|
+
const result = await n8nHandler({
|
|
314
|
+
formInfo,
|
|
315
|
+
hookUrl: context.N8N_FORM_EMAIL_HOOK,
|
|
316
|
+
});
|
|
303
317
|
|
|
304
|
-
|
|
318
|
+
return result;
|
|
319
|
+
} catch (error) {
|
|
320
|
+
console.error(error);
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
success: false,
|
|
324
|
+
errors: [error instanceof Error ? error.message : "Unknown error"],
|
|
325
|
+
};
|
|
326
|
+
}
|
|
305
327
|
};
|
|
306
328
|
|
|
307
329
|
const Outlet = () => {
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
|
|
3
|
+
import { ReactSdkContext } from "@webstudio-is/react-sdk";
|
|
4
|
+
import { Page } from "../../../../__generated__/_index";
|
|
5
|
+
import {
|
|
6
|
+
loadResources,
|
|
7
|
+
getPageMeta,
|
|
8
|
+
getRemixParams,
|
|
9
|
+
} from "../../../../__generated__/_index.server";
|
|
10
|
+
|
|
11
|
+
import { assetBaseUrl, imageBaseUrl, imageLoader } from "../constants.mjs";
|
|
12
|
+
import { renderToString } from "react-dom/server";
|
|
13
|
+
|
|
14
|
+
export const loader = async (arg: LoaderFunctionArgs) => {
|
|
15
|
+
const url = new URL(arg.request.url);
|
|
16
|
+
const host =
|
|
17
|
+
arg.request.headers.get("x-forwarded-host") ||
|
|
18
|
+
arg.request.headers.get("host") ||
|
|
19
|
+
"";
|
|
20
|
+
url.host = host;
|
|
21
|
+
url.protocol = "https";
|
|
22
|
+
|
|
23
|
+
const params = getRemixParams(arg.params);
|
|
24
|
+
|
|
25
|
+
const system = {
|
|
26
|
+
params,
|
|
27
|
+
search: Object.fromEntries(url.searchParams),
|
|
28
|
+
origin: url.origin,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const resources = await loadResources({ system });
|
|
32
|
+
const pageMeta = getPageMeta({ system, resources });
|
|
33
|
+
|
|
34
|
+
if (pageMeta.redirect) {
|
|
35
|
+
const status =
|
|
36
|
+
pageMeta.status === 301 || pageMeta.status === 302
|
|
37
|
+
? pageMeta.status
|
|
38
|
+
: 302;
|
|
39
|
+
return redirect(pageMeta.redirect, status);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// typecheck
|
|
43
|
+
arg.context.EXCLUDE_FROM_SEARCH satisfies boolean;
|
|
44
|
+
|
|
45
|
+
const text = renderToString(
|
|
46
|
+
<ReactSdkContext.Provider
|
|
47
|
+
value={{
|
|
48
|
+
imageLoader,
|
|
49
|
+
assetBaseUrl,
|
|
50
|
+
imageBaseUrl,
|
|
51
|
+
resources,
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
<Page system={system} />
|
|
55
|
+
</ReactSdkContext.Provider>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return new Response(`<?xml version="1.0" encoding="UTF-8"?>\n${text}`, {
|
|
59
|
+
headers: { "Content-Type": "application/xml" },
|
|
60
|
+
});
|
|
61
|
+
};
|
|
@@ -8,28 +8,28 @@
|
|
|
8
8
|
"typecheck": "tsc"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@remix-run/
|
|
12
|
-
"@remix-run/
|
|
13
|
-
"@remix-run/
|
|
14
|
-
"@webstudio-is/react-sdk": "0.
|
|
15
|
-
"@webstudio-is/sdk-components-react-radix": "0.
|
|
16
|
-
"@webstudio-is/sdk-components-react-remix": "0.
|
|
17
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
18
|
-
"@webstudio-is/form-handlers": "0.
|
|
19
|
-
"@webstudio-is/image": "0.
|
|
20
|
-
"@webstudio-is/sdk": "0.
|
|
11
|
+
"@remix-run/node": "2.9.1",
|
|
12
|
+
"@remix-run/react": "2.9.1",
|
|
13
|
+
"@remix-run/server-runtime": "2.9.1",
|
|
14
|
+
"@webstudio-is/react-sdk": "0.163.0",
|
|
15
|
+
"@webstudio-is/sdk-components-react-radix": "0.163.0",
|
|
16
|
+
"@webstudio-is/sdk-components-react-remix": "0.163.0",
|
|
17
|
+
"@webstudio-is/sdk-components-react": "0.163.0",
|
|
18
|
+
"@webstudio-is/form-handlers": "0.163.0",
|
|
19
|
+
"@webstudio-is/image": "0.163.0",
|
|
20
|
+
"@webstudio-is/sdk": "0.163.0",
|
|
21
21
|
"isbot": "^3.6.8",
|
|
22
22
|
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
23
23
|
"react-dom": "18.3.0-canary-14898b6a9-20240318"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@remix-run/dev": "
|
|
26
|
+
"@remix-run/dev": "2.9.1",
|
|
27
27
|
"@types/react": "^18.2.70",
|
|
28
28
|
"@types/react-dom": "^18.2.25",
|
|
29
29
|
"typescript": "5.4.5",
|
|
30
|
-
"vite": "^5.2.
|
|
30
|
+
"vite": "^5.2.11"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
|
-
"node": ">=
|
|
33
|
+
"node": ">=20.0.0"
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -16,11 +16,6 @@
|
|
|
16
16
|
"forceConsistentCasingInFileNames": true,
|
|
17
17
|
"allowImportingTsExtensions": true,
|
|
18
18
|
"baseUrl": ".",
|
|
19
|
-
"paths": {
|
|
20
|
-
"~/*": ["./app/*"]
|
|
21
|
-
},
|
|
22
|
-
"customConditions": ["webstudio"],
|
|
23
|
-
|
|
24
19
|
// Remix takes care of building everything in `remix build`.
|
|
25
20
|
"noEmit": true,
|
|
26
21
|
"skipLibCheck": true
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
2
1
|
import { defineConfig } from "vite";
|
|
3
2
|
import { vitePlugin as remix } from "@remix-run/dev";
|
|
4
3
|
|
|
5
4
|
export default defineConfig({
|
|
6
5
|
plugins: [remix()],
|
|
7
|
-
resolve: {
|
|
8
|
-
alias: [
|
|
9
|
-
{
|
|
10
|
-
find: "~",
|
|
11
|
-
replacement: resolve("app"),
|
|
12
|
-
},
|
|
13
|
-
],
|
|
14
|
-
},
|
|
15
6
|
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["**/*.ts", "**/*.tsx", "**/*.mjs"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
5
|
+
"types": ["@remix-run/node", "vite/client"],
|
|
6
|
+
"isolatedModules": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"module": "ESNext",
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"target": "ES2022",
|
|
13
|
+
"strict": true,
|
|
14
|
+
"allowJs": true,
|
|
15
|
+
"checkJs": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
"allowImportingTsExtensions": true,
|
|
18
|
+
"baseUrl": ".",
|
|
19
|
+
"customConditions": ["webstudio"],
|
|
20
|
+
|
|
21
|
+
// Remix takes care of building everything in `remix build`.
|
|
22
|
+
"noEmit": true,
|
|
23
|
+
"skipLibCheck": true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
2
1
|
import { vitePlugin as remix } from "@remix-run/dev";
|
|
3
2
|
import { defineConfig } from "vite";
|
|
4
3
|
import { netlifyPlugin } from "@netlify/remix-edge-adapter/plugin";
|
|
5
4
|
|
|
6
5
|
export default defineConfig({
|
|
7
6
|
plugins: [remix(), netlifyPlugin()],
|
|
8
|
-
resolve: {
|
|
9
|
-
alias: [
|
|
10
|
-
{
|
|
11
|
-
find: "~",
|
|
12
|
-
replacement: resolve("app"),
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
},
|
|
16
7
|
});
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
2
1
|
import { vitePlugin as remix } from "@remix-run/dev";
|
|
3
2
|
import { defineConfig } from "vite";
|
|
4
3
|
import { netlifyPlugin } from "@netlify/remix-adapter/plugin";
|
|
5
4
|
|
|
6
5
|
export default defineConfig({
|
|
7
6
|
plugins: [remix(), netlifyPlugin()],
|
|
8
|
-
resolve: {
|
|
9
|
-
alias: [
|
|
10
|
-
{
|
|
11
|
-
find: "~",
|
|
12
|
-
replacement: resolve("app"),
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
},
|
|
16
7
|
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": [
|
|
3
|
+
"**/*.ts",
|
|
4
|
+
"**/*.tsx",
|
|
5
|
+
"**/.server/**/*.ts",
|
|
6
|
+
"**/.server/**/*.tsx",
|
|
7
|
+
"**/.client/**/*.ts",
|
|
8
|
+
"**/.client/**/*.tsx"
|
|
9
|
+
],
|
|
10
|
+
"compilerOptions": {
|
|
11
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
12
|
+
"types": [
|
|
13
|
+
"@remix-run/cloudflare",
|
|
14
|
+
"vite/client",
|
|
15
|
+
"@cloudflare/workers-types/2023-07-01"
|
|
16
|
+
],
|
|
17
|
+
"isolatedModules": true,
|
|
18
|
+
"esModuleInterop": true,
|
|
19
|
+
"jsx": "react-jsx",
|
|
20
|
+
"module": "ESNext",
|
|
21
|
+
"moduleResolution": "Bundler",
|
|
22
|
+
"resolveJsonModule": true,
|
|
23
|
+
"target": "ES2022",
|
|
24
|
+
"strict": true,
|
|
25
|
+
"allowJs": true,
|
|
26
|
+
"skipLibCheck": true,
|
|
27
|
+
"forceConsistentCasingInFileNames": true,
|
|
28
|
+
"baseUrl": ".",
|
|
29
|
+
"customConditions": ["webstudio"],
|
|
30
|
+
|
|
31
|
+
// Vite takes care of building everything, not tsc.
|
|
32
|
+
"noEmit": true
|
|
33
|
+
}
|
|
34
|
+
}
|