webstudio 0.0.0-588fe22 → 0.0.0-73cd6ea
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/README.md +1 -7
- package/lib/cli.js +5131 -2582
- package/package.json +37 -34
- package/templates/cloudflare/package.json +2 -2
- package/templates/cloudflare/vite.config.ts +8 -0
- package/templates/defaults/app/root.tsx +6 -2
- package/templates/defaults/app/route-templates/html.tsx +12 -13
- package/templates/defaults/app/route-templates/xml.tsx +3 -5
- package/templates/defaults/package.json +14 -14
- package/templates/defaults/vite.config.ts +8 -0
- package/templates/{react-router-docker → react-router}/app/root.tsx +6 -2
- package/templates/{react-router-docker → react-router}/app/route-templates/html.tsx +12 -13
- package/templates/{react-router-docker → react-router}/app/route-templates/xml.tsx +3 -1
- package/templates/react-router/package.json +34 -0
- package/templates/react-router/vite.config.ts +14 -0
- package/templates/react-router-cloudflare/app/constants.mjs +21 -0
- package/templates/react-router-cloudflare/app/entry.server.tsx +43 -0
- package/templates/react-router-cloudflare/package.json +12 -0
- package/templates/react-router-cloudflare/react-router.config.ts +7 -0
- package/templates/react-router-cloudflare/tsconfig.json +23 -0
- package/templates/react-router-cloudflare/vite.config.ts +15 -0
- package/templates/react-router-cloudflare/workers/app.ts +26 -0
- package/templates/react-router-cloudflare/wrangler.jsonc +6 -0
- package/templates/react-router-docker/app/constants.mjs +14 -1
- package/templates/react-router-docker/package.json +5 -33
- package/templates/{netlify-edge-functions → react-router-netlify}/app/constants.mjs +1 -1
- package/templates/react-router-netlify/netlify.toml +6 -0
- package/templates/react-router-netlify/package.json +10 -0
- package/templates/react-router-netlify/vite.config.ts +15 -0
- package/templates/{vercel → react-router-vercel}/app/constants.mjs +1 -1
- package/templates/react-router-vercel/package.json +9 -0
- package/templates/react-router-vercel/react-router.config.ts +6 -0
- package/templates/{vercel → react-router-vercel}/vercel.json +1 -0
- package/templates/saas-helpers/package.json +4 -1
- package/templates/saas-helpers/vite.config.ts +48 -0
- package/templates/ssg/app/route-templates/html/+Head.tsx +14 -6
- package/templates/ssg/app/route-templates/html/+Page.tsx +3 -1
- package/templates/ssg/package.json +10 -10
- package/templates/ssg/renderer/+onRenderHtml.tsx +13 -5
- package/templates/ssg/vite.config.ts +8 -0
- package/templates/netlify-edge-functions/app/entry.server.tsx +0 -21
- package/templates/netlify-edge-functions/netlify.toml +0 -16
- package/templates/netlify-edge-functions/package.json +0 -9
- package/templates/netlify-edge-functions/vite.config.ts +0 -18
- package/templates/netlify-functions/app/constants.mjs +0 -29
- package/templates/netlify-functions/app/entry.server.tsx +0 -1
- package/templates/netlify-functions/netlify.toml +0 -16
- package/templates/netlify-functions/package.json +0 -9
- package/templates/netlify-functions/vite.config.ts +0 -18
- package/templates/react-router-docker/vite.config.ts +0 -6
- package/templates/vercel/.vercelignore +0 -8
- package/templates/vercel/package.json +0 -1
- /package/templates/{react-router-docker → react-router}/app/extension.ts +0 -0
- /package/templates/{react-router-docker → react-router}/app/route-templates/default-sitemap.tsx +0 -0
- /package/templates/{react-router-docker → react-router}/app/route-templates/redirect.tsx +0 -0
- /package/templates/{react-router-docker → react-router}/app/routes/[robots.txt].tsx +0 -0
- /package/templates/{react-router-docker → react-router}/app/routes.ts +0 -0
- /package/templates/{react-router-docker → react-router}/public/favicon.ico +0 -0
- /package/templates/{react-router-docker → react-router}/tsconfig.json +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webstudio",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-73cd6ea",
|
|
4
4
|
"description": "Webstudio CLI",
|
|
5
5
|
"author": "Webstudio <github@webstudio.is>",
|
|
6
6
|
"homepage": "https://webstudio.is",
|
|
@@ -26,58 +26,61 @@
|
|
|
26
26
|
"node": ">=20.12"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@clack/prompts": "^0.
|
|
29
|
+
"@clack/prompts": "^0.10.0",
|
|
30
30
|
"@emotion/hash": "^0.9.2",
|
|
31
|
-
"acorn": "^8.14.
|
|
31
|
+
"acorn": "^8.14.1",
|
|
32
32
|
"acorn-walk": "^8.3.4",
|
|
33
33
|
"change-case": "^5.4.4",
|
|
34
34
|
"deepmerge": "^4.3.1",
|
|
35
35
|
"env-paths": "^3.0.0",
|
|
36
|
-
"nanoid": "^5.
|
|
36
|
+
"nanoid": "^5.1.5",
|
|
37
37
|
"p-limit": "^6.2.0",
|
|
38
|
-
"parse5": "7.
|
|
38
|
+
"parse5": "7.3.0",
|
|
39
39
|
"picocolors": "^1.1.1",
|
|
40
40
|
"reserved-identifiers": "^1.0.0",
|
|
41
41
|
"tinyexec": "^0.3.2",
|
|
42
42
|
"yargs": "^17.7.2",
|
|
43
|
-
"zod": "^3.
|
|
43
|
+
"zod": "^3.24.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@
|
|
47
|
-
"@netlify/
|
|
48
|
-
"@react-router/dev": "^7.
|
|
49
|
-
"@react-router/fs-routes": "^7.
|
|
50
|
-
"@remix-run/cloudflare": "^2.
|
|
51
|
-
"@remix-run/cloudflare-pages": "^2.
|
|
52
|
-
"@remix-run/dev": "^2.
|
|
53
|
-
"@remix-run/node": "^2.
|
|
54
|
-
"@remix-run/react": "^2.
|
|
55
|
-
"@remix-run/server-runtime": "^2.
|
|
46
|
+
"@cloudflare/vite-plugin": "^1.1.0",
|
|
47
|
+
"@netlify/vite-plugin-react-router": "^1.0.1",
|
|
48
|
+
"@react-router/dev": "^7.5.3",
|
|
49
|
+
"@react-router/fs-routes": "^7.5.3",
|
|
50
|
+
"@remix-run/cloudflare": "^2.16.5",
|
|
51
|
+
"@remix-run/cloudflare-pages": "^2.16.5",
|
|
52
|
+
"@remix-run/dev": "^2.16.5",
|
|
53
|
+
"@remix-run/node": "^2.16.5",
|
|
54
|
+
"@remix-run/react": "^2.16.5",
|
|
55
|
+
"@remix-run/server-runtime": "^2.16.5",
|
|
56
56
|
"@types/react": "^18.2.70",
|
|
57
57
|
"@types/react-dom": "^18.2.25",
|
|
58
58
|
"@types/yargs": "^17.0.33",
|
|
59
|
-
"@
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
59
|
+
"@vercel/react-router": "^1.1.0",
|
|
60
|
+
"@vitejs/plugin-react": "^4.4.1",
|
|
61
|
+
"h3": "^1.15.1",
|
|
62
|
+
"ipx": "^3.0.3",
|
|
63
|
+
"isbot": "^5.1.25",
|
|
64
|
+
"prettier": "3.5.3",
|
|
63
65
|
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
64
66
|
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|
|
65
|
-
"react-router": "^7.
|
|
67
|
+
"react-router": "^7.5.3",
|
|
66
68
|
"ts-expect": "^1.3.0",
|
|
67
|
-
"vike": "^0.4.
|
|
68
|
-
"vite": "^
|
|
69
|
-
"vitest": "^3.
|
|
69
|
+
"vike": "^0.4.229",
|
|
70
|
+
"vite": "^6.3.4",
|
|
71
|
+
"vitest": "^3.1.2",
|
|
70
72
|
"wrangler": "^3.63.2",
|
|
71
|
-
"@webstudio-is/
|
|
72
|
-
"@webstudio-is/
|
|
73
|
-
"@webstudio-is/
|
|
74
|
-
"@webstudio-is/
|
|
75
|
-
"@webstudio-is/sdk
|
|
76
|
-
"@webstudio-is/sdk-components-
|
|
77
|
-
"@webstudio-is/sdk-components-react-
|
|
78
|
-
"@webstudio-is/sdk-components-react-remix": "0.0.0-
|
|
79
|
-
"@webstudio-is/sdk-components-react
|
|
80
|
-
"@webstudio-is/tsconfig": "1.0.7"
|
|
73
|
+
"@webstudio-is/css-engine": "0.0.0-73cd6ea",
|
|
74
|
+
"@webstudio-is/http-client": "0.0.0-73cd6ea",
|
|
75
|
+
"@webstudio-is/image": "0.0.0-73cd6ea",
|
|
76
|
+
"@webstudio-is/sdk": "0.0.0-73cd6ea",
|
|
77
|
+
"@webstudio-is/react-sdk": "0.0.0-73cd6ea",
|
|
78
|
+
"@webstudio-is/sdk-components-animation": "0.0.0-73cd6ea",
|
|
79
|
+
"@webstudio-is/sdk-components-react-router": "0.0.0-73cd6ea",
|
|
80
|
+
"@webstudio-is/sdk-components-react-remix": "0.0.0-73cd6ea",
|
|
81
|
+
"@webstudio-is/sdk-components-react": "0.0.0-73cd6ea",
|
|
82
|
+
"@webstudio-is/tsconfig": "1.0.7",
|
|
83
|
+
"@webstudio-is/sdk-components-react-radix": "0.0.0-73cd6ea"
|
|
81
84
|
},
|
|
82
85
|
"scripts": {
|
|
83
86
|
"typecheck": "tsc",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"build-cf-types": "wrangler types"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@remix-run/cloudflare": "2.
|
|
16
|
-
"@remix-run/cloudflare-pages": "2.
|
|
15
|
+
"@remix-run/cloudflare": "2.16.5",
|
|
16
|
+
"@remix-run/cloudflare-pages": "2.16.5"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@cloudflare/workers-types": "^4.20240620.0",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { Links, Meta, Outlet, useMatches } from "@remix-run/react";
|
|
4
4
|
// @todo think about how to make __generated__ typeable
|
|
5
5
|
// @ts-ignore
|
|
6
|
-
import { CustomCode } from "./__generated__/_index";
|
|
6
|
+
import { CustomCode, projectId, lastPublished } from "./__generated__/_index";
|
|
7
7
|
|
|
8
8
|
const Root = () => {
|
|
9
9
|
// Get language from matches
|
|
@@ -19,7 +19,11 @@ const Root = () => {
|
|
|
19
19
|
const lang = lastMatchWithLanguage?.data?.pageMeta?.language ?? "en";
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
|
-
<html
|
|
22
|
+
<html
|
|
23
|
+
lang={lang}
|
|
24
|
+
data-ws-project={projectId}
|
|
25
|
+
data-ws-last-published={lastPublished}
|
|
26
|
+
>
|
|
23
27
|
<head>
|
|
24
28
|
<meta charSet="utf-8" />
|
|
25
29
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
@@ -23,20 +23,21 @@ import {
|
|
|
23
23
|
PageSettingsCanonicalLink,
|
|
24
24
|
} from "@webstudio-is/react-sdk/runtime";
|
|
25
25
|
import {
|
|
26
|
+
projectId,
|
|
26
27
|
Page,
|
|
27
28
|
siteName,
|
|
28
29
|
favIconAsset,
|
|
29
30
|
pageFontAssets,
|
|
30
31
|
pageBackgroundImageAssets,
|
|
32
|
+
breakpoints,
|
|
31
33
|
} from "__CLIENT__";
|
|
32
34
|
import {
|
|
33
35
|
getResources,
|
|
34
36
|
getPageMeta,
|
|
35
37
|
getRemixParams,
|
|
36
|
-
projectId,
|
|
37
38
|
contactEmail,
|
|
38
39
|
} from "__SERVER__";
|
|
39
|
-
import
|
|
40
|
+
import * as constants from "__CONSTANTS__";
|
|
40
41
|
import css from "__CSS__?url";
|
|
41
42
|
import { sitemap } from "__SITEMAP__";
|
|
42
43
|
|
|
@@ -150,8 +151,8 @@ export const links: LinksFunction = () => {
|
|
|
150
151
|
if (favIconAsset) {
|
|
151
152
|
result.push({
|
|
152
153
|
rel: "icon",
|
|
153
|
-
href: imageLoader({
|
|
154
|
-
src: `${assetBaseUrl}${favIconAsset
|
|
154
|
+
href: constants.imageLoader({
|
|
155
|
+
src: `${constants.assetBaseUrl}${favIconAsset}`,
|
|
155
156
|
// width,height must be multiple of 48 https://developers.google.com/search/docs/appearance/favicon-in-search
|
|
156
157
|
width: 144,
|
|
157
158
|
height: 144,
|
|
@@ -166,7 +167,7 @@ export const links: LinksFunction = () => {
|
|
|
166
167
|
for (const asset of pageFontAssets) {
|
|
167
168
|
result.push({
|
|
168
169
|
rel: "preload",
|
|
169
|
-
href: `${assetBaseUrl}${asset
|
|
170
|
+
href: `${constants.assetBaseUrl}${asset}`,
|
|
170
171
|
as: "font",
|
|
171
172
|
crossOrigin: "anonymous",
|
|
172
173
|
});
|
|
@@ -175,7 +176,7 @@ export const links: LinksFunction = () => {
|
|
|
175
176
|
for (const backgroundImageAsset of pageBackgroundImageAssets) {
|
|
176
177
|
result.push({
|
|
177
178
|
rel: "preload",
|
|
178
|
-
href: `${assetBaseUrl}${backgroundImageAsset
|
|
179
|
+
href: `${constants.assetBaseUrl}${backgroundImageAsset}`,
|
|
179
180
|
as: "image",
|
|
180
181
|
});
|
|
181
182
|
}
|
|
@@ -232,10 +233,6 @@ export const action = async ({
|
|
|
232
233
|
formData.delete(formBotFieldName);
|
|
233
234
|
|
|
234
235
|
if (resource) {
|
|
235
|
-
resource.headers.push({
|
|
236
|
-
name: "Content-Type",
|
|
237
|
-
value: "application/json",
|
|
238
|
-
});
|
|
239
236
|
resource.body = Object.fromEntries(formData);
|
|
240
237
|
} else {
|
|
241
238
|
if (contactEmail === undefined) {
|
|
@@ -274,9 +271,10 @@ const Outlet = () => {
|
|
|
274
271
|
return (
|
|
275
272
|
<ReactSdkContext.Provider
|
|
276
273
|
value={{
|
|
277
|
-
|
|
278
|
-
assetBaseUrl,
|
|
274
|
+
...constants,
|
|
279
275
|
resources,
|
|
276
|
+
breakpoints,
|
|
277
|
+
onError: console.error,
|
|
280
278
|
}}
|
|
281
279
|
>
|
|
282
280
|
{/* Use the URL as the key to force scripts in HTML Embed to reload on dynamic pages */}
|
|
@@ -286,7 +284,8 @@ const Outlet = () => {
|
|
|
286
284
|
pageMeta={pageMeta}
|
|
287
285
|
host={host}
|
|
288
286
|
siteName={siteName}
|
|
289
|
-
imageLoader={imageLoader}
|
|
287
|
+
imageLoader={constants.imageLoader}
|
|
288
|
+
assetBaseUrl={constants.assetBaseUrl}
|
|
290
289
|
/>
|
|
291
290
|
<PageSettingsTitle>{pageMeta.title}</PageSettingsTitle>
|
|
292
291
|
<PageSettingsCanonicalLink href={url} />
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
ReactSdkContext,
|
|
6
6
|
xmlNodeTagSuffix,
|
|
7
7
|
} from "@webstudio-is/react-sdk/runtime";
|
|
8
|
-
import { Page } from "__CLIENT__";
|
|
8
|
+
import { Page, breakpoints } from "__CLIENT__";
|
|
9
9
|
import { getPageMeta, getRemixParams, getResources } from "__SERVER__";
|
|
10
10
|
import { assetBaseUrl, imageLoader } from "__CONSTANTS__";
|
|
11
11
|
import { sitemap } from "__SITEMAP__";
|
|
@@ -65,16 +65,14 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
65
65
|
imageLoader,
|
|
66
66
|
assetBaseUrl,
|
|
67
67
|
resources,
|
|
68
|
+
breakpoints,
|
|
69
|
+
onError: console.error,
|
|
68
70
|
}}
|
|
69
71
|
>
|
|
70
72
|
<Page system={system} />
|
|
71
73
|
</ReactSdkContext.Provider>
|
|
72
74
|
);
|
|
73
75
|
|
|
74
|
-
// Xml is wrapped with <svg> to prevent React from hoisting elements like <title>, <meta>, and <link> out of their intended scope during rendering.
|
|
75
|
-
// More details: https://github.com/facebook/react/blob/7c8e5e7ab8bb63de911637892392c5efd8ce1d0f/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js#L3083
|
|
76
|
-
text = text.replace(/^<svg>/g, "").replace(/<\/svg>$/g, "");
|
|
77
|
-
|
|
78
76
|
// React has issues rendering certain elements, such as errors when a <link> element has children.
|
|
79
77
|
// To render XML, we wrap it with an <svg> tag and add a suffix to avoid React's default behavior on these elements.
|
|
80
78
|
text = text.replaceAll(xmlNodeTagSuffix, "");
|
|
@@ -8,26 +8,26 @@
|
|
|
8
8
|
"typecheck": "tsc"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@remix-run/node": "2.
|
|
12
|
-
"@remix-run/react": "2.
|
|
13
|
-
"@remix-run/server-runtime": "2.
|
|
14
|
-
"@webstudio-is/image": "0.0.0-
|
|
15
|
-
"@webstudio-is/react-sdk": "0.0.0-
|
|
16
|
-
"@webstudio-is/sdk": "0.0.0-
|
|
17
|
-
"@webstudio-is/sdk-components-react": "0.0.0-
|
|
18
|
-
"@webstudio-is/sdk-components-animation": "0.0.0-
|
|
19
|
-
"@webstudio-is/sdk-components-react-radix": "0.0.0-
|
|
20
|
-
"@webstudio-is/sdk-components-react-remix": "0.0.0-
|
|
21
|
-
"isbot": "^5.1.
|
|
11
|
+
"@remix-run/node": "2.16.5",
|
|
12
|
+
"@remix-run/react": "2.16.5",
|
|
13
|
+
"@remix-run/server-runtime": "2.16.5",
|
|
14
|
+
"@webstudio-is/image": "0.0.0-73cd6ea",
|
|
15
|
+
"@webstudio-is/react-sdk": "0.0.0-73cd6ea",
|
|
16
|
+
"@webstudio-is/sdk": "0.0.0-73cd6ea",
|
|
17
|
+
"@webstudio-is/sdk-components-react": "0.0.0-73cd6ea",
|
|
18
|
+
"@webstudio-is/sdk-components-animation": "0.0.0-73cd6ea",
|
|
19
|
+
"@webstudio-is/sdk-components-react-radix": "0.0.0-73cd6ea",
|
|
20
|
+
"@webstudio-is/sdk-components-react-remix": "0.0.0-73cd6ea",
|
|
21
|
+
"isbot": "^5.1.25",
|
|
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": "2.
|
|
26
|
+
"@remix-run/dev": "2.16.5",
|
|
27
27
|
"@types/react": "^18.2.70",
|
|
28
28
|
"@types/react-dom": "^18.2.25",
|
|
29
|
-
"typescript": "5.
|
|
30
|
-
"vite": "^
|
|
29
|
+
"typescript": "5.8.2",
|
|
30
|
+
"vite": "^6.3.4"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
33
|
"node": ">=20.0.0"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { Links, Meta, Outlet, useMatches } from "react-router";
|
|
4
4
|
// @todo think about how to make __generated__ typeable
|
|
5
5
|
// @ts-ignore
|
|
6
|
-
import { CustomCode } from "./__generated__/_index";
|
|
6
|
+
import { CustomCode, projectId, lastPublished } from "./__generated__/_index";
|
|
7
7
|
|
|
8
8
|
const Root = () => {
|
|
9
9
|
// Get language from matches
|
|
@@ -19,7 +19,11 @@ const Root = () => {
|
|
|
19
19
|
const lang = lastMatchWithLanguage?.data?.pageMeta?.language ?? "en";
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
|
-
<html
|
|
22
|
+
<html
|
|
23
|
+
lang={lang}
|
|
24
|
+
data-ws-project={projectId}
|
|
25
|
+
data-ws-last-published={lastPublished}
|
|
26
|
+
>
|
|
23
27
|
<head>
|
|
24
28
|
<meta charSet="utf-8" />
|
|
25
29
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
@@ -22,20 +22,21 @@ import {
|
|
|
22
22
|
PageSettingsTitle,
|
|
23
23
|
} from "@webstudio-is/react-sdk/runtime";
|
|
24
24
|
import {
|
|
25
|
+
projectId,
|
|
25
26
|
Page,
|
|
26
27
|
siteName,
|
|
27
28
|
favIconAsset,
|
|
28
29
|
pageFontAssets,
|
|
29
30
|
pageBackgroundImageAssets,
|
|
31
|
+
breakpoints,
|
|
30
32
|
} from "__CLIENT__";
|
|
31
33
|
import {
|
|
32
34
|
getResources,
|
|
33
35
|
getPageMeta,
|
|
34
36
|
getRemixParams,
|
|
35
|
-
projectId,
|
|
36
37
|
contactEmail,
|
|
37
38
|
} from "__SERVER__";
|
|
38
|
-
import
|
|
39
|
+
import * as constants from "__CONSTANTS__";
|
|
39
40
|
import css from "__CSS__?url";
|
|
40
41
|
import { sitemap } from "__SITEMAP__";
|
|
41
42
|
|
|
@@ -149,8 +150,8 @@ export const links: LinksFunction = () => {
|
|
|
149
150
|
if (favIconAsset) {
|
|
150
151
|
result.push({
|
|
151
152
|
rel: "icon",
|
|
152
|
-
href: imageLoader({
|
|
153
|
-
src: `${assetBaseUrl}${favIconAsset
|
|
153
|
+
href: constants.imageLoader({
|
|
154
|
+
src: `${constants.assetBaseUrl}${favIconAsset}`,
|
|
154
155
|
// width,height must be multiple of 48 https://developers.google.com/search/docs/appearance/favicon-in-search
|
|
155
156
|
width: 144,
|
|
156
157
|
height: 144,
|
|
@@ -165,7 +166,7 @@ export const links: LinksFunction = () => {
|
|
|
165
166
|
for (const asset of pageFontAssets) {
|
|
166
167
|
result.push({
|
|
167
168
|
rel: "preload",
|
|
168
|
-
href: `${assetBaseUrl}${asset
|
|
169
|
+
href: `${constants.assetBaseUrl}${asset}`,
|
|
169
170
|
as: "font",
|
|
170
171
|
crossOrigin: "anonymous",
|
|
171
172
|
});
|
|
@@ -174,7 +175,7 @@ export const links: LinksFunction = () => {
|
|
|
174
175
|
for (const backgroundImageAsset of pageBackgroundImageAssets) {
|
|
175
176
|
result.push({
|
|
176
177
|
rel: "preload",
|
|
177
|
-
href: `${assetBaseUrl}${backgroundImageAsset
|
|
178
|
+
href: `${constants.assetBaseUrl}${backgroundImageAsset}`,
|
|
178
179
|
as: "image",
|
|
179
180
|
});
|
|
180
181
|
}
|
|
@@ -231,10 +232,6 @@ export const action = async ({
|
|
|
231
232
|
formData.delete(formBotFieldName);
|
|
232
233
|
|
|
233
234
|
if (resource) {
|
|
234
|
-
resource.headers.push({
|
|
235
|
-
name: "Content-Type",
|
|
236
|
-
value: "application/json",
|
|
237
|
-
});
|
|
238
235
|
resource.body = Object.fromEntries(formData);
|
|
239
236
|
} else {
|
|
240
237
|
if (contactEmail === undefined) {
|
|
@@ -273,9 +270,10 @@ const Outlet = () => {
|
|
|
273
270
|
return (
|
|
274
271
|
<ReactSdkContext.Provider
|
|
275
272
|
value={{
|
|
276
|
-
|
|
277
|
-
assetBaseUrl,
|
|
273
|
+
...constants,
|
|
278
274
|
resources,
|
|
275
|
+
breakpoints,
|
|
276
|
+
onError: console.error,
|
|
279
277
|
}}
|
|
280
278
|
>
|
|
281
279
|
{/* Use the URL as the key to force scripts in HTML Embed to reload on dynamic pages */}
|
|
@@ -285,7 +283,8 @@ const Outlet = () => {
|
|
|
285
283
|
pageMeta={pageMeta}
|
|
286
284
|
host={host}
|
|
287
285
|
siteName={siteName}
|
|
288
|
-
imageLoader={imageLoader}
|
|
286
|
+
imageLoader={constants.imageLoader}
|
|
287
|
+
assetBaseUrl={constants.assetBaseUrl}
|
|
289
288
|
/>
|
|
290
289
|
<PageSettingsTitle>{pageMeta.title}</PageSettingsTitle>
|
|
291
290
|
</ReactSdkContext.Provider>
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
ReactSdkContext,
|
|
6
6
|
xmlNodeTagSuffix,
|
|
7
7
|
} from "@webstudio-is/react-sdk/runtime";
|
|
8
|
-
import { Page } from "__CLIENT__";
|
|
8
|
+
import { Page, breakpoints } from "__CLIENT__";
|
|
9
9
|
import { getPageMeta, getRemixParams, getResources } from "__SERVER__";
|
|
10
10
|
import { assetBaseUrl, imageLoader } from "__CONSTANTS__";
|
|
11
11
|
import { sitemap } from "__SITEMAP__";
|
|
@@ -65,6 +65,8 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
65
65
|
imageLoader,
|
|
66
66
|
assetBaseUrl,
|
|
67
67
|
resources,
|
|
68
|
+
breakpoints,
|
|
69
|
+
onError: console.error,
|
|
68
70
|
}}
|
|
69
71
|
>
|
|
70
72
|
<Page system={system} />
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"private": true,
|
|
4
|
+
"sideEffects": false,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "react-router build",
|
|
7
|
+
"dev": "react-router dev",
|
|
8
|
+
"typecheck": "tsc"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@react-router/dev": "^7.5.3",
|
|
12
|
+
"@react-router/fs-routes": "^7.5.3",
|
|
13
|
+
"@webstudio-is/image": "0.0.0-73cd6ea",
|
|
14
|
+
"@webstudio-is/react-sdk": "0.0.0-73cd6ea",
|
|
15
|
+
"@webstudio-is/sdk": "0.0.0-73cd6ea",
|
|
16
|
+
"@webstudio-is/sdk-components-animation": "0.0.0-73cd6ea",
|
|
17
|
+
"@webstudio-is/sdk-components-react-radix": "0.0.0-73cd6ea",
|
|
18
|
+
"@webstudio-is/sdk-components-react-router": "0.0.0-73cd6ea",
|
|
19
|
+
"@webstudio-is/sdk-components-react": "0.0.0-73cd6ea",
|
|
20
|
+
"isbot": "^5.1.25",
|
|
21
|
+
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
22
|
+
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|
|
23
|
+
"react-router": "^7.5.3",
|
|
24
|
+
"vite": "^6.3.4"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/react": "^18.2.70",
|
|
28
|
+
"@types/react-dom": "^18.2.25",
|
|
29
|
+
"typescript": "5.8.2"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20.0.0"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import { reactRouter } from "@react-router/dev/vite";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [reactRouter()],
|
|
6
|
+
resolve: {
|
|
7
|
+
conditions: ["browser", "development|production"],
|
|
8
|
+
},
|
|
9
|
+
ssr: {
|
|
10
|
+
resolve: {
|
|
11
|
+
conditions: ["node", "development|production"],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* We use mjs extension as constants in this file is shared with the build script
|
|
3
|
+
* and we use `node --eval` to extract the constants.
|
|
4
|
+
*/
|
|
5
|
+
export const assetBaseUrl = "/assets/";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @type {import("@webstudio-is/image").ImageLoader}
|
|
9
|
+
*/
|
|
10
|
+
export const imageLoader = (props) => {
|
|
11
|
+
if (import.meta.env.DEV) {
|
|
12
|
+
return props.src;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (props.format === "raw") {
|
|
16
|
+
return props.src;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// @todo https://developers.cloudflare.com/images/transform-images/transform-via-url/
|
|
20
|
+
return props.src;
|
|
21
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AppLoadContext, EntryContext } from "react-router";
|
|
2
|
+
import { ServerRouter } from "react-router";
|
|
3
|
+
import { isbot } from "isbot";
|
|
4
|
+
import { renderToReadableStream } from "react-dom/server";
|
|
5
|
+
|
|
6
|
+
export default async function handleRequest(
|
|
7
|
+
request: Request,
|
|
8
|
+
responseStatusCode: number,
|
|
9
|
+
responseHeaders: Headers,
|
|
10
|
+
routerContext: EntryContext,
|
|
11
|
+
_loadContext: AppLoadContext
|
|
12
|
+
) {
|
|
13
|
+
let shellRendered = false;
|
|
14
|
+
const userAgent = request.headers.get("user-agent");
|
|
15
|
+
|
|
16
|
+
const body = await renderToReadableStream(
|
|
17
|
+
<ServerRouter context={routerContext} url={request.url} />,
|
|
18
|
+
{
|
|
19
|
+
onError(error: unknown) {
|
|
20
|
+
responseStatusCode = 500;
|
|
21
|
+
// Log streaming rendering errors from inside the shell. Don't log
|
|
22
|
+
// errors encountered during initial shell rendering since they'll
|
|
23
|
+
// reject and get logged in handleDocumentRequest.
|
|
24
|
+
if (shellRendered) {
|
|
25
|
+
console.error(error);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
shellRendered = true;
|
|
31
|
+
|
|
32
|
+
// Ensure requests from bots and SPA Mode renders wait for all content to load before responding
|
|
33
|
+
// https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation
|
|
34
|
+
if ((userAgent && isbot(userAgent)) || routerContext.isSpaMode) {
|
|
35
|
+
await body.allReady;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
responseHeaders.set("Content-Type", "text/html");
|
|
39
|
+
return new Response(body, {
|
|
40
|
+
headers: responseHeaders,
|
|
41
|
+
status: responseStatusCode,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"typecheck": "wrangler types && tsc",
|
|
4
|
+
"typegen": "wrangler types",
|
|
5
|
+
"preview": "react-router build && vite preview",
|
|
6
|
+
"deploy": "react-router build && wrangler deploy"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@cloudflare/vite-plugin": "^1.1.0",
|
|
10
|
+
"wrangler": "^4.14.1"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["**/*.ts", "**/*.tsx", "**/*.mjs"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
5
|
+
"types": [
|
|
6
|
+
"./worker-configuration.d.ts",
|
|
7
|
+
"vite/client",
|
|
8
|
+
"@webstudio-is/react-sdk/placeholder"
|
|
9
|
+
],
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"jsx": "react-jsx",
|
|
13
|
+
"module": "ESNext",
|
|
14
|
+
"moduleResolution": "bundler",
|
|
15
|
+
"target": "ES2022",
|
|
16
|
+
"strict": true,
|
|
17
|
+
"allowJs": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"noEmit": true,
|
|
20
|
+
"skipLibCheck": true,
|
|
21
|
+
"customConditions": ["webstudio"]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import { cloudflare } from "@cloudflare/vite-plugin";
|
|
3
|
+
import { reactRouter } from "@react-router/dev/vite";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [cloudflare({ viteEnvironment: { name: "ssr" } }), reactRouter()],
|
|
7
|
+
resolve: {
|
|
8
|
+
conditions: ["browser", "development|production"],
|
|
9
|
+
},
|
|
10
|
+
ssr: {
|
|
11
|
+
resolve: {
|
|
12
|
+
conditions: ["node", "development|production"],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createRequestHandler } from "react-router";
|
|
2
|
+
|
|
3
|
+
declare module "react-router" {
|
|
4
|
+
export interface AppLoadContext {
|
|
5
|
+
cloudflare: {
|
|
6
|
+
env: Env;
|
|
7
|
+
ctx: ExecutionContext;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const requestHandler = createRequestHandler(
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
() => import("virtual:react-router/server-build"),
|
|
15
|
+
import.meta.env.MODE
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
async fetch(request, env, ctx) {
|
|
20
|
+
return requestHandler(request, {
|
|
21
|
+
EXCLUDE_FROM_SEARCH: false,
|
|
22
|
+
getDefaultActionResource: undefined,
|
|
23
|
+
cloudflare: { env, ctx },
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
} satisfies ExportedHandler<Env>;
|