webstudio 0.174.0 → 0.179.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
@@ -44,12 +44,41 @@ var zGlobalConfig = z.record(
44
44
  var jsonToGlobalConfig = (json) => {
45
45
  return zGlobalConfig.parse(json);
46
46
  };
47
- var PROJECT_TEMPALTES = [
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)" }
47
+ var PROJECT_TEMPLATES = [
48
+ {
49
+ value: "vanilla",
50
+ label: "Vanilla",
51
+ expand: ["defaults"]
52
+ },
53
+ { value: "vercel", label: "Vercel", expand: ["defaults", "vercel"] },
54
+ {
55
+ value: "netlify-functions",
56
+ label: "Netlify Functions",
57
+ expand: ["defaults", "netlify-functions"]
58
+ },
59
+ {
60
+ value: "netlify-edge-functions",
61
+ label: "Netlify Edge Functions",
62
+ expand: ["defaults", "netlify-edge-functions"]
63
+ },
64
+ { value: "ssg", label: "Static Site Generation (SSG)" },
65
+ {
66
+ value: "ssg-netlify",
67
+ label: "Static Site Generation (SSG) Netlify",
68
+ expand: ["ssg", "ssg-netlify"]
69
+ },
70
+ {
71
+ value: "ssg-vercel",
72
+ label: "Static Site Generation (SSG) Vercel",
73
+ expand: ["ssg", "ssg-vercel"]
74
+ }
75
+ ];
76
+ var INTERNAL_TEMPLATES = [
77
+ {
78
+ value: "cloudflare",
79
+ label: "Cloudflare",
80
+ expand: ["defaults", "cloudflare"]
81
+ }
53
82
  ];
54
83
 
55
84
  // src/fs-utils.ts
@@ -99,20 +128,23 @@ import { cwd, exit } from "node:process";
99
128
  import { join as join2 } from "node:path";
100
129
  import { readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
101
130
  import { cancel, isCancel, log, text } from "@clack/prompts";
131
+ import { parseBuilderUrl } from "@webstudio-is/http-client";
102
132
  var parseShareLink = (value) => {
103
133
  const url = new URL(value);
104
- const origin = url.origin;
105
134
  const token = url.searchParams.get("authToken");
106
- const segments = url.pathname.split("/").slice(1);
107
- if (segments.length !== 2 || segments[0] !== "builder") {
108
- throw Error("Segments not matching");
135
+ let { projectId, sourceOrigin } = parseBuilderUrl(url.href);
136
+ if (projectId === void 0) {
137
+ const segments = url.pathname.split("/").slice(1);
138
+ if (segments.length !== 2 || segments[0] !== "builder") {
139
+ throw Error("Segments not matching");
140
+ }
141
+ projectId = segments[1];
109
142
  }
110
- const [_builder, projectId] = segments;
111
143
  if (token == null) {
112
144
  throw Error("Token is missing");
113
145
  }
114
146
  return {
115
- origin,
147
+ origin: sourceOrigin,
116
148
  projectId,
117
149
  token
118
150
  };
@@ -180,7 +212,7 @@ import pc from "picocolors";
180
212
  import { spinner } from "@clack/prompts";
181
213
  import {
182
214
  loadProjectDataByBuildId,
183
- loadProjectDataById
215
+ loadProjectDataByProjectId
184
216
  } from "@webstudio-is/http-client";
185
217
  var syncOptions = (yargs) => yargs.option("buildId", {
186
218
  type: "string",
@@ -194,21 +226,13 @@ var syncOptions = (yargs) => yargs.option("buildId", {
194
226
  });
195
227
  var sync = async (options) => {
196
228
  const syncing = spinner();
197
- syncing.start("Synchronizing project data");
198
- const definedOptionValues = [
199
- options.buildId,
200
- options.origin,
201
- options.authToken
202
- ].filter(Boolean);
203
- if (definedOptionValues.length > 0 && definedOptionValues.length < 3) {
204
- syncing.stop(`Please provide buildId, origin and authToken`, 2);
205
- return;
206
- }
207
229
  let project;
230
+ syncing.start(`Synchronizing project data`);
208
231
  if (options.buildId !== void 0 && options.origin !== void 0 && options.authToken !== void 0) {
232
+ syncing.message(`Synchronizing project data from ${options.origin}`);
209
233
  project = await loadProjectDataByBuildId({
210
234
  buildId: options.buildId,
211
- authToken: options.authToken,
235
+ seviceToken: options.authToken,
212
236
  origin: options.origin
213
237
  });
214
238
  } else {
@@ -235,8 +259,13 @@ var sync = async (options) => {
235
259
  return;
236
260
  }
237
261
  const { origin, token } = projectConfig;
262
+ syncing.message(`Synchronizing project data from ${origin}`);
238
263
  try {
239
- project = await loadProjectDataById({
264
+ project = options.buildId !== void 0 ? await loadProjectDataByBuildId({
265
+ buildId: options.buildId,
266
+ authToken: token,
267
+ origin
268
+ }) : await loadProjectDataByProjectId({
240
269
  projectId: localConfig.projectId,
241
270
  authToken: token,
242
271
  origin
@@ -659,9 +688,6 @@ Please check webstudio --help for more details`
659
688
  exit2(1);
660
689
  }
661
690
  for (const template of options.template) {
662
- if (template === "vanilla" || template === "ssg") {
663
- continue;
664
- }
665
691
  if (template.startsWith(".") || template.startsWith("/")) {
666
692
  continue;
667
693
  }
@@ -679,12 +705,8 @@ Please check webstudio --help for more details`
679
705
  await rm3(generatedDir, { recursive: true, force: true });
680
706
  const routesDir = join6(appRoot, "routes");
681
707
  await rm3(routesDir, { recursive: true, force: true });
682
- await copyTemplates(options.template.includes("ssg") ? "ssg" : "defaults");
683
708
  await writeFile4(join6(cwd3(), ".npmrc"), "force=true");
684
709
  for (const template of options.template) {
685
- if (template === "vanilla" || template === "ssg") {
686
- continue;
687
- }
688
710
  await copyTemplates(template);
689
711
  }
690
712
  let framework;
@@ -851,6 +873,7 @@ Please check webstudio --help for more details`
851
873
  "useState",
852
874
  "Fragment",
853
875
  "useResource",
876
+ "useVariableState",
854
877
  "Page",
855
878
  "_props"
856
879
  ]);
@@ -948,7 +971,7 @@ Please check webstudio --help for more details`
948
971
 
949
972
  import { Fragment, useState } from "react";
950
973
  import type { FontAsset, ImageAsset } from "@webstudio-is/sdk";
951
- import { useResource } from "@webstudio-is/react-sdk";
974
+ import { useResource, useVariableState } from "@webstudio-is/react-sdk/runtime";
952
975
  ${componentImports}
953
976
 
954
977
  export const siteName = ${JSON.stringify(projectMeta?.siteName)};
@@ -1102,7 +1125,23 @@ var buildOptions = (yargs) => yargs.option("assets", {
1102
1125
  type: "array",
1103
1126
  string: true,
1104
1127
  default: [],
1105
- describe: `Template to use for the build [choices: ${PROJECT_TEMPALTES.map(
1128
+ coerce: (values) => {
1129
+ const templates = [];
1130
+ for (const value of values) {
1131
+ const template = PROJECT_TEMPLATES.find((item) => item.value === value) ?? INTERNAL_TEMPLATES.find((item) => item.value === value);
1132
+ if (template == null) {
1133
+ templates.push(value);
1134
+ continue;
1135
+ }
1136
+ if ("expand" in template && template.expand != null) {
1137
+ templates.push(...template.expand);
1138
+ continue;
1139
+ }
1140
+ templates.push(value);
1141
+ }
1142
+ return templates;
1143
+ },
1144
+ describe: `Template to use for the build [choices: ${PROJECT_TEMPLATES.map(
1106
1145
  (item) => item.value
1107
1146
  ).join(", ")}]`
1108
1147
  });
@@ -1178,7 +1217,7 @@ var initFlow = async (options) => {
1178
1217
  projectTemplate = exitIfCancelled(
1179
1218
  await select({
1180
1219
  message: "Where would you like to deploy your project?",
1181
- options: PROJECT_TEMPALTES
1220
+ options: PROJECT_TEMPLATES
1182
1221
  })
1183
1222
  );
1184
1223
  shouldInstallDeps = exitIfCancelled(
@@ -1192,7 +1231,7 @@ var initFlow = async (options) => {
1192
1231
  projectTemplate = exitIfCancelled(
1193
1232
  await select({
1194
1233
  message: "Where would you like to deploy your project?",
1195
- options: PROJECT_TEMPALTES
1234
+ options: PROJECT_TEMPLATES
1196
1235
  })
1197
1236
  );
1198
1237
  }
@@ -1242,7 +1281,7 @@ import makeCLI from "yargs";
1242
1281
  // package.json
1243
1282
  var package_default = {
1244
1283
  name: "webstudio",
1245
- version: "0.174.0",
1284
+ version: "0.179.0",
1246
1285
  description: "Webstudio CLI",
1247
1286
  author: "Webstudio <github@webstudio.is>",
1248
1287
  homepage: "https://webstudio.is",
@@ -1296,25 +1335,25 @@ var package_default = {
1296
1335
  "@jest/globals": "^29.7.0",
1297
1336
  "@netlify/remix-adapter": "^2.4.0",
1298
1337
  "@netlify/remix-edge-adapter": "3.3.0",
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",
1338
+ "@remix-run/cloudflare": "^2.11.0",
1339
+ "@remix-run/cloudflare-pages": "^2.11.0",
1340
+ "@remix-run/dev": "^2.11.0",
1341
+ "@remix-run/node": "^2.11.0",
1342
+ "@remix-run/react": "^2.11.0",
1343
+ "@remix-run/server-runtime": "^2.11.0",
1305
1344
  "@types/node": "^20.12.7",
1306
1345
  "@types/react": "^18.2.70",
1307
1346
  "@types/react-dom": "^18.2.25",
1308
1347
  "@types/yargs": "^17.0.32",
1309
1348
  "@vitejs/plugin-react": "^4.3.1",
1310
- "@webstudio-is/form-handlers": "workspace:*",
1311
1349
  "@webstudio-is/jest-config": "workspace:*",
1312
1350
  "@webstudio-is/tsconfig": "workspace:*",
1313
1351
  react: "18.3.0-canary-14898b6a9-20240318",
1314
1352
  "react-dom": "18.3.0-canary-14898b6a9-20240318",
1353
+ "ts-expect": "^1.3.0",
1315
1354
  typescript: "5.5.2",
1316
- vike: "^0.4.180",
1317
- vite: "^5.3.4",
1355
+ vike: "^0.4.182",
1356
+ vite: "^5.4.0",
1318
1357
  wrangler: "^3.63.2"
1319
1358
  }
1320
1359
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webstudio",
3
- "version": "0.174.0",
3
+ "version": "0.179.0",
4
4
  "description": "Webstudio CLI",
5
5
  "author": "Webstudio <github@webstudio.is>",
6
6
  "homepage": "https://webstudio.is",
@@ -37,24 +37,24 @@
37
37
  "strip-indent": "^4.0.0",
38
38
  "yargs": "^17.7.2",
39
39
  "zod": "^3.22.4",
40
- "@webstudio-is/http-client": "0.174.0",
41
- "@webstudio-is/image": "0.174.0",
42
- "@webstudio-is/sdk-components-react": "0.174.0",
43
- "@webstudio-is/react-sdk": "0.174.0",
44
- "@webstudio-is/sdk": "0.174.0",
45
- "@webstudio-is/sdk-components-react-radix": "0.174.0",
46
- "@webstudio-is/sdk-components-react-remix": "0.174.0"
40
+ "@webstudio-is/http-client": "0.179.0",
41
+ "@webstudio-is/image": "0.179.0",
42
+ "@webstudio-is/sdk": "0.179.0",
43
+ "@webstudio-is/sdk-components-react": "0.179.0",
44
+ "@webstudio-is/react-sdk": "0.179.0",
45
+ "@webstudio-is/sdk-components-react-radix": "0.179.0",
46
+ "@webstudio-is/sdk-components-react-remix": "0.179.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@jest/globals": "^29.7.0",
50
50
  "@netlify/remix-adapter": "^2.4.0",
51
51
  "@netlify/remix-edge-adapter": "3.3.0",
52
- "@remix-run/cloudflare": "^2.10.3",
53
- "@remix-run/cloudflare-pages": "^2.10.3",
54
- "@remix-run/dev": "^2.10.3",
55
- "@remix-run/node": "^2.10.3",
56
- "@remix-run/react": "^2.10.3",
57
- "@remix-run/server-runtime": "^2.10.3",
52
+ "@remix-run/cloudflare": "^2.11.0",
53
+ "@remix-run/cloudflare-pages": "^2.11.0",
54
+ "@remix-run/dev": "^2.11.0",
55
+ "@remix-run/node": "^2.11.0",
56
+ "@remix-run/react": "^2.11.0",
57
+ "@remix-run/server-runtime": "^2.11.0",
58
58
  "@types/node": "^20.12.7",
59
59
  "@types/react": "^18.2.70",
60
60
  "@types/react-dom": "^18.2.25",
@@ -62,11 +62,11 @@
62
62
  "@vitejs/plugin-react": "^4.3.1",
63
63
  "react": "18.3.0-canary-14898b6a9-20240318",
64
64
  "react-dom": "18.3.0-canary-14898b6a9-20240318",
65
+ "ts-expect": "^1.3.0",
65
66
  "typescript": "5.5.2",
66
- "vike": "^0.4.180",
67
- "vite": "^5.3.4",
67
+ "vike": "^0.4.182",
68
+ "vite": "^5.4.0",
68
69
  "wrangler": "^3.63.2",
69
- "@webstudio-is/form-handlers": "0.174.0",
70
70
  "@webstudio-is/jest-config": "1.0.7",
71
71
  "@webstudio-is/tsconfig": "1.0.7"
72
72
  },
@@ -12,8 +12,8 @@
12
12
  "build-cf-types": "wrangler types"
13
13
  },
14
14
  "dependencies": {
15
- "@remix-run/cloudflare": "2.10.3",
16
- "@remix-run/cloudflare-pages": "2.10.3"
15
+ "@remix-run/cloudflare": "2.11.0",
16
+ "@remix-run/cloudflare-pages": "2.11.0"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@cloudflare/workers-types": "^4.20240620.0",
@@ -1,10 +1,16 @@
1
1
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
2
  // @ts-ignore
3
3
  import { AppLoadContext } from "@remix-run/server-runtime";
4
+ import { ResourceRequest } from "@webstudio-is/sdk";
4
5
 
5
6
  declare module "@remix-run/server-runtime" {
6
7
  interface AppLoadContext {
7
8
  EXCLUDE_FROM_SEARCH: boolean;
8
- N8N_FORM_EMAIL_HOOK: string;
9
+ getDefaultActionResource?: (options: {
10
+ url: URL;
11
+ projectId: string;
12
+ contactEmail: string;
13
+ formData: FormData;
14
+ }) => ResourceRequest;
9
15
  }
10
16
  }
@@ -1,4 +1,3 @@
1
- /* eslint-disable camelcase */
2
1
  import {
3
2
  type ServerRuntimeMetaFunction as MetaFunction,
4
3
  type LinksFunction,
@@ -14,13 +13,10 @@ import {
14
13
  isLocalResource,
15
14
  loadResource,
16
15
  loadResources,
17
- } from "@webstudio-is/sdk";
18
- import { ReactSdkContext } from "@webstudio-is/react-sdk";
19
- import {
20
- n8nHandler,
21
16
  formIdFieldName,
22
17
  formBotFieldName,
23
- } from "@webstudio-is/form-handlers";
18
+ } from "@webstudio-is/sdk";
19
+ import { ReactSdkContext } from "@webstudio-is/react-sdk/runtime";
24
20
  import {
25
21
  Page,
26
22
  siteName,
@@ -251,19 +247,19 @@ export const action = async ({
251
247
  { success: true } | { success: false; errors: string[] }
252
248
  > => {
253
249
  try {
254
- const pageUrl = new URL(request.url);
255
- pageUrl.host = getRequestHost(request);
250
+ const url = new URL(request.url);
251
+ url.host = getRequestHost(request);
256
252
 
257
253
  const formData = await request.formData();
258
254
 
259
255
  const system = {
260
256
  params: {},
261
257
  search: {},
262
- origin: pageUrl.origin,
258
+ origin: url.origin,
263
259
  };
264
260
 
265
261
  const resourceName = formData.get(formIdFieldName);
266
- const resource =
262
+ let resource =
267
263
  typeof resourceName === "string"
268
264
  ? getResources({ system }).action.get(resourceName)
269
265
  : undefined;
@@ -290,32 +286,32 @@ export const action = async ({
290
286
  formData.delete(formBotFieldName);
291
287
 
292
288
  if (resource) {
293
- const { ok, statusText } = await loadResource(fetch, {
294
- ...resource,
295
- body: Object.fromEntries(formData),
289
+ resource.headers.push({
290
+ name: "Content-Type",
291
+ value: "application/json",
296
292
  });
297
- if (ok) {
298
- return { success: true };
293
+ resource.body = Object.fromEntries(formData);
294
+ } else {
295
+ if (contactEmail === undefined) {
296
+ throw new Error("Contact email not found");
299
297
  }
300
- return { success: false, errors: [statusText] };
301
- }
302
-
303
- if (contactEmail === undefined) {
304
- throw new Error("Contact email not found");
305
- }
306
298
 
307
- const result = await n8nHandler({
308
- formInfo: {
309
- formId: projectId,
299
+ resource = context.getDefaultActionResource?.({
300
+ url,
301
+ projectId,
302
+ contactEmail,
310
303
  formData,
311
- pageUrl: pageUrl.toString(),
312
- toEmail: contactEmail,
313
- fromEmail: pageUrl.hostname + "@webstudio.email",
314
- },
315
- hookUrl: context.N8N_FORM_EMAIL_HOOK,
316
- });
304
+ });
305
+ }
317
306
 
318
- return result;
307
+ if (resource === undefined) {
308
+ throw Error("Resource not found");
309
+ }
310
+ const { ok, statusText } = await loadResource(fetch, resource);
311
+ if (ok) {
312
+ return { success: true };
313
+ }
314
+ return { success: false, errors: [statusText] };
319
315
  } catch (error) {
320
316
  console.error(error);
321
317
 
@@ -1,8 +1,7 @@
1
- /* eslint-disable camelcase */
2
1
  import { renderToString } from "react-dom/server";
3
2
  import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
4
3
  import { isLocalResource, loadResources } from "@webstudio-is/sdk";
5
- import { ReactSdkContext } from "@webstudio-is/react-sdk";
4
+ import { ReactSdkContext } from "@webstudio-is/react-sdk/runtime";
6
5
  import { Page } from "__CLIENT__";
7
6
  import { getPageMeta, getRemixParams, getResources } from "__SERVER__";
8
7
  import { assetBaseUrl, imageBaseUrl, imageLoader } from "__CONSTANTS__";
@@ -8,26 +8,25 @@
8
8
  "typecheck": "tsc"
9
9
  },
10
10
  "dependencies": {
11
- "@remix-run/node": "2.10.3",
12
- "@remix-run/react": "2.10.3",
13
- "@remix-run/server-runtime": "2.10.3",
14
- "@webstudio-is/react-sdk": "0.174.0",
15
- "@webstudio-is/sdk-components-react-radix": "0.174.0",
16
- "@webstudio-is/sdk-components-react-remix": "0.174.0",
17
- "@webstudio-is/sdk-components-react": "0.174.0",
18
- "@webstudio-is/form-handlers": "0.174.0",
19
- "@webstudio-is/image": "0.174.0",
20
- "@webstudio-is/sdk": "0.174.0",
21
- "isbot": "^5.1.13",
11
+ "@remix-run/node": "2.11.0",
12
+ "@remix-run/react": "2.11.0",
13
+ "@remix-run/server-runtime": "2.11.0",
14
+ "@webstudio-is/react-sdk": "0.179.0",
15
+ "@webstudio-is/sdk-components-react-radix": "0.179.0",
16
+ "@webstudio-is/sdk-components-react-remix": "0.179.0",
17
+ "@webstudio-is/sdk-components-react": "0.179.0",
18
+ "@webstudio-is/image": "0.179.0",
19
+ "@webstudio-is/sdk": "0.179.0",
20
+ "isbot": "^5.1.17",
22
21
  "react": "18.3.0-canary-14898b6a9-20240318",
23
22
  "react-dom": "18.3.0-canary-14898b6a9-20240318"
24
23
  },
25
24
  "devDependencies": {
26
- "@remix-run/dev": "2.10.3",
25
+ "@remix-run/dev": "2.11.0",
27
26
  "@types/react": "^18.2.70",
28
27
  "@types/react-dom": "^18.2.25",
29
28
  "typescript": "5.5.2",
30
- "vite": "^5.3.4"
29
+ "vite": "^5.4.0"
31
30
  },
32
31
  "engines": {
33
32
  "node": ">=20.0.0"
@@ -4,7 +4,6 @@
4
4
  "@webstudio-is/sdk-components-react-radix": "workspace:*",
5
5
  "@webstudio-is/sdk-components-react-remix": "workspace:*",
6
6
  "@webstudio-is/sdk-components-react": "workspace:*",
7
- "@webstudio-is/form-handlers": "workspace:*",
8
7
  "@webstudio-is/image": "workspace:*",
9
8
  "@webstudio-is/sdk": "workspace:*"
10
9
  }
@@ -1,5 +1,5 @@
1
1
  import type { PageContext } from "vike/types";
2
- import { ReactSdkContext } from "@webstudio-is/react-sdk";
2
+ import { ReactSdkContext } from "@webstudio-is/react-sdk/runtime";
3
3
  import { assetBaseUrl, imageBaseUrl, imageLoader } from "__CONSTANTS__";
4
4
  import { Page } from "__CLIENT__";
5
5
 
@@ -8,22 +8,21 @@
8
8
  "typecheck": "tsc"
9
9
  },
10
10
  "dependencies": {
11
- "@webstudio-is/react-sdk": "0.174.0",
12
- "@webstudio-is/sdk-components-react-radix": "0.174.0",
13
- "@webstudio-is/sdk-components-react": "0.174.0",
14
- "@webstudio-is/form-handlers": "0.174.0",
15
- "@webstudio-is/image": "0.174.0",
16
- "@webstudio-is/sdk": "0.174.0",
11
+ "@webstudio-is/react-sdk": "0.179.0",
12
+ "@webstudio-is/sdk-components-react-radix": "0.179.0",
13
+ "@webstudio-is/sdk-components-react": "0.179.0",
14
+ "@webstudio-is/image": "0.179.0",
15
+ "@webstudio-is/sdk": "0.179.0",
17
16
  "react": "18.3.0-canary-14898b6a9-20240318",
18
17
  "react-dom": "18.3.0-canary-14898b6a9-20240318",
19
- "vike": "^0.4.180"
18
+ "vike": "^0.4.182"
20
19
  },
21
20
  "devDependencies": {
22
21
  "@types/react": "^18.2.70",
23
22
  "@types/react-dom": "^18.2.25",
24
23
  "@vitejs/plugin-react": "^4.3.1",
25
24
  "typescript": "5.5.2",
26
- "vite": "^5.3.4"
25
+ "vite": "^5.4.0"
27
26
  },
28
27
  "engines": {
29
28
  "node": ">=20.0.0"
@@ -0,0 +1,33 @@
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
+ export const imageBaseUrl = "/assets/";
7
+
8
+ /**
9
+ * @type {import("@webstudio-is/image").ImageLoader}
10
+ */
11
+ export const imageLoader = (props) => {
12
+ if (URL.canParse(props.src)) {
13
+ return props.src;
14
+ }
15
+
16
+ if (process.env.NODE_ENV !== "production") {
17
+ return imageBaseUrl + props.src;
18
+ }
19
+
20
+ if (props.format === "raw") {
21
+ return imageBaseUrl + props.src;
22
+ }
23
+
24
+ // https://docs.netlify.com/image-cdn/overview/
25
+ return (
26
+ "/.netlify/images?url=" +
27
+ encodeURIComponent(imageBaseUrl + props.src) +
28
+ "&w=" +
29
+ props.width +
30
+ "&q=" +
31
+ props.quality
32
+ );
33
+ };
@@ -0,0 +1,33 @@
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
+ export const imageBaseUrl = "/assets/";
7
+
8
+ /**
9
+ * @type {import("@webstudio-is/image").ImageLoader}
10
+ */
11
+ export const imageLoader = (props) => {
12
+ if (URL.canParse(props.src)) {
13
+ return props.src;
14
+ }
15
+
16
+ if (process.env.NODE_ENV !== "production") {
17
+ return imageBaseUrl + props.src;
18
+ }
19
+
20
+ if (props.format === "raw") {
21
+ return imageBaseUrl + props.src;
22
+ }
23
+
24
+ // https://vercel.com/blog/build-your-own-web-framework#automatic-image-optimization
25
+ return (
26
+ "/_vercel/image?url=" +
27
+ encodeURIComponent(imageBaseUrl + props.src) +
28
+ "&w=" +
29
+ props.width +
30
+ "&q=" +
31
+ props.quality
32
+ );
33
+ };
@@ -0,0 +1,11 @@
1
+ {
2
+ "images": {
3
+ "domains": [],
4
+ "sizes": [
5
+ 16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048,
6
+ 3840
7
+ ],
8
+ "minimumCacheTTL": 60,
9
+ "formats": ["image/webp", "image/avif"]
10
+ }
11
+ }