webstudio 0.111.1-3138155.0 → 0.113.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
@@ -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);
@@ -497,11 +502,6 @@ var prebuild = async (options) => {
497
502
  }
498
503
  }
499
504
  spinner.text = "Generating routes and pages";
500
- const appRoot = "app";
501
- const generatedDir = join4(appRoot, "__generated__");
502
- await rm(generatedDir, { recursive: true, force: true });
503
- const routesDir = join4(appRoot, "routes");
504
- await rm(routesDir, { recursive: true, force: true });
505
505
  const routeFileTemplate = await readFile4(
506
506
  normalize(
507
507
  join4(
@@ -627,6 +627,21 @@ ${utilsExport}
627
627
  }
628
628
  );
629
629
  await ensureFileInPath(join4(generatedDir, "index.css"), cssText);
630
+ await writeFile4(
631
+ join4(generatedDir, "[sitemap.xml].ts"),
632
+ `
633
+ export const sitemap = ${JSON.stringify(
634
+ {
635
+ pages: siteData.pages.map((page) => ({
636
+ path: page.path,
637
+ lastModified: siteData.build.updatedAt
638
+ }))
639
+ },
640
+ null,
641
+ 2
642
+ )};
643
+ `
644
+ );
630
645
  spinner.text = "Downloading fonts and images";
631
646
  await Promise.all(assetsToDownload);
632
647
  spinner.succeed("Build finished");
@@ -791,7 +806,7 @@ import makeCLI from "yargs";
791
806
  // package.json
792
807
  var package_default = {
793
808
  name: "webstudio",
794
- version: "0.111.1-3138155.0",
809
+ version: "0.113.0",
795
810
  description: "Webstudio CLI",
796
811
  author: "Webstudio <github@webstudio.is>",
797
812
  homepage: "https://webstudio.is",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webstudio",
3
- "version": "0.111.1-3138155.0",
3
+ "version": "0.113.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.1-3138155.0",
32
- "@webstudio-is/image": "0.111.1-3138155.0",
33
- "@webstudio-is/react-sdk": "0.111.1-3138155.0",
34
- "@webstudio-is/sdk": "0.111.1-3138155.0",
35
- "@webstudio-is/sdk-components-react": "0.111.1-3138155.0",
36
- "@webstudio-is/sdk-components-react-radix": "0.111.1-3138155.0",
37
- "@webstudio-is/sdk-components-react-remix": "0.111.1-3138155.0"
31
+ "@webstudio-is/http-client": "0.113.0",
32
+ "@webstudio-is/image": "0.113.0",
33
+ "@webstudio-is/react-sdk": "0.113.0",
34
+ "@webstudio-is/sdk": "0.113.0",
35
+ "@webstudio-is/sdk-components-react": "0.113.0",
36
+ "@webstudio-is/sdk-components-react-radix": "0.113.0",
37
+ "@webstudio-is/sdk-components-react-remix": "0.113.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.1-3138155.0",
45
- "@webstudio-is/tsconfig": "1.0.8-3138155.0"
44
+ "@webstudio-is/form-handlers": "0.113.0",
45
+ "@webstudio-is/tsconfig": "1.0.7"
46
46
  },
47
47
  "scripts": {
48
48
  "typecheck": "tsc",
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The only intent of this file is to support typings inside ../routes/[sitemap.xml].tsx for easier development.
3
+ **/
4
+ export const sitemap = {
5
+ pages: [
6
+ {
7
+ path: "",
8
+ lastModified: "2021-10-13T12:00:00.000Z",
9
+ },
10
+ ],
11
+ };
@@ -0,0 +1,9 @@
1
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
+ // @ts-ignore
3
+ import { AppLoadContext } from "@remix-run/server-runtime";
4
+
5
+ declare module "@remix-run/server-runtime" {
6
+ interface AppLoadContext {
7
+ EXCLUDE_FROM_SEARCH: boolean;
8
+ }
9
+ }
@@ -0,0 +1,24 @@
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
+ Sitemap: https://${host}/sitemap.xml
15
+
16
+ `,
17
+ {
18
+ headers: {
19
+ "Content-Type": "text/plain",
20
+ },
21
+ status: 200,
22
+ }
23
+ );
24
+ };
@@ -0,0 +1,34 @@
1
+ import type { LoaderArgs } from "@remix-run/server-runtime";
2
+ import { sitemap } from "../__generated__/[sitemap.xml]";
3
+
4
+ export const loader = (arg: LoaderArgs) => {
5
+ const host =
6
+ arg.request.headers.get("x-forwarded-host") ||
7
+ arg.request.headers.get("host") ||
8
+ "";
9
+
10
+ const urls = sitemap.pages.map((page) => {
11
+ const url = new URL(`https://${host}${page.path}`);
12
+
13
+ return `
14
+ <url>
15
+ <loc>${url.href}</loc>
16
+ <lastmod>${page.lastModified.split("T")[0]}</lastmod>
17
+ </url>
18
+ `;
19
+ });
20
+
21
+ return new Response(
22
+ `<?xml version="1.0" encoding="UTF-8"?>
23
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
24
+ ${urls.join("")}
25
+ </urlset>
26
+ `,
27
+ {
28
+ headers: {
29
+ "Content-Type": "application/xml",
30
+ },
31
+ status: 200,
32
+ }
33
+ );
34
+ };
@@ -34,19 +34,56 @@ export const loader = async (arg: LoaderArgs) => {
34
34
  arg.request.headers.get("x-forwarded-host") ||
35
35
  arg.request.headers.get("host") ||
36
36
  "";
37
- return json({ host });
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
+ };
38
61
  };
39
62
 
40
63
  export const meta: V2_ServerRuntimeMetaFunction<typeof loader> = ({ data }) => {
41
64
  const { page, site } = pageData;
42
65
 
43
- const metas: ReturnType<V2_ServerRuntimeMetaFunction> = [
44
- { title: page.title },
45
- {
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 });
77
+
78
+ metas.push({
46
79
  property: "og:title",
47
80
  content: page.title,
48
- },
49
- ];
81
+ });
82
+ }
83
+
84
+ metas.push({ property: "og:type", content: "website" });
85
+
86
+ const origin = `https://${data?.host}`;
50
87
 
51
88
  if (site?.siteName) {
52
89
  metas.push({
@@ -56,13 +93,20 @@ export const meta: V2_ServerRuntimeMetaFunction<typeof loader> = ({ data }) => {
56
93
  metas.push({
57
94
  "script:ld+json": {
58
95
  "@context": "https://schema.org",
59
- "@type": "Organization",
96
+ "@type": "WebSite",
60
97
  name: site.siteName,
61
- url: `https://${data?.host}`,
98
+ url: origin,
62
99
  },
63
100
  });
64
101
  }
65
102
 
103
+ if (page.meta.excludePageFromSearch || data?.excludeFromSearch) {
104
+ metas.push({
105
+ name: "robots",
106
+ content: "noindex, nofollow",
107
+ });
108
+ }
109
+
66
110
  if (page.meta.description) {
67
111
  metas.push({
68
112
  name: "description",
@@ -82,15 +126,22 @@ export const meta: V2_ServerRuntimeMetaFunction<typeof loader> = ({ data }) => {
82
126
  if (imageAsset) {
83
127
  metas.push({
84
128
  property: "og:image",
85
- content: imageLoader({
129
+ content: `https://${data?.host}${imageLoader({
86
130
  src: imageAsset.name,
87
131
  // Do not transform social image (not enough information do we need to do this)
88
132
  format: "raw",
89
- }),
133
+ })}`,
90
134
  });
91
135
  }
92
136
  }
93
137
 
138
+ for (const customMeta of page.meta.custom ?? []) {
139
+ if (customMeta.property.trim().length === 0) {
140
+ continue;
141
+ }
142
+ metas.push(customMeta);
143
+ }
144
+
94
145
  return metas;
95
146
  };
96
147