webstudio 0.163.0 → 0.168.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/README.md +1 -1
- package/bin.js +1 -1
- package/lib/cli.js +347 -193
- package/package.json +35 -25
- package/templates/cloudflare/package.json +3 -3
- package/templates/cloudflare/tsconfig.json +1 -1
- package/templates/defaults/app/root.tsx +20 -2
- package/templates/defaults/app/route-templates/html.tsx +4 -15
- package/templates/defaults/package.json +13 -13
- package/templates/defaults/tsconfig.json +1 -1
- package/templates/internal/tsconfig.json +1 -1
- package/templates/netlify-edge-functions/package.json +2 -2
- package/templates/netlify-functions/package.json +2 -2
- package/templates/saas-helpers/tsconfig.json +1 -1
package/README.md
CHANGED
package/bin.js
CHANGED
package/lib/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/cli.ts
|
|
2
|
-
import { exit, argv } from "node:process";
|
|
2
|
+
import { exit as exit4, argv } from "node:process";
|
|
3
3
|
import { hideBin } from "yargs/helpers";
|
|
4
4
|
|
|
5
5
|
// src/config.ts
|
|
@@ -94,10 +94,41 @@ var loadJSONFile = async (filePath) => {
|
|
|
94
94
|
};
|
|
95
95
|
|
|
96
96
|
// src/commands/link.ts
|
|
97
|
-
import {
|
|
97
|
+
import { cwd, exit } from "node:process";
|
|
98
98
|
import { join as join2 } from "node:path";
|
|
99
|
-
import * as readline from "node:readline/promises";
|
|
100
99
|
import { readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
100
|
+
import { cancel, isCancel, log, text } from "@clack/prompts";
|
|
101
|
+
var parseShareLink = (value) => {
|
|
102
|
+
const url = new URL(value);
|
|
103
|
+
const origin = url.origin;
|
|
104
|
+
const token = url.searchParams.get("authToken");
|
|
105
|
+
const segments = url.pathname.split("/").slice(1);
|
|
106
|
+
if (segments.length !== 2 || segments[0] !== "builder") {
|
|
107
|
+
throw Error("Segments not matching");
|
|
108
|
+
}
|
|
109
|
+
const [_builder, projectId] = segments;
|
|
110
|
+
if (token == null) {
|
|
111
|
+
throw Error("Token is missing");
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
origin,
|
|
115
|
+
projectId,
|
|
116
|
+
token
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
var validateShareLink = (value) => {
|
|
120
|
+
if (value.length === 0) {
|
|
121
|
+
return "Share link is required";
|
|
122
|
+
}
|
|
123
|
+
if (URL.canParse(value) === false) {
|
|
124
|
+
return "Share link is invalid";
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
parseShareLink(value);
|
|
128
|
+
} catch {
|
|
129
|
+
return "Share link is invalid";
|
|
130
|
+
}
|
|
131
|
+
};
|
|
101
132
|
var linkOptions = (yargs) => yargs.option("link", {
|
|
102
133
|
alias: "l",
|
|
103
134
|
type: "string",
|
|
@@ -108,62 +139,48 @@ var link = async (options) => {
|
|
|
108
139
|
if (options.link) {
|
|
109
140
|
shareLink = options.link;
|
|
110
141
|
} else {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const origin = shareLinkUrl.origin;
|
|
119
|
-
const token = shareLinkUrl.searchParams.get("authToken");
|
|
120
|
-
const paths = shareLinkUrl.pathname.split("/").slice(1);
|
|
121
|
-
if (paths[0] !== "builder" || paths.length !== 2) {
|
|
122
|
-
throw new Error("Invalid share link.");
|
|
123
|
-
}
|
|
124
|
-
const projectId = paths[1];
|
|
125
|
-
if (token == null) {
|
|
126
|
-
throw new Error("Invalid share link.");
|
|
127
|
-
}
|
|
128
|
-
try {
|
|
129
|
-
const currentConfig = await readFile2(GLOBAL_CONFIG_FILE, "utf-8");
|
|
130
|
-
const currentConfigJson = jsonToGlobalConfig(JSON.parse(currentConfig));
|
|
131
|
-
const newConfig = {
|
|
132
|
-
...currentConfigJson,
|
|
133
|
-
[projectId]: {
|
|
134
|
-
origin,
|
|
135
|
-
token
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
await writeFile2(GLOBAL_CONFIG_FILE, JSON.stringify(newConfig, null, 2));
|
|
139
|
-
console.info(`Saved credentials for project ${projectId}.
|
|
140
|
-
You can find your config at ${GLOBAL_CONFIG_FILE}
|
|
141
|
-
`);
|
|
142
|
-
const localConfig = {
|
|
143
|
-
projectId
|
|
144
|
-
};
|
|
145
|
-
await createFileIfNotExists(
|
|
146
|
-
join2(cwd(), LOCAL_CONFIG_FILE),
|
|
147
|
-
JSON.stringify(localConfig, null, 2)
|
|
148
|
-
);
|
|
149
|
-
} catch (error) {
|
|
150
|
-
if (error instanceof Error && "code" in error && error.code === "ENONET") {
|
|
151
|
-
throw new Error(`Global config file is not found`);
|
|
142
|
+
shareLink = await text({
|
|
143
|
+
message: "Please paste a link from the Share Dialog in the builder",
|
|
144
|
+
validate: validateShareLink
|
|
145
|
+
});
|
|
146
|
+
if (isCancel(shareLink)) {
|
|
147
|
+
cancel("Project linking is cancelled");
|
|
148
|
+
exit(1);
|
|
152
149
|
}
|
|
153
|
-
throw error;
|
|
154
150
|
}
|
|
151
|
+
const { origin, projectId, token } = parseShareLink(shareLink);
|
|
152
|
+
const currentConfig = await readFile2(GLOBAL_CONFIG_FILE, "utf-8");
|
|
153
|
+
const currentConfigJson = jsonToGlobalConfig(JSON.parse(currentConfig));
|
|
154
|
+
const newConfig = {
|
|
155
|
+
...currentConfigJson,
|
|
156
|
+
[projectId]: {
|
|
157
|
+
origin,
|
|
158
|
+
token
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
await writeFile2(GLOBAL_CONFIG_FILE, JSON.stringify(newConfig, null, 2));
|
|
162
|
+
log.info(`Saved credentials for project ${projectId}.
|
|
163
|
+
You can find your config at ${GLOBAL_CONFIG_FILE}`);
|
|
164
|
+
const localConfig = {
|
|
165
|
+
projectId
|
|
166
|
+
};
|
|
167
|
+
await createFileIfNotExists(
|
|
168
|
+
join2(cwd(), LOCAL_CONFIG_FILE),
|
|
169
|
+
JSON.stringify(localConfig, null, 2)
|
|
170
|
+
);
|
|
171
|
+
log.step("The project is linked successfully");
|
|
155
172
|
};
|
|
156
173
|
|
|
157
174
|
// src/commands/sync.ts
|
|
158
175
|
import { readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
159
176
|
import { cwd as cwd2 } from "node:process";
|
|
160
177
|
import { join as join3 } from "node:path";
|
|
161
|
-
import
|
|
178
|
+
import pc from "picocolors";
|
|
179
|
+
import { spinner } from "@clack/prompts";
|
|
162
180
|
import {
|
|
163
181
|
loadProjectDataByBuildId,
|
|
164
182
|
loadProjectDataById
|
|
165
183
|
} from "@webstudio-is/http-client";
|
|
166
|
-
import pc from "picocolors";
|
|
167
184
|
var syncOptions = (yargs) => yargs.option("buildId", {
|
|
168
185
|
type: "string",
|
|
169
186
|
describe: "[Experimental] Project build id to sync"
|
|
@@ -175,15 +192,15 @@ var syncOptions = (yargs) => yargs.option("buildId", {
|
|
|
175
192
|
describe: "[Experimental] Service token"
|
|
176
193
|
});
|
|
177
194
|
var sync = async (options) => {
|
|
178
|
-
const
|
|
179
|
-
|
|
195
|
+
const syncing = spinner();
|
|
196
|
+
syncing.start("Synchronizing project data");
|
|
180
197
|
const definedOptionValues = [
|
|
181
198
|
options.buildId,
|
|
182
199
|
options.origin,
|
|
183
200
|
options.authToken
|
|
184
201
|
].filter(Boolean);
|
|
185
202
|
if (definedOptionValues.length > 0 && definedOptionValues.length < 3) {
|
|
186
|
-
|
|
203
|
+
syncing.stop(`Please provide buildId, origin and authToken`, 2);
|
|
187
204
|
return;
|
|
188
205
|
}
|
|
189
206
|
let project;
|
|
@@ -194,17 +211,12 @@ var sync = async (options) => {
|
|
|
194
211
|
origin: options.origin
|
|
195
212
|
});
|
|
196
213
|
} else {
|
|
197
|
-
if (await isFileExists(GLOBAL_CONFIG_FILE) === false) {
|
|
198
|
-
spinner.fail(
|
|
199
|
-
`Global config file at path ${GLOBAL_CONFIG_FILE} is not found. Please link your project using webstudio link command`
|
|
200
|
-
);
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
214
|
const globalConfigText = await readFile3(GLOBAL_CONFIG_FILE, "utf-8");
|
|
204
215
|
const globalConfig = jsonToGlobalConfig(JSON.parse(globalConfigText));
|
|
205
216
|
if (await isFileExists(LOCAL_CONFIG_FILE) === false) {
|
|
206
|
-
|
|
207
|
-
`Local config file is not found. Please make sure current directory is a webstudio project
|
|
217
|
+
syncing.stop(
|
|
218
|
+
`Local config file is not found. Please make sure current directory is a webstudio project`,
|
|
219
|
+
2
|
|
208
220
|
);
|
|
209
221
|
return;
|
|
210
222
|
}
|
|
@@ -215,29 +227,35 @@ var sync = async (options) => {
|
|
|
215
227
|
const localConfig = jsonToLocalConfig(JSON.parse(localConfigText));
|
|
216
228
|
const projectConfig = globalConfig[localConfig.projectId];
|
|
217
229
|
if (projectConfig === void 0) {
|
|
218
|
-
|
|
219
|
-
`Project config is not found, please run ${pc.dim("webstudio link")}
|
|
230
|
+
syncing.stop(
|
|
231
|
+
`Project config is not found, please run ${pc.dim("webstudio link")}`,
|
|
232
|
+
2
|
|
220
233
|
);
|
|
221
234
|
return;
|
|
222
235
|
}
|
|
223
236
|
const { origin, token } = projectConfig;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
237
|
+
try {
|
|
238
|
+
project = await loadProjectDataById({
|
|
239
|
+
projectId: localConfig.projectId,
|
|
240
|
+
authToken: token,
|
|
241
|
+
origin
|
|
242
|
+
});
|
|
243
|
+
} catch (error) {
|
|
244
|
+
syncing.stop(error.message, 2);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
230
247
|
}
|
|
231
248
|
project;
|
|
232
|
-
spinner.text = "Saving project data to config file";
|
|
233
249
|
const localBuildFilePath = join3(cwd2(), LOCAL_DATA_FILE);
|
|
234
250
|
await createFileIfNotExists(localBuildFilePath);
|
|
235
251
|
await writeFile3(localBuildFilePath, JSON.stringify(project, null, 2), "utf8");
|
|
236
|
-
|
|
252
|
+
syncing.stop("Project data synchronized successfully");
|
|
237
253
|
};
|
|
238
254
|
|
|
239
255
|
// src/commands/build.ts
|
|
240
256
|
import { access as access3 } from "node:fs/promises";
|
|
257
|
+
import { exit as exit3 } from "node:process";
|
|
258
|
+
import { log as log3 } from "@clack/prompts";
|
|
241
259
|
|
|
242
260
|
// src/prebuild.ts
|
|
243
261
|
import { basename, dirname as dirname2, join as join4, normalize } from "node:path";
|
|
@@ -252,10 +270,10 @@ import {
|
|
|
252
270
|
readdir
|
|
253
271
|
} from "node:fs/promises";
|
|
254
272
|
import { pipeline } from "node:stream/promises";
|
|
255
|
-
import { cwd as cwd3 } from "node:process";
|
|
273
|
+
import { cwd as cwd3, exit as exit2 } from "node:process";
|
|
256
274
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
257
275
|
import pLimit from "p-limit";
|
|
258
|
-
import
|
|
276
|
+
import { log as log2, spinner as spinner2 } from "@clack/prompts";
|
|
259
277
|
import merge from "deepmerge";
|
|
260
278
|
import {
|
|
261
279
|
generateCss,
|
|
@@ -281,6 +299,122 @@ import { createImageLoader } from "@webstudio-is/image";
|
|
|
281
299
|
import * as baseComponentMetas from "@webstudio-is/sdk-components-react/metas";
|
|
282
300
|
import * as remixComponentMetas from "@webstudio-is/sdk-components-react-remix/metas";
|
|
283
301
|
import * as radixComponentMetas from "@webstudio-is/sdk-components-react-radix/metas";
|
|
302
|
+
|
|
303
|
+
// src/html-to-jsx.ts
|
|
304
|
+
import {
|
|
305
|
+
parseFragment,
|
|
306
|
+
defaultTreeAdapter
|
|
307
|
+
} from "parse5";
|
|
308
|
+
import { camelCase } from "change-case";
|
|
309
|
+
var BOOLEAN_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
310
|
+
"async",
|
|
311
|
+
"autofocus",
|
|
312
|
+
"autoplay",
|
|
313
|
+
"checked",
|
|
314
|
+
"contenteditable",
|
|
315
|
+
"controls",
|
|
316
|
+
"default",
|
|
317
|
+
"defer",
|
|
318
|
+
"disabled",
|
|
319
|
+
"formnovalidate",
|
|
320
|
+
"hidden",
|
|
321
|
+
"ismap",
|
|
322
|
+
"itemscope",
|
|
323
|
+
"loop",
|
|
324
|
+
"multiple",
|
|
325
|
+
"muted",
|
|
326
|
+
"nomodule",
|
|
327
|
+
"novalidate",
|
|
328
|
+
"open",
|
|
329
|
+
"playsinline",
|
|
330
|
+
"readonly",
|
|
331
|
+
"required",
|
|
332
|
+
"reversed",
|
|
333
|
+
"scoped",
|
|
334
|
+
"selected",
|
|
335
|
+
"truespeed"
|
|
336
|
+
]);
|
|
337
|
+
var isBooleanAttr = (name) => BOOLEAN_ATTRIBUTES.has(name.toLowerCase());
|
|
338
|
+
function* walkChildNodes(node) {
|
|
339
|
+
if (defaultTreeAdapter.isCommentNode(node) || defaultTreeAdapter.isTextNode(node) || defaultTreeAdapter.isDocumentTypeNode(node)) {
|
|
340
|
+
throw new Error("Unsupported node type");
|
|
341
|
+
}
|
|
342
|
+
for (const childNode of node.childNodes) {
|
|
343
|
+
if (defaultTreeAdapter.isCommentNode(childNode)) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
if (defaultTreeAdapter.isTextNode(childNode)) {
|
|
347
|
+
yield { type: "text", value: childNode.value };
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (false === defaultTreeAdapter.isElementNode(childNode)) {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
const attributes = childNode.attrs.map((attr) => [
|
|
354
|
+
attr.name,
|
|
355
|
+
attr.value
|
|
356
|
+
]);
|
|
357
|
+
yield { type: "element-start", tagName: childNode.tagName, attributes };
|
|
358
|
+
yield* walkChildNodes(childNode);
|
|
359
|
+
yield { type: "element-end", tagName: childNode.tagName };
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
var convertStyleString = (style) => {
|
|
363
|
+
const styles = style.split(";").map((style2) => style2.trim()).map((style2) => style2.split(":").map((part) => part.trim()));
|
|
364
|
+
const res = {};
|
|
365
|
+
for (const [name, value] of styles) {
|
|
366
|
+
res[camelCase(name)] = value;
|
|
367
|
+
}
|
|
368
|
+
return JSON.stringify(res);
|
|
369
|
+
};
|
|
370
|
+
var escape = (value) => JSON.stringify(value);
|
|
371
|
+
var toAttrString = (name, value) => {
|
|
372
|
+
const attName = name.toLowerCase();
|
|
373
|
+
const jsxName = attName === "class" ? "className" : attName;
|
|
374
|
+
if (value === "" && isBooleanAttr(attName)) {
|
|
375
|
+
return `${jsxName}`;
|
|
376
|
+
}
|
|
377
|
+
if (attName === "style") {
|
|
378
|
+
return `${jsxName}={${convertStyleString(value)}}`;
|
|
379
|
+
}
|
|
380
|
+
return `${jsxName}={${escape(value)}}`;
|
|
381
|
+
};
|
|
382
|
+
var attributesToString = (attributes) => attributes.map(([attName, value]) => ` ${toAttrString(attName, value)}`).join("");
|
|
383
|
+
var convertTagName = (tagName) => {
|
|
384
|
+
const tag = tagName.toLowerCase();
|
|
385
|
+
if (tag === "script") {
|
|
386
|
+
return "Script";
|
|
387
|
+
}
|
|
388
|
+
if (tag === "style") {
|
|
389
|
+
return "Style";
|
|
390
|
+
}
|
|
391
|
+
return tag;
|
|
392
|
+
};
|
|
393
|
+
var htmlToJsx = (html) => {
|
|
394
|
+
const parsedHtml = parseFragment(html, { scriptingEnabled: false });
|
|
395
|
+
let result = "";
|
|
396
|
+
for (const walkNode of walkChildNodes(parsedHtml)) {
|
|
397
|
+
switch (walkNode.type) {
|
|
398
|
+
case "text": {
|
|
399
|
+
const escapedValue = escape(walkNode.value);
|
|
400
|
+
result += escapedValue ? "{" + escapedValue + "}" : "";
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
case "element-start": {
|
|
404
|
+
const tag = convertTagName(walkNode.tagName);
|
|
405
|
+
result += `<${tag}${attributesToString(walkNode.attributes)}>`;
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
408
|
+
case "element-end": {
|
|
409
|
+
result += `</${convertTagName(walkNode.tagName)}>`;
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return result;
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// src/prebuild.ts
|
|
284
418
|
var limit = pLimit(10);
|
|
285
419
|
var downloadAsset = async (url, name, assetBaseUrl) => {
|
|
286
420
|
const assetPath = join4("public", assetBaseUrl, name);
|
|
@@ -357,12 +491,12 @@ var copyTemplates = async (template = "defaults") => {
|
|
|
357
491
|
}
|
|
358
492
|
};
|
|
359
493
|
var prebuild = async (options) => {
|
|
360
|
-
if (options.template ===
|
|
361
|
-
|
|
362
|
-
`
|
|
363
|
-
|
|
364
|
-
Please check webstudio --help for more details`
|
|
494
|
+
if (options.template.length === 0) {
|
|
495
|
+
log2.error(
|
|
496
|
+
`Template is not provided
|
|
497
|
+
Please check webstudio --help for more details`
|
|
365
498
|
);
|
|
499
|
+
exit2(1);
|
|
366
500
|
}
|
|
367
501
|
for (const template of options.template) {
|
|
368
502
|
if (template === "vanilla") {
|
|
@@ -372,22 +506,21 @@ var prebuild = async (options) => {
|
|
|
372
506
|
continue;
|
|
373
507
|
}
|
|
374
508
|
if (await isCliTemplate(template) === false) {
|
|
375
|
-
|
|
376
|
-
`
|
|
377
|
-
|
|
378
|
-
Please check webstudio --help for more details`
|
|
509
|
+
log2.error(
|
|
510
|
+
`Template ${options.template} is not available
|
|
511
|
+
Please check webstudio --help for more details`
|
|
379
512
|
);
|
|
513
|
+
exit2(1);
|
|
380
514
|
}
|
|
381
515
|
}
|
|
382
|
-
|
|
383
|
-
spinner.start();
|
|
384
|
-
spinner.text = "Generating files";
|
|
516
|
+
log2.step("Scaffolding the project files");
|
|
385
517
|
const appRoot = "app";
|
|
386
518
|
const generatedDir = join4(appRoot, "__generated__");
|
|
387
519
|
await rm(generatedDir, { recursive: true, force: true });
|
|
388
520
|
const routesDir = join4(appRoot, "routes");
|
|
389
521
|
await rm(routesDir, { recursive: true, force: true });
|
|
390
522
|
await copyTemplates();
|
|
523
|
+
await writeFile4(join4(cwd3(), ".npmrc"), "force=true");
|
|
391
524
|
for (const template of options.template) {
|
|
392
525
|
if (template === "vanilla") {
|
|
393
526
|
continue;
|
|
@@ -544,7 +677,6 @@ var prebuild = async (options) => {
|
|
|
544
677
|
}
|
|
545
678
|
}
|
|
546
679
|
const assets = new Map(siteData.assets.map((asset) => [asset.id, asset]));
|
|
547
|
-
spinner.text = "Generating css file";
|
|
548
680
|
const { cssText, classesMap } = generateCss({
|
|
549
681
|
instances: new Map(siteData.build.instances),
|
|
550
682
|
props: new Map(siteData.build.props),
|
|
@@ -558,7 +690,6 @@ var prebuild = async (options) => {
|
|
|
558
690
|
atomic: siteData.build.pages.compiler?.atomicStyles ?? true
|
|
559
691
|
});
|
|
560
692
|
await createFileIfNotExists(join4(generatedDir, "index.css"), cssText);
|
|
561
|
-
spinner.text = "Generating routes and pages";
|
|
562
693
|
const routeTemplatesDir = join4(cwd3(), "app/route-templates");
|
|
563
694
|
const routeTemplatePath = normalize(join4(routeTemplatesDir, "html.tsx"));
|
|
564
695
|
const routeXmlTemplatePath = normalize(join4(routeTemplatesDir, "xml.tsx"));
|
|
@@ -669,6 +800,9 @@ var prebuild = async (options) => {
|
|
|
669
800
|
const pageMeta = pageData.page.meta;
|
|
670
801
|
const favIconAsset = assets.get(projectMeta?.faviconAssetId ?? "");
|
|
671
802
|
const socialImageAsset = assets.get(pageMeta.socialImageAssetId ?? "");
|
|
803
|
+
const pagePath = getPagePath(pageData.page.id, siteData.build.pages);
|
|
804
|
+
const remixRoute = generateRemixRoute(pagePath);
|
|
805
|
+
const fileName = `${remixRoute}.tsx`;
|
|
672
806
|
const pageExports = `/* eslint-disable */
|
|
673
807
|
/* This is a auto generated file for building the project */
|
|
674
808
|
|
|
@@ -693,6 +827,29 @@ var prebuild = async (options) => {
|
|
|
693
827
|
export const pageBackgroundImageAssets: ImageAsset[] =
|
|
694
828
|
${JSON.stringify(pageBackgroundImageAssets)}
|
|
695
829
|
|
|
830
|
+
${remixRoute === "_index" ? `
|
|
831
|
+
${projectMeta?.code ? `
|
|
832
|
+
const Script = ({children, ...props}: Record<string, string | boolean>) => {
|
|
833
|
+
if (children == null) {
|
|
834
|
+
return <script {...props} />;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
return <script {...props} dangerouslySetInnerHTML={{__html: children}} />;
|
|
838
|
+
};
|
|
839
|
+
const Style = ({children, ...props}: Record<string, string | boolean>) => {
|
|
840
|
+
if (children == null) {
|
|
841
|
+
return <style {...props} />;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
return <style {...props} dangerouslySetInnerHTML={{__html: children}} />;
|
|
845
|
+
};
|
|
846
|
+
` : ""}
|
|
847
|
+
|
|
848
|
+
export const CustomCode = () => {
|
|
849
|
+
return (<>${projectMeta?.code ? htmlToJsx(projectMeta.code) : ""}</>);
|
|
850
|
+
}
|
|
851
|
+
` : ""}
|
|
852
|
+
|
|
696
853
|
${xmlPresentationComponents}
|
|
697
854
|
|
|
698
855
|
${pageComponent}
|
|
@@ -724,14 +881,7 @@ var prebuild = async (options) => {
|
|
|
724
881
|
export const projectId = "${siteData.build.projectId}";
|
|
725
882
|
|
|
726
883
|
export const contactEmail = ${JSON.stringify(contactEmail)};
|
|
727
|
-
|
|
728
|
-
export const customCode = ${JSON.stringify(
|
|
729
|
-
projectMeta?.code?.trim() ?? ""
|
|
730
|
-
)};
|
|
731
884
|
`;
|
|
732
|
-
const pagePath = getPagePath(pageData.page.id, siteData.build.pages);
|
|
733
|
-
const remixRoute = generateRemixRoute(pagePath);
|
|
734
|
-
const fileName = `${remixRoute}.tsx`;
|
|
735
885
|
const routeFileContent = (documentType === "html" ? routeFileTemplate : routeXmlFileTemplate).replace(
|
|
736
886
|
/".*\/__generated__\/_index"/,
|
|
737
887
|
`"../__generated__/${remixRoute}"`
|
|
@@ -762,7 +912,6 @@ var prebuild = async (options) => {
|
|
|
762
912
|
);
|
|
763
913
|
const redirects = siteData.build.pages?.redirects;
|
|
764
914
|
if (redirects !== void 0 && redirects.length > 0) {
|
|
765
|
-
spinner.text = "Generating redirects";
|
|
766
915
|
for (const redirect of redirects) {
|
|
767
916
|
const redirectPagePath = generateRemixRoute(redirect.old);
|
|
768
917
|
const redirectFileName = `${redirectPagePath}.ts`;
|
|
@@ -775,9 +924,13 @@ var prebuild = async (options) => {
|
|
|
775
924
|
await createFileIfNotExists(join4(routesDir, redirectFileName), content);
|
|
776
925
|
}
|
|
777
926
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
927
|
+
if (assetsToDownload.length > 0) {
|
|
928
|
+
const downloading = spinner2();
|
|
929
|
+
downloading.start("Downloading fonts and images");
|
|
930
|
+
await Promise.all(assetsToDownload);
|
|
931
|
+
downloading.stop("Downloaded fonts and images");
|
|
932
|
+
}
|
|
933
|
+
log2.step("Build finished");
|
|
781
934
|
};
|
|
782
935
|
|
|
783
936
|
// src/commands/build.ts
|
|
@@ -792,6 +945,7 @@ var buildOptions = (yargs) => yargs.option("assets", {
|
|
|
792
945
|
}).option("template", {
|
|
793
946
|
type: "array",
|
|
794
947
|
string: true,
|
|
948
|
+
default: [],
|
|
795
949
|
describe: `Template to use for the build [choices: ${PROJECT_TEMPALTES.join(
|
|
796
950
|
", "
|
|
797
951
|
)}]`
|
|
@@ -801,9 +955,10 @@ var build = async (options) => {
|
|
|
801
955
|
await access3(LOCAL_DATA_FILE);
|
|
802
956
|
} catch (error) {
|
|
803
957
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
804
|
-
|
|
958
|
+
log3.error(
|
|
805
959
|
`You need to link a webstudio project before building it. Run \`webstudio link\` to link a project.`
|
|
806
960
|
);
|
|
961
|
+
exit3(1);
|
|
807
962
|
}
|
|
808
963
|
throw error;
|
|
809
964
|
}
|
|
@@ -813,110 +968,99 @@ var build = async (options) => {
|
|
|
813
968
|
// src/commands/init-flow.ts
|
|
814
969
|
import { chdir, cwd as cwd4 } from "node:process";
|
|
815
970
|
import { join as join5 } from "node:path";
|
|
816
|
-
import ora3 from "ora";
|
|
817
|
-
|
|
818
|
-
// src/prompts.ts
|
|
819
|
-
import prompts from "prompts";
|
|
820
|
-
var prompt = (prompt2) => {
|
|
821
|
-
return prompts([
|
|
822
|
-
{
|
|
823
|
-
...prompt2,
|
|
824
|
-
onState: (state) => {
|
|
825
|
-
if (state.aborted) {
|
|
826
|
-
process.nextTick(() => {
|
|
827
|
-
process.exit(0);
|
|
828
|
-
});
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
]);
|
|
833
|
-
};
|
|
834
|
-
|
|
835
|
-
// src/commands/init-flow.ts
|
|
836
971
|
import pc2 from "picocolors";
|
|
972
|
+
import {
|
|
973
|
+
cancel as cancel2,
|
|
974
|
+
confirm,
|
|
975
|
+
isCancel as isCancel2,
|
|
976
|
+
log as log4,
|
|
977
|
+
select,
|
|
978
|
+
spinner as spinner3,
|
|
979
|
+
text as text2
|
|
980
|
+
} from "@clack/prompts";
|
|
837
981
|
import { $ } from "execa";
|
|
838
982
|
import { titleCase } from "title-case";
|
|
983
|
+
var exitIfCancelled = (value) => {
|
|
984
|
+
if (isCancel2(value)) {
|
|
985
|
+
cancel2("Project initialization is cancelled");
|
|
986
|
+
process.exit(0);
|
|
987
|
+
}
|
|
988
|
+
return value;
|
|
989
|
+
};
|
|
839
990
|
var initFlow = async (options) => {
|
|
840
991
|
const isProjectConfigured = await isFileExists(".webstudio/config.json");
|
|
841
992
|
let shouldInstallDeps = false;
|
|
842
993
|
let folderName;
|
|
843
994
|
let projectTemplate = void 0;
|
|
844
995
|
if (isProjectConfigured === false) {
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
996
|
+
const shouldCreateFolder = exitIfCancelled(
|
|
997
|
+
await confirm({
|
|
998
|
+
message: "Would you like to create a project folder? (no to use current folder)",
|
|
999
|
+
initialValue: true
|
|
1000
|
+
})
|
|
1001
|
+
);
|
|
851
1002
|
if (shouldCreateFolder === true) {
|
|
852
|
-
folderName = (
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1003
|
+
folderName = exitIfCancelled(
|
|
1004
|
+
await text2({
|
|
1005
|
+
message: "Please enter a project name",
|
|
1006
|
+
validate(value) {
|
|
1007
|
+
if (value.length === 0) {
|
|
1008
|
+
return "Folder name is required";
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
})
|
|
1012
|
+
);
|
|
860
1013
|
await createFolderIfNotExists(join5(cwd4(), folderName));
|
|
861
1014
|
chdir(join5(cwd4(), folderName));
|
|
862
1015
|
}
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
});
|
|
868
|
-
if (projectLink === void 0) {
|
|
869
|
-
throw new Error(`Project Link is required`);
|
|
870
|
-
}
|
|
871
|
-
await link({ link: projectLink });
|
|
872
|
-
const { deployTarget } = await prompt({
|
|
873
|
-
type: "select",
|
|
874
|
-
name: "deployTarget",
|
|
875
|
-
message: "Where would you like to deploy your project?",
|
|
876
|
-
choices: PROJECT_TEMPALTES.map((template) => {
|
|
877
|
-
return {
|
|
878
|
-
title: titleCase(template),
|
|
879
|
-
value: template
|
|
880
|
-
};
|
|
1016
|
+
const shareLink = exitIfCancelled(
|
|
1017
|
+
await text2({
|
|
1018
|
+
message: "Please paste a link from the Share Dialog in the builder",
|
|
1019
|
+
validate: validateShareLink
|
|
881
1020
|
})
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1021
|
+
);
|
|
1022
|
+
await link({ link: shareLink });
|
|
1023
|
+
projectTemplate = exitIfCancelled(
|
|
1024
|
+
await select({
|
|
1025
|
+
message: "Where would you like to deploy your project?",
|
|
1026
|
+
options: PROJECT_TEMPALTES.map((template) => ({
|
|
1027
|
+
value: template,
|
|
1028
|
+
label: titleCase(template)
|
|
1029
|
+
}))
|
|
1030
|
+
})
|
|
1031
|
+
);
|
|
1032
|
+
shouldInstallDeps = exitIfCancelled(
|
|
1033
|
+
await confirm({
|
|
1034
|
+
message: "Would you like to install dependencies? (recommended)",
|
|
1035
|
+
initialValue: true
|
|
1036
|
+
})
|
|
1037
|
+
);
|
|
891
1038
|
}
|
|
892
|
-
await sync({ buildId: void 0, origin: void 0, authToken: void 0 });
|
|
893
1039
|
if (projectTemplate === void 0) {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
value: template
|
|
902
|
-
};
|
|
1040
|
+
projectTemplate = exitIfCancelled(
|
|
1041
|
+
await select({
|
|
1042
|
+
message: "Where would you like to deploy your project?",
|
|
1043
|
+
options: PROJECT_TEMPALTES.map((template) => ({
|
|
1044
|
+
value: template,
|
|
1045
|
+
label: titleCase(template)
|
|
1046
|
+
}))
|
|
903
1047
|
})
|
|
904
|
-
|
|
905
|
-
projectTemplate = deployTarget;
|
|
1048
|
+
);
|
|
906
1049
|
}
|
|
1050
|
+
await sync({ buildId: void 0, origin: void 0, authToken: void 0 });
|
|
907
1051
|
await build({
|
|
908
1052
|
...options,
|
|
909
1053
|
...projectTemplate && { template: [projectTemplate] }
|
|
910
1054
|
});
|
|
911
1055
|
if (shouldInstallDeps === true) {
|
|
912
|
-
const
|
|
913
|
-
|
|
1056
|
+
const install = spinner3();
|
|
1057
|
+
install.start("Installing dependencies");
|
|
914
1058
|
await $`npm install`;
|
|
915
|
-
|
|
1059
|
+
install.stop("Installed dependencies");
|
|
916
1060
|
}
|
|
917
|
-
|
|
918
|
-
Your project was successfully synced \u{1F389}`)));
|
|
919
|
-
|
|
1061
|
+
log4.message();
|
|
1062
|
+
log4.message(pc2.green(pc2.bold(`Your project was successfully synced \u{1F389}`)));
|
|
1063
|
+
log4.message(
|
|
920
1064
|
[
|
|
921
1065
|
"Now you can:",
|
|
922
1066
|
folderName && `Go to your project: ${pc2.dim(`cd ${folderName}`)}`,
|
|
@@ -949,7 +1093,7 @@ import makeCLI from "yargs";
|
|
|
949
1093
|
// package.json
|
|
950
1094
|
var package_default = {
|
|
951
1095
|
name: "webstudio",
|
|
952
|
-
version: "0.
|
|
1096
|
+
version: "0.168.0",
|
|
953
1097
|
description: "Webstudio CLI",
|
|
954
1098
|
author: "Webstudio <github@webstudio.is>",
|
|
955
1099
|
homepage: "https://webstudio.is",
|
|
@@ -958,6 +1102,12 @@ var package_default = {
|
|
|
958
1102
|
"webstudio-cli": "./bin.js",
|
|
959
1103
|
webstudio: "./bin.js"
|
|
960
1104
|
},
|
|
1105
|
+
imports: {
|
|
1106
|
+
"#cli": {
|
|
1107
|
+
webstudio: "./src/cli.ts",
|
|
1108
|
+
default: "./lib/cli.js"
|
|
1109
|
+
}
|
|
1110
|
+
},
|
|
961
1111
|
files: [
|
|
962
1112
|
"lib/*",
|
|
963
1113
|
"templates/*",
|
|
@@ -968,11 +1118,15 @@ var package_default = {
|
|
|
968
1118
|
typecheck: "tsc",
|
|
969
1119
|
checks: "pnpm typecheck",
|
|
970
1120
|
build: "rm -rf lib && esbuild src/cli.ts --outdir=lib --bundle --format=esm --packages=external",
|
|
971
|
-
|
|
972
|
-
|
|
1121
|
+
dev: "esbuild src/cli.ts --watch --bundle --format=esm --packages=external --outdir=./lib",
|
|
1122
|
+
test: "NODE_OPTIONS=--experimental-vm-modules jest"
|
|
973
1123
|
},
|
|
974
1124
|
license: "AGPL-3.0-or-later",
|
|
1125
|
+
engines: {
|
|
1126
|
+
node: ">=20.12"
|
|
1127
|
+
},
|
|
975
1128
|
dependencies: {
|
|
1129
|
+
"@clack/prompts": "^0.7.0",
|
|
976
1130
|
"@webstudio-is/http-client": "workspace:*",
|
|
977
1131
|
"@webstudio-is/image": "workspace:*",
|
|
978
1132
|
"@webstudio-is/react-sdk": "workspace:*",
|
|
@@ -980,39 +1134,39 @@ var package_default = {
|
|
|
980
1134
|
"@webstudio-is/sdk-components-react": "workspace:*",
|
|
981
1135
|
"@webstudio-is/sdk-components-react-radix": "workspace:*",
|
|
982
1136
|
"@webstudio-is/sdk-components-react-remix": "workspace:*",
|
|
1137
|
+
"change-case": "^5.4.4",
|
|
983
1138
|
deepmerge: "^4.3.1",
|
|
984
1139
|
"env-paths": "^3.0.0",
|
|
985
1140
|
execa: "^7.2.0",
|
|
986
|
-
ora: "^7.0.1",
|
|
987
1141
|
"p-limit": "^4.0.0",
|
|
988
|
-
|
|
989
|
-
|
|
1142
|
+
parse5: "7.1.2",
|
|
1143
|
+
picocolors: "^1.0.1",
|
|
990
1144
|
"strip-indent": "^4.0.0",
|
|
991
1145
|
"title-case": "^4.1.0",
|
|
992
1146
|
yargs: "^17.7.2",
|
|
993
1147
|
zod: "^3.22.4"
|
|
994
1148
|
},
|
|
995
1149
|
devDependencies: {
|
|
996
|
-
"@
|
|
997
|
-
"@netlify/remix-
|
|
998
|
-
"@remix-
|
|
999
|
-
"@remix-run/cloudflare
|
|
1000
|
-
"@remix-run/
|
|
1001
|
-
"@remix-run/
|
|
1002
|
-
"@remix-run/
|
|
1003
|
-
"@remix-run/
|
|
1150
|
+
"@jest/globals": "^29.7.0",
|
|
1151
|
+
"@netlify/remix-adapter": "^2.4.0",
|
|
1152
|
+
"@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",
|
|
1004
1159
|
"@types/node": "^20.12.7",
|
|
1005
|
-
"@types/prompts": "^2.4.5",
|
|
1006
1160
|
"@types/react": "^18.2.70",
|
|
1007
1161
|
"@types/react-dom": "^18.2.25",
|
|
1008
1162
|
"@types/yargs": "^17.0.32",
|
|
1009
1163
|
"@webstudio-is/form-handlers": "workspace:*",
|
|
1164
|
+
"@webstudio-is/jest-config": "workspace:*",
|
|
1010
1165
|
"@webstudio-is/tsconfig": "workspace:*",
|
|
1011
1166
|
react: "18.3.0-canary-14898b6a9-20240318",
|
|
1012
1167
|
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|
|
1013
|
-
tsx: "^4.7.2",
|
|
1014
1168
|
typescript: "5.4.5",
|
|
1015
|
-
vite: "^5.2.
|
|
1169
|
+
vite: "^5.2.13",
|
|
1016
1170
|
wrangler: "^3.48.0"
|
|
1017
1171
|
}
|
|
1018
1172
|
};
|
|
@@ -1056,7 +1210,7 @@ var main = async () => {
|
|
|
1056
1210
|
await cmd.parse();
|
|
1057
1211
|
} catch (error) {
|
|
1058
1212
|
console.error(error);
|
|
1059
|
-
|
|
1213
|
+
exit4(1);
|
|
1060
1214
|
}
|
|
1061
1215
|
};
|
|
1062
1216
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webstudio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.168.0",
|
|
4
4
|
"description": "Webstudio CLI",
|
|
5
5
|
"author": "Webstudio <github@webstudio.is>",
|
|
6
6
|
"homepage": "https://webstudio.is",
|
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
"webstudio-cli": "./bin.js",
|
|
10
10
|
"webstudio": "./bin.js"
|
|
11
11
|
},
|
|
12
|
+
"imports": {
|
|
13
|
+
"#cli": {
|
|
14
|
+
"webstudio": "./src/cli.ts",
|
|
15
|
+
"default": "./lib/cli.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
12
18
|
"files": [
|
|
13
19
|
"lib/*",
|
|
14
20
|
"templates/*",
|
|
@@ -16,54 +22,58 @@
|
|
|
16
22
|
"!*.{test,stories}.*"
|
|
17
23
|
],
|
|
18
24
|
"license": "AGPL-3.0-or-later",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20.12"
|
|
27
|
+
},
|
|
19
28
|
"dependencies": {
|
|
29
|
+
"@clack/prompts": "^0.7.0",
|
|
30
|
+
"change-case": "^5.4.4",
|
|
20
31
|
"deepmerge": "^4.3.1",
|
|
21
32
|
"env-paths": "^3.0.0",
|
|
22
33
|
"execa": "^7.2.0",
|
|
23
|
-
"ora": "^7.0.1",
|
|
24
34
|
"p-limit": "^4.0.0",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
35
|
+
"parse5": "7.1.2",
|
|
36
|
+
"picocolors": "^1.0.1",
|
|
27
37
|
"strip-indent": "^4.0.0",
|
|
28
38
|
"title-case": "^4.1.0",
|
|
29
39
|
"yargs": "^17.7.2",
|
|
30
40
|
"zod": "^3.22.4",
|
|
31
|
-
"@webstudio-is/
|
|
32
|
-
"@webstudio-is/react-sdk": "0.
|
|
33
|
-
"@webstudio-is/
|
|
34
|
-
"@webstudio-is/
|
|
35
|
-
"@webstudio-is/sdk-components-react
|
|
36
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
37
|
-
"@webstudio-is/sdk-components-react-remix": "0.
|
|
41
|
+
"@webstudio-is/image": "0.168.0",
|
|
42
|
+
"@webstudio-is/react-sdk": "0.168.0",
|
|
43
|
+
"@webstudio-is/sdk": "0.168.0",
|
|
44
|
+
"@webstudio-is/http-client": "0.168.0",
|
|
45
|
+
"@webstudio-is/sdk-components-react": "0.168.0",
|
|
46
|
+
"@webstudio-is/sdk-components-react-radix": "0.168.0",
|
|
47
|
+
"@webstudio-is/sdk-components-react-remix": "0.168.0"
|
|
38
48
|
},
|
|
39
49
|
"devDependencies": {
|
|
40
|
-
"@
|
|
41
|
-
"@netlify/remix-
|
|
42
|
-
"@remix-
|
|
43
|
-
"@remix-run/cloudflare
|
|
44
|
-
"@remix-run/
|
|
45
|
-
"@remix-run/
|
|
46
|
-
"@remix-run/
|
|
47
|
-
"@remix-run/
|
|
50
|
+
"@jest/globals": "^29.7.0",
|
|
51
|
+
"@netlify/remix-adapter": "^2.4.0",
|
|
52
|
+
"@netlify/remix-edge-adapter": "3.3.0",
|
|
53
|
+
"@remix-run/cloudflare": "^2.9.2",
|
|
54
|
+
"@remix-run/cloudflare-pages": "^2.9.2",
|
|
55
|
+
"@remix-run/dev": "^2.9.2",
|
|
56
|
+
"@remix-run/node": "^2.9.2",
|
|
57
|
+
"@remix-run/react": "^2.9.2",
|
|
58
|
+
"@remix-run/server-runtime": "^2.9.2",
|
|
48
59
|
"@types/node": "^20.12.7",
|
|
49
|
-
"@types/prompts": "^2.4.5",
|
|
50
60
|
"@types/react": "^18.2.70",
|
|
51
61
|
"@types/react-dom": "^18.2.25",
|
|
52
62
|
"@types/yargs": "^17.0.32",
|
|
53
63
|
"react": "18.3.0-canary-14898b6a9-20240318",
|
|
54
64
|
"react-dom": "18.3.0-canary-14898b6a9-20240318",
|
|
55
|
-
"tsx": "^4.7.2",
|
|
56
65
|
"typescript": "5.4.5",
|
|
57
|
-
"vite": "^5.2.
|
|
66
|
+
"vite": "^5.2.13",
|
|
58
67
|
"wrangler": "^3.48.0",
|
|
59
|
-
"@webstudio-is/
|
|
68
|
+
"@webstudio-is/jest-config": "1.0.7",
|
|
69
|
+
"@webstudio-is/form-handlers": "0.168.0",
|
|
60
70
|
"@webstudio-is/tsconfig": "1.0.7"
|
|
61
71
|
},
|
|
62
72
|
"scripts": {
|
|
63
73
|
"typecheck": "tsc",
|
|
64
74
|
"checks": "pnpm typecheck",
|
|
65
75
|
"build": "rm -rf lib && esbuild src/cli.ts --outdir=lib --bundle --format=esm --packages=external",
|
|
66
|
-
"
|
|
67
|
-
"
|
|
76
|
+
"dev": "esbuild src/cli.ts --watch --bundle --format=esm --packages=external --outdir=./lib",
|
|
77
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
|
|
68
78
|
}
|
|
69
79
|
}
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
"build-cf-types": "wrangler types"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@remix-run/cloudflare": "2.9.
|
|
16
|
-
"@remix-run/cloudflare-pages": "2.9.
|
|
17
|
-
"isbot": "^
|
|
15
|
+
"@remix-run/cloudflare": "2.9.2",
|
|
16
|
+
"@remix-run/cloudflare-pages": "2.9.2",
|
|
17
|
+
"isbot": "^5.1.8"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@cloudflare/workers-types": "^4.20240405.0",
|
|
@@ -1,13 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
|
|
3
|
+
import { Links, Meta, Outlet, useMatches } from "@remix-run/react";
|
|
4
|
+
// @todo think about how to make __generated__ typeable
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
import { CustomCode } from "./__generated__/_index";
|
|
2
7
|
|
|
3
8
|
const Root = () => {
|
|
9
|
+
// Get language from matches
|
|
10
|
+
const matches = useMatches();
|
|
11
|
+
|
|
12
|
+
const lastMatchWithLanguage = matches.findLast((match) => {
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
const language = match?.data?.pageMeta?.language;
|
|
15
|
+
return language != null;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
const lang = lastMatchWithLanguage?.data?.pageMeta?.language ?? "en";
|
|
20
|
+
|
|
4
21
|
return (
|
|
5
|
-
<html lang=
|
|
22
|
+
<html lang={lang}>
|
|
6
23
|
<head>
|
|
7
24
|
<meta charSet="utf-8" />
|
|
8
25
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
9
26
|
<Meta />
|
|
10
27
|
<Links />
|
|
28
|
+
<CustomCode />
|
|
11
29
|
</head>
|
|
12
30
|
<Outlet />
|
|
13
31
|
</html>
|
|
@@ -81,7 +81,6 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
81
81
|
status: pageMeta.status,
|
|
82
82
|
headers: {
|
|
83
83
|
"Cache-Control": "public, max-age=600",
|
|
84
|
-
"x-ws-language": pageMeta.language ?? "en",
|
|
85
84
|
},
|
|
86
85
|
}
|
|
87
86
|
);
|
|
@@ -90,7 +89,6 @@ export const loader = async (arg: LoaderFunctionArgs) => {
|
|
|
90
89
|
export const headers: HeadersFunction = ({ loaderHeaders }) => {
|
|
91
90
|
return {
|
|
92
91
|
"Cache-Control": "public, max-age=0, must-revalidate",
|
|
93
|
-
"x-ws-language": loaderHeaders.get("x-ws-language") ?? "",
|
|
94
92
|
};
|
|
95
93
|
};
|
|
96
94
|
|
|
@@ -188,24 +186,15 @@ export const links: LinksFunction = () => {
|
|
|
188
186
|
rel: "icon",
|
|
189
187
|
href: imageLoader({
|
|
190
188
|
src: favIconAsset.name,
|
|
191
|
-
width
|
|
189
|
+
// width,height must be multiple of 48 https://developers.google.com/search/docs/appearance/favicon-in-search
|
|
190
|
+
width: 144,
|
|
191
|
+
height: 144,
|
|
192
|
+
fit: "pad",
|
|
192
193
|
quality: 100,
|
|
193
194
|
format: "auto",
|
|
194
195
|
}),
|
|
195
196
|
type: undefined,
|
|
196
197
|
});
|
|
197
|
-
} else {
|
|
198
|
-
result.push({
|
|
199
|
-
rel: "icon",
|
|
200
|
-
href: "/favicon.ico",
|
|
201
|
-
type: "image/x-icon",
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
result.push({
|
|
205
|
-
rel: "shortcut icon",
|
|
206
|
-
href: "/favicon.ico",
|
|
207
|
-
type: "image/x-icon",
|
|
208
|
-
});
|
|
209
198
|
}
|
|
210
199
|
|
|
211
200
|
for (const asset of pageFontAssets) {
|
|
@@ -8,26 +8,26 @@
|
|
|
8
8
|
"typecheck": "tsc"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@remix-run/node": "2.9.
|
|
12
|
-
"@remix-run/react": "2.9.
|
|
13
|
-
"@remix-run/server-runtime": "2.9.
|
|
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.
|
|
21
|
-
"isbot": "^
|
|
11
|
+
"@remix-run/node": "2.9.2",
|
|
12
|
+
"@remix-run/react": "2.9.2",
|
|
13
|
+
"@remix-run/server-runtime": "2.9.2",
|
|
14
|
+
"@webstudio-is/react-sdk": "0.168.0",
|
|
15
|
+
"@webstudio-is/sdk-components-react-radix": "0.168.0",
|
|
16
|
+
"@webstudio-is/sdk-components-react-remix": "0.168.0",
|
|
17
|
+
"@webstudio-is/sdk-components-react": "0.168.0",
|
|
18
|
+
"@webstudio-is/form-handlers": "0.168.0",
|
|
19
|
+
"@webstudio-is/image": "0.168.0",
|
|
20
|
+
"@webstudio-is/sdk": "0.168.0",
|
|
21
|
+
"isbot": "^5.1.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": "2.9.
|
|
26
|
+
"@remix-run/dev": "2.9.2",
|
|
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.13"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
33
|
"node": ">=20.0.0"
|