webstudio 0.111.0 → 0.111.1-0d68965.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 +15 -9
- package/package.json +10 -10
- package/templates/defaults/app/extension.ts +9 -0
- package/templates/defaults/app/routes/[robots.txt].tsx +25 -0
- package/templates/defaults/remix.env.d.ts +1 -0
- package/templates/route-template.tsx +138 -16
- package/templates/vercel/app/constants.mjs +9 -5
package/lib/cli.js
CHANGED
|
@@ -357,6 +357,11 @@ var prebuild = async (options) => {
|
|
|
357
357
|
const spinner = ora2("Scaffolding the project files");
|
|
358
358
|
spinner.start();
|
|
359
359
|
spinner.text = "Generating files";
|
|
360
|
+
const appRoot = "app";
|
|
361
|
+
const generatedDir = join4(appRoot, "__generated__");
|
|
362
|
+
await rm(generatedDir, { recursive: true, force: true });
|
|
363
|
+
const routesDir = join4(appRoot, "routes");
|
|
364
|
+
await rm(routesDir, { recursive: true, force: true });
|
|
360
365
|
await copyTemplates();
|
|
361
366
|
if (options.template !== void 0) {
|
|
362
367
|
await copyTemplates(options.template);
|
|
@@ -456,6 +461,12 @@ var prebuild = async (options) => {
|
|
|
456
461
|
}
|
|
457
462
|
const assetsToDownload = [];
|
|
458
463
|
const fontAssets = [];
|
|
464
|
+
const imageAssets = [];
|
|
465
|
+
for (const asset of siteData.assets) {
|
|
466
|
+
if (asset.type === "image") {
|
|
467
|
+
imageAssets.push(asset);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
459
470
|
const appDomain = options.preview ? "wstd.work" : "wstd.io";
|
|
460
471
|
const assetBuildUrl = `https://${domain}.${appDomain}/cgi/asset/`;
|
|
461
472
|
const temporaryDir = await mkdtemp(join4(tmpdir(), "webstudio-"));
|
|
@@ -466,8 +477,6 @@ var prebuild = async (options) => {
|
|
|
466
477
|
for (const asset of siteData.assets) {
|
|
467
478
|
if (asset.type === "image") {
|
|
468
479
|
const imageSrc = imageLoader({
|
|
469
|
-
width: 16,
|
|
470
|
-
quality: 100,
|
|
471
480
|
src: asset.name,
|
|
472
481
|
format: "raw"
|
|
473
482
|
});
|
|
@@ -493,11 +502,6 @@ var prebuild = async (options) => {
|
|
|
493
502
|
}
|
|
494
503
|
}
|
|
495
504
|
spinner.text = "Generating routes and pages";
|
|
496
|
-
const appRoot = "app";
|
|
497
|
-
const generatedDir = join4(appRoot, "__generated__");
|
|
498
|
-
await rm(generatedDir, { recursive: true, force: true });
|
|
499
|
-
const routesDir = join4(appRoot, "routes");
|
|
500
|
-
await rm(routesDir, { recursive: true, force: true });
|
|
501
505
|
const routeFileTemplate = await readFile4(
|
|
502
506
|
normalize(
|
|
503
507
|
join4(
|
|
@@ -556,6 +560,7 @@ var prebuild = async (options) => {
|
|
|
556
560
|
}
|
|
557
561
|
const pageData = siteDataByPage[pathName];
|
|
558
562
|
const renderedPageData = {
|
|
563
|
+
site: siteData.build.pages.meta,
|
|
559
564
|
page: pageData.page
|
|
560
565
|
};
|
|
561
566
|
const rootInstanceId = pageData.page.rootInstanceId;
|
|
@@ -583,9 +588,10 @@ var prebuild = async (options) => {
|
|
|
583
588
|
|
|
584
589
|
import { type ReactNode, useState } from "react";
|
|
585
590
|
import type { PageData } from "~/routes/_index";
|
|
586
|
-
import type { Asset } from "@webstudio-is/sdk";
|
|
591
|
+
import type { Asset, ImageAsset, SiteMeta } from "@webstudio-is/sdk";
|
|
587
592
|
${componentImports}
|
|
588
593
|
export const fontAssets: Asset[] = ${JSON.stringify(fontAssets)}
|
|
594
|
+
export const imageAssets: ImageAsset[] = ${JSON.stringify(imageAssets)}
|
|
589
595
|
export const pageData: PageData = ${JSON.stringify(renderedPageData)};
|
|
590
596
|
export const user: { email: string | null } | undefined = ${JSON.stringify(
|
|
591
597
|
siteData.user
|
|
@@ -785,7 +791,7 @@ import makeCLI from "yargs";
|
|
|
785
791
|
// package.json
|
|
786
792
|
var package_default = {
|
|
787
793
|
name: "webstudio",
|
|
788
|
-
version: "0.111.0",
|
|
794
|
+
version: "0.111.1-0d68965.0",
|
|
789
795
|
description: "Webstudio CLI",
|
|
790
796
|
author: "Webstudio <github@webstudio.is>",
|
|
791
797
|
homepage: "https://webstudio.is",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webstudio",
|
|
3
|
-
"version": "0.111.0",
|
|
3
|
+
"version": "0.111.1-0d68965.0",
|
|
4
4
|
"description": "Webstudio CLI",
|
|
5
5
|
"author": "Webstudio <github@webstudio.is>",
|
|
6
6
|
"homepage": "https://webstudio.is",
|
|
@@ -28,21 +28,21 @@
|
|
|
28
28
|
"title-case": "^4.1.0",
|
|
29
29
|
"yargs": "^17.7.2",
|
|
30
30
|
"zod": "^3.21.4",
|
|
31
|
-
"@webstudio-is/http-client": "0.111.0",
|
|
32
|
-
"@webstudio-is/image": "0.111.0",
|
|
33
|
-
"@webstudio-is/react-sdk": "0.111.0",
|
|
34
|
-
"@webstudio-is/sdk": "0.111.0",
|
|
35
|
-
"@webstudio-is/sdk-components-react": "0.111.0",
|
|
36
|
-
"@webstudio-is/sdk-components-react-radix": "0.111.0",
|
|
37
|
-
"@webstudio-is/sdk-components-react-remix": "0.111.0"
|
|
31
|
+
"@webstudio-is/http-client": "0.111.1-0d68965.0",
|
|
32
|
+
"@webstudio-is/image": "0.111.1-0d68965.0",
|
|
33
|
+
"@webstudio-is/react-sdk": "0.111.1-0d68965.0",
|
|
34
|
+
"@webstudio-is/sdk": "0.111.1-0d68965.0",
|
|
35
|
+
"@webstudio-is/sdk-components-react": "0.111.1-0d68965.0",
|
|
36
|
+
"@webstudio-is/sdk-components-react-radix": "0.111.1-0d68965.0",
|
|
37
|
+
"@webstudio-is/sdk-components-react-remix": "0.111.1-0d68965.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^18.17.1",
|
|
41
41
|
"@types/prompts": "^2.4.5",
|
|
42
42
|
"tsx": "^3.12.8",
|
|
43
43
|
"typescript": "5.2.2",
|
|
44
|
-
"@webstudio-is/form-handlers": "0.111.0",
|
|
45
|
-
"@webstudio-is/tsconfig": "1.0.
|
|
44
|
+
"@webstudio-is/form-handlers": "0.111.1-0d68965.0",
|
|
45
|
+
"@webstudio-is/tsconfig": "1.0.8-0d68965.0"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"typecheck": "tsc",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { LoaderArgs } from "@remix-run/server-runtime";
|
|
2
|
+
|
|
3
|
+
export const loader = (arg: LoaderArgs) => {
|
|
4
|
+
const host =
|
|
5
|
+
arg.request.headers.get("x-forwarded-host") ||
|
|
6
|
+
arg.request.headers.get("host") ||
|
|
7
|
+
"";
|
|
8
|
+
|
|
9
|
+
return new Response(
|
|
10
|
+
`
|
|
11
|
+
User-agent: *
|
|
12
|
+
Disallow: /api/
|
|
13
|
+
|
|
14
|
+
# Uncomment
|
|
15
|
+
# Sitemap: https://${host}/sitemap.xml
|
|
16
|
+
|
|
17
|
+
`,
|
|
18
|
+
{
|
|
19
|
+
headers: {
|
|
20
|
+
"Content-Type": "text/plain",
|
|
21
|
+
},
|
|
22
|
+
status: 200,
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
type LinksFunction,
|
|
5
5
|
type LinkDescriptor,
|
|
6
6
|
type ActionArgs,
|
|
7
|
+
type LoaderArgs,
|
|
7
8
|
json,
|
|
8
9
|
} from "@remix-run/server-runtime";
|
|
9
|
-
import type { Page as PageType } from "@webstudio-is/sdk";
|
|
10
|
+
import type { Page as PageType, SiteMeta } from "@webstudio-is/sdk";
|
|
10
11
|
import { ReactSdkContext } from "@webstudio-is/react-sdk";
|
|
11
12
|
import { n8nHandler, getFormId } from "@webstudio-is/form-handlers";
|
|
12
13
|
import { Scripts, ScrollRestoration } from "@remix-run/react";
|
|
@@ -18,34 +19,122 @@ import {
|
|
|
18
19
|
pagesPaths,
|
|
19
20
|
formsProperties,
|
|
20
21
|
Page,
|
|
22
|
+
imageAssets,
|
|
21
23
|
} from "../__generated__/index";
|
|
22
24
|
import css from "../__generated__/index.css";
|
|
23
25
|
import { assetBaseUrl, imageBaseUrl, imageLoader } from "~/constants.mjs";
|
|
24
26
|
|
|
25
27
|
export type PageData = {
|
|
28
|
+
site?: SiteMeta;
|
|
26
29
|
page: PageType;
|
|
27
30
|
};
|
|
28
31
|
|
|
29
|
-
export const
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
export const loader = async (arg: LoaderArgs) => {
|
|
33
|
+
const host =
|
|
34
|
+
arg.request.headers.get("x-forwarded-host") ||
|
|
35
|
+
arg.request.headers.get("host") ||
|
|
36
|
+
"";
|
|
37
|
+
|
|
38
|
+
const url = new URL(arg.request.url);
|
|
39
|
+
url.host = host;
|
|
40
|
+
url.protocol = "https";
|
|
41
|
+
|
|
42
|
+
// typecheck
|
|
43
|
+
arg.context.EXCLUDE_FROM_SEARCH satisfies boolean;
|
|
44
|
+
|
|
45
|
+
return json(
|
|
46
|
+
{
|
|
47
|
+
host,
|
|
48
|
+
url: url.href,
|
|
49
|
+
excludeFromSearch: arg.context.EXCLUDE_FROM_SEARCH,
|
|
50
|
+
},
|
|
51
|
+
// No way for current information to change, so add cache for 10 minutes
|
|
52
|
+
// In case of CRM Data, this should be set to 0
|
|
53
|
+
{ headers: { "Cache-Control": "public, max-age=600" } }
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const headers = () => {
|
|
58
|
+
return {
|
|
59
|
+
"Cache-Control": "public, max-age=0, must-revalidate",
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const meta: V2_ServerRuntimeMetaFunction<typeof loader> = ({ data }) => {
|
|
64
|
+
const { page, site } = pageData;
|
|
65
|
+
|
|
66
|
+
const metas: ReturnType<V2_ServerRuntimeMetaFunction> = [];
|
|
67
|
+
|
|
68
|
+
if (data?.url) {
|
|
69
|
+
metas.push({
|
|
70
|
+
property: "og:url",
|
|
71
|
+
content: data.url,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (page.title) {
|
|
76
|
+
metas.push({ title: page.title });
|
|
42
77
|
|
|
43
78
|
metas.push({
|
|
44
|
-
|
|
45
|
-
content:
|
|
79
|
+
property: "og:title",
|
|
80
|
+
content: page.title,
|
|
46
81
|
});
|
|
47
82
|
}
|
|
48
83
|
|
|
84
|
+
metas.push({ property: "og:type", content: "website" });
|
|
85
|
+
|
|
86
|
+
const origin = `https://${data?.host}`;
|
|
87
|
+
|
|
88
|
+
if (site?.siteName) {
|
|
89
|
+
metas.push({
|
|
90
|
+
property: "og:site_name",
|
|
91
|
+
content: site.siteName,
|
|
92
|
+
});
|
|
93
|
+
metas.push({
|
|
94
|
+
"script:ld+json": {
|
|
95
|
+
"@context": "https://schema.org",
|
|
96
|
+
"@type": "WebSite",
|
|
97
|
+
name: site.siteName,
|
|
98
|
+
url: origin,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (page.meta.excludePageFromSearch || data?.excludeFromSearch) {
|
|
104
|
+
metas.push({
|
|
105
|
+
name: "robots",
|
|
106
|
+
content: "noindex",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (page.meta.description) {
|
|
111
|
+
metas.push({
|
|
112
|
+
name: "description",
|
|
113
|
+
content: page.meta.description,
|
|
114
|
+
});
|
|
115
|
+
metas.push({
|
|
116
|
+
property: "og:description",
|
|
117
|
+
content: page.meta.description,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (page.meta.socialImageAssetId) {
|
|
122
|
+
const imageAsset = imageAssets.find(
|
|
123
|
+
(asset) => asset.id === page.meta.socialImageAssetId
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
if (imageAsset) {
|
|
127
|
+
metas.push({
|
|
128
|
+
property: "og:image",
|
|
129
|
+
content: `https://${data?.host}${imageLoader({
|
|
130
|
+
src: imageAsset.name,
|
|
131
|
+
// Do not transform social image (not enough information do we need to do this)
|
|
132
|
+
format: "raw",
|
|
133
|
+
})}`,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
49
138
|
return metas;
|
|
50
139
|
};
|
|
51
140
|
|
|
@@ -57,6 +146,39 @@ export const links: LinksFunction = () => {
|
|
|
57
146
|
href: css,
|
|
58
147
|
});
|
|
59
148
|
|
|
149
|
+
const { site } = pageData;
|
|
150
|
+
|
|
151
|
+
if (site?.faviconAssetId) {
|
|
152
|
+
const imageAsset = imageAssets.find(
|
|
153
|
+
(asset) => asset.id === site.faviconAssetId
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
if (imageAsset) {
|
|
157
|
+
result.push({
|
|
158
|
+
rel: "icon",
|
|
159
|
+
href: imageLoader({
|
|
160
|
+
src: imageAsset.name,
|
|
161
|
+
width: 128,
|
|
162
|
+
quality: 100,
|
|
163
|
+
format: "auto",
|
|
164
|
+
}),
|
|
165
|
+
type: undefined,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
result.push({
|
|
170
|
+
rel: "icon",
|
|
171
|
+
href: "/favicon.ico",
|
|
172
|
+
type: "image/x-icon",
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
result.push({
|
|
176
|
+
rel: "shortcut icon",
|
|
177
|
+
href: "/favicon.ico",
|
|
178
|
+
type: "image/x-icon",
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
60
182
|
for (const asset of fontAssets) {
|
|
61
183
|
if (asset.type === "font") {
|
|
62
184
|
result.push({
|
|
@@ -8,18 +8,22 @@ export const imageBaseUrl = "/assets/";
|
|
|
8
8
|
/**
|
|
9
9
|
* @type {import("@webstudio-is/image").ImageLoader}
|
|
10
10
|
*/
|
|
11
|
-
export const imageLoader = (
|
|
11
|
+
export const imageLoader = (props) => {
|
|
12
12
|
if (process.env.NODE_ENV !== "production") {
|
|
13
|
-
return imageBaseUrl + src;
|
|
13
|
+
return imageBaseUrl + props.src;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (props.format === "raw") {
|
|
17
|
+
return imageBaseUrl + props.src;
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
// https://vercel.com/blog/build-your-own-web-framework#automatic-image-optimization
|
|
17
21
|
return (
|
|
18
22
|
"/_vercel/image?url=" +
|
|
19
|
-
encodeURIComponent(imageBaseUrl + src) +
|
|
23
|
+
encodeURIComponent(imageBaseUrl + props.src) +
|
|
20
24
|
"&w=" +
|
|
21
|
-
width +
|
|
25
|
+
props.width +
|
|
22
26
|
"&q=" +
|
|
23
|
-
quality
|
|
27
|
+
props.quality
|
|
24
28
|
);
|
|
25
29
|
};
|