webstudio 0.123.0 → 0.124.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 +2 -2
- package/lib/cli.js +76 -54
- package/package.json +10 -10
- package/templates/netlify-functions/_app_redirects +5 -3
- package/templates/route-template.tsx +19 -10
package/README.md
CHANGED
|
@@ -108,7 +108,7 @@ If you want to build a production version of the app, you can run `npm run build
|
|
|
108
108
|
|
|
109
109
|
### Vercel
|
|
110
110
|
|
|
111
|
-
Once you've built the project locally, you can use the [Vercel CLI](https://vercel.com/docs/cli) to deploy your
|
|
111
|
+
Once you've built the project locally, you can use the [Vercel CLI](https://vercel.com/docs/cli) to deploy your project directly to [Vercel](https://vercel.com):
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
114
|
vercel deploy
|
|
@@ -118,7 +118,7 @@ Follow the instructions [here](https://vercel.com/docs/cli) to install the `verc
|
|
|
118
118
|
|
|
119
119
|
### Netlify
|
|
120
120
|
|
|
121
|
-
If you want to deploy to netlify, you can use [Netlify CLI](https://docs.netlify.com/cli/get-started/) to deploy your
|
|
121
|
+
If you want to deploy to netlify, you can use [Netlify CLI](https://docs.netlify.com/cli/get-started/) to deploy your project directly to [Netlify](https://netlify.com/):
|
|
122
122
|
|
|
123
123
|
```bash
|
|
124
124
|
netlify deploy
|
package/lib/cli.js
CHANGED
|
@@ -258,12 +258,16 @@ import pLimit from "p-limit";
|
|
|
258
258
|
import ora2 from "ora";
|
|
259
259
|
import merge from "deepmerge";
|
|
260
260
|
import {
|
|
261
|
-
|
|
261
|
+
generateCss,
|
|
262
262
|
generateUtilsExport,
|
|
263
263
|
generatePageComponent,
|
|
264
264
|
getIndexesWithinAncestors,
|
|
265
265
|
namespaceMeta,
|
|
266
|
-
normalizeProps
|
|
266
|
+
normalizeProps,
|
|
267
|
+
generateRemixRoute,
|
|
268
|
+
generateRemixParams,
|
|
269
|
+
generateResourcesLoader,
|
|
270
|
+
collectionComponent
|
|
267
271
|
} from "@webstudio-is/react-sdk";
|
|
268
272
|
import {
|
|
269
273
|
createScope,
|
|
@@ -382,11 +386,8 @@ var prebuild = async (options) => {
|
|
|
382
386
|
}
|
|
383
387
|
const domain = siteData.build.deployment?.projectDomain;
|
|
384
388
|
if (domain === void 0) {
|
|
385
|
-
throw new Error(`Project domain is missing from the
|
|
389
|
+
throw new Error(`Project domain is missing from the project data`);
|
|
386
390
|
}
|
|
387
|
-
const remixRoutes = {
|
|
388
|
-
routes: []
|
|
389
|
-
};
|
|
390
391
|
const radixComponentNamespacedMetas = Object.entries(
|
|
391
392
|
radixComponentMetas
|
|
392
393
|
).reduce(
|
|
@@ -412,14 +413,6 @@ var prebuild = async (options) => {
|
|
|
412
413
|
const componentsByPage = {};
|
|
413
414
|
const siteDataByPage = {};
|
|
414
415
|
for (const page of Object.values(siteData.pages)) {
|
|
415
|
-
const originPath = page.path;
|
|
416
|
-
const path = originPath === "" ? "index" : originPath.replace("/", "");
|
|
417
|
-
if (path !== "index") {
|
|
418
|
-
remixRoutes.routes.push({
|
|
419
|
-
path: originPath === "" ? "/" : originPath,
|
|
420
|
-
file: `routes/${path}.tsx`
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
416
|
const instanceMap = new Map(siteData.build.instances);
|
|
424
417
|
const pageInstanceSet = findTreeInstanceIds(
|
|
425
418
|
instanceMap,
|
|
@@ -439,29 +432,41 @@ var prebuild = async (options) => {
|
|
|
439
432
|
props.push([prop.id, prop]);
|
|
440
433
|
}
|
|
441
434
|
}
|
|
435
|
+
const resourceIds = /* @__PURE__ */ new Set();
|
|
442
436
|
for (const [dataSourceId, dataSource] of siteData.build.dataSources) {
|
|
443
437
|
if (dataSource.scopeInstanceId === void 0 || pageInstanceSet.has(dataSource.scopeInstanceId)) {
|
|
444
438
|
dataSources.push([dataSourceId, dataSource]);
|
|
439
|
+
if (dataSource.type === "resource") {
|
|
440
|
+
resourceIds.add(dataSource.resourceId);
|
|
441
|
+
}
|
|
445
442
|
}
|
|
446
443
|
}
|
|
447
|
-
|
|
444
|
+
const resources = [];
|
|
445
|
+
for (const [resourceId, resource] of siteData.build.resources ?? []) {
|
|
446
|
+
if (resourceIds.has(resourceId)) {
|
|
447
|
+
resources.push([resourceId, resource]);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
siteDataByPage[page.path] = {
|
|
448
451
|
build: {
|
|
449
452
|
props,
|
|
450
453
|
instances,
|
|
451
|
-
dataSources
|
|
454
|
+
dataSources,
|
|
455
|
+
resources
|
|
452
456
|
},
|
|
453
457
|
pages: siteData.pages,
|
|
454
458
|
page,
|
|
455
459
|
assets: siteData.assets
|
|
456
460
|
};
|
|
457
|
-
componentsByPage[path] = /* @__PURE__ */ new Set();
|
|
461
|
+
componentsByPage[page.path] = /* @__PURE__ */ new Set();
|
|
458
462
|
for (const [_instanceId, instance] of instances) {
|
|
459
|
-
if (instance.component) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
463
|
+
if (instance.component === collectionComponent) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
componentsByPage[page.path].add(instance.component);
|
|
467
|
+
const meta = metas.get(instance.component);
|
|
468
|
+
if (meta) {
|
|
469
|
+
projectMetas.set(instance.component, meta);
|
|
465
470
|
}
|
|
466
471
|
}
|
|
467
472
|
}
|
|
@@ -503,6 +508,22 @@ var prebuild = async (options) => {
|
|
|
503
508
|
}
|
|
504
509
|
}
|
|
505
510
|
}
|
|
511
|
+
spinner.text = "Generating css file";
|
|
512
|
+
const { cssText, classesMap } = generateCss(
|
|
513
|
+
{
|
|
514
|
+
assets: siteData.assets,
|
|
515
|
+
breakpoints: siteData.build?.breakpoints,
|
|
516
|
+
styles: siteData.build?.styles,
|
|
517
|
+
styleSourceSelections: siteData.build?.styleSourceSelections,
|
|
518
|
+
// pass only used metas to not generate unused preset styles
|
|
519
|
+
componentMetas: projectMetas
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
assetBaseUrl,
|
|
523
|
+
atomic: siteData.build.pages.settings?.atomicStyles ?? true
|
|
524
|
+
}
|
|
525
|
+
);
|
|
526
|
+
await ensureFileInPath(join4(generatedDir, "index.css"), cssText);
|
|
506
527
|
spinner.text = "Generating routes and pages";
|
|
507
528
|
const routeFileTemplate = await readFile4(
|
|
508
529
|
normalize(
|
|
@@ -515,11 +536,11 @@ var prebuild = async (options) => {
|
|
|
515
536
|
),
|
|
516
537
|
"utf8"
|
|
517
538
|
);
|
|
518
|
-
for (const [
|
|
539
|
+
for (const [pathname, pageComponents] of Object.entries(componentsByPage)) {
|
|
519
540
|
const scope = createScope([
|
|
520
541
|
// manually maintained list of occupied identifiers
|
|
521
542
|
"useState",
|
|
522
|
-
"
|
|
543
|
+
"Fragment",
|
|
523
544
|
"PageData",
|
|
524
545
|
"Asset",
|
|
525
546
|
"fontAssets",
|
|
@@ -528,7 +549,7 @@ var prebuild = async (options) => {
|
|
|
528
549
|
"projectId",
|
|
529
550
|
"formsProperties",
|
|
530
551
|
"Page",
|
|
531
|
-
"
|
|
552
|
+
"_props"
|
|
532
553
|
]);
|
|
533
554
|
const namespaces = /* @__PURE__ */ new Map();
|
|
534
555
|
const BASE_NAMESPACE = "@webstudio-is/sdk-components-react";
|
|
@@ -560,25 +581,27 @@ var prebuild = async (options) => {
|
|
|
560
581
|
componentImports += `import { ${specifiers} } from "${namespace}";
|
|
561
582
|
`;
|
|
562
583
|
}
|
|
563
|
-
const pageData = siteDataByPage[
|
|
584
|
+
const pageData = siteDataByPage[pathname];
|
|
564
585
|
const renderedPageData = {
|
|
565
|
-
|
|
586
|
+
project: siteData.build.pages.meta,
|
|
566
587
|
page: pageData.page
|
|
567
588
|
};
|
|
568
589
|
const rootInstanceId = pageData.page.rootInstanceId;
|
|
569
590
|
const instances = new Map(pageData.build.instances);
|
|
570
591
|
const props = new Map(pageData.build.props);
|
|
571
592
|
const dataSources = new Map(pageData.build.dataSources);
|
|
593
|
+
const resources = new Map(pageData.build.resources);
|
|
572
594
|
const utilsExport = generateUtilsExport({
|
|
573
595
|
pages: siteData.build.pages,
|
|
574
596
|
props
|
|
575
597
|
});
|
|
576
598
|
const pageComponent = generatePageComponent({
|
|
577
599
|
scope,
|
|
578
|
-
|
|
600
|
+
page: pageData.page,
|
|
579
601
|
instances,
|
|
580
602
|
props,
|
|
581
603
|
dataSources,
|
|
604
|
+
classesMap,
|
|
582
605
|
indexesWithinAncestors: getIndexesWithinAncestors(
|
|
583
606
|
projectMetas,
|
|
584
607
|
instances,
|
|
@@ -588,9 +611,9 @@ var prebuild = async (options) => {
|
|
|
588
611
|
const pageExports = `/* eslint-disable */
|
|
589
612
|
/* This is a auto generated file for building the project */
|
|
590
613
|
|
|
591
|
-
import {
|
|
614
|
+
import { Fragment, useState } from "react";
|
|
592
615
|
import type { PageData } from "~/routes/_index";
|
|
593
|
-
import type { Asset, ImageAsset,
|
|
616
|
+
import type { Asset, ImageAsset, ProjectMeta } from "@webstudio-is/sdk";
|
|
594
617
|
${componentImports}
|
|
595
618
|
export const fontAssets: Asset[] = ${JSON.stringify(fontAssets)}
|
|
596
619
|
export const imageAssets: ImageAsset[] = ${JSON.stringify(imageAssets)}
|
|
@@ -604,31 +627,28 @@ ${pageComponent}
|
|
|
604
627
|
|
|
605
628
|
export { Page }
|
|
606
629
|
|
|
630
|
+
${generateRemixParams(pathname)}
|
|
631
|
+
|
|
607
632
|
${utilsExport}
|
|
608
633
|
`;
|
|
609
|
-
const
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
634
|
+
const remixRoute = generateRemixRoute(pathname);
|
|
635
|
+
const fileName = `${remixRoute}.tsx`;
|
|
636
|
+
const routeFileContent = routeFileTemplate.replace('../__generated__/index"', `../__generated__/${remixRoute}"`).replace(
|
|
637
|
+
'../__generated__/index.server"',
|
|
638
|
+
`../__generated__/${remixRoute}.server"`
|
|
613
639
|
);
|
|
614
640
|
await ensureFileInPath(join4(routesDir, fileName), routeFileContent);
|
|
615
641
|
await ensureFileInPath(join4(generatedDir, fileName), pageExports);
|
|
642
|
+
await ensureFileInPath(
|
|
643
|
+
join4(generatedDir, `${remixRoute}.server.tsx`),
|
|
644
|
+
generateResourcesLoader({
|
|
645
|
+
scope,
|
|
646
|
+
page: pageData.page,
|
|
647
|
+
dataSources,
|
|
648
|
+
resources
|
|
649
|
+
})
|
|
650
|
+
);
|
|
616
651
|
}
|
|
617
|
-
spinner.text = "Generating css file";
|
|
618
|
-
const cssText = generateCssText(
|
|
619
|
-
{
|
|
620
|
-
assets: siteData.assets,
|
|
621
|
-
breakpoints: siteData.build?.breakpoints,
|
|
622
|
-
styles: siteData.build?.styles,
|
|
623
|
-
styleSourceSelections: siteData.build?.styleSourceSelections,
|
|
624
|
-
// pass only used metas to not generate unused preset styles
|
|
625
|
-
componentMetas: projectMetas
|
|
626
|
-
},
|
|
627
|
-
{
|
|
628
|
-
assetBaseUrl
|
|
629
|
-
}
|
|
630
|
-
);
|
|
631
|
-
await ensureFileInPath(join4(generatedDir, "index.css"), cssText);
|
|
632
652
|
await writeFile4(
|
|
633
653
|
join4(generatedDir, "[sitemap.xml].ts"),
|
|
634
654
|
`
|
|
@@ -788,7 +808,7 @@ Your project was successfully synced \u{1F389}`)));
|
|
|
788
808
|
[
|
|
789
809
|
"Now you can:",
|
|
790
810
|
folderName && `Go to your project: ${pc2.dim(`cd ${folderName}`)}`,
|
|
791
|
-
`Run ${pc2.dim("npm run dev")} to preview your
|
|
811
|
+
`Run ${pc2.dim("npm run dev")} to preview your project on a local server.`,
|
|
792
812
|
projectTemplate && getDeploymentInstructions(projectTemplate)
|
|
793
813
|
].filter(Boolean).join("\n")
|
|
794
814
|
);
|
|
@@ -802,8 +822,10 @@ var getDeploymentInstructions = (deployTarget) => {
|
|
|
802
822
|
return [
|
|
803
823
|
`To deploy to Netlify, run the following commands: `,
|
|
804
824
|
`Run ${pc2.dim("npx netlify-cli login")} to login to Netlify.`,
|
|
805
|
-
`Run ${pc2.dim(
|
|
806
|
-
|
|
825
|
+
`Run ${pc2.dim(
|
|
826
|
+
"npx netlify-cli sites:create"
|
|
827
|
+
)} to create a new project.`,
|
|
828
|
+
`Run ${pc2.dim("npx netlify-cli build")} to build the project`,
|
|
807
829
|
`Run ${pc2.dim("npx netlify-cli deploy")} to deploy on Netlify.`
|
|
808
830
|
].join("\n");
|
|
809
831
|
}
|
|
@@ -815,7 +837,7 @@ import makeCLI from "yargs";
|
|
|
815
837
|
// package.json
|
|
816
838
|
var package_default = {
|
|
817
839
|
name: "webstudio",
|
|
818
|
-
version: "0.
|
|
840
|
+
version: "0.124.0",
|
|
819
841
|
description: "Webstudio CLI",
|
|
820
842
|
author: "Webstudio <github@webstudio.is>",
|
|
821
843
|
homepage: "https://webstudio.is",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webstudio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.124.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.
|
|
32
|
-
"@webstudio-is/
|
|
33
|
-
"@webstudio-is/
|
|
34
|
-
"@webstudio-is/
|
|
35
|
-
"@webstudio-is/sdk-components-react": "0.
|
|
36
|
-
"@webstudio-is/sdk-components-react-
|
|
37
|
-
"@webstudio-is/sdk-components-react
|
|
31
|
+
"@webstudio-is/http-client": "0.124.0",
|
|
32
|
+
"@webstudio-is/image": "0.124.0",
|
|
33
|
+
"@webstudio-is/react-sdk": "0.124.0",
|
|
34
|
+
"@webstudio-is/sdk": "0.124.0",
|
|
35
|
+
"@webstudio-is/sdk-components-react-radix": "0.124.0",
|
|
36
|
+
"@webstudio-is/sdk-components-react-remix": "0.124.0",
|
|
37
|
+
"@webstudio-is/sdk-components-react": "0.124.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/
|
|
45
|
-
"@webstudio-is/
|
|
44
|
+
"@webstudio-is/tsconfig": "1.0.7",
|
|
45
|
+
"@webstudio-is/form-handlers": "0.124.0"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"typecheck": "tsc",
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
# This template uses this file instead of the typicial Netlify _redirects file.
|
|
1
|
+
# This template uses this file instead of the typicial Netlify \_redirects file.
|
|
2
|
+
|
|
2
3
|
# For more information about redirects and rewrites, see https://docs.netlify.com/routing/redirects/.
|
|
3
4
|
|
|
4
|
-
# Do not remove the line below. This is required to serve the
|
|
5
|
-
|
|
5
|
+
# Do not remove the line below. This is required to serve the project when deployed.
|
|
6
|
+
|
|
7
|
+
/\* /.netlify/functions/server 200
|
|
6
8
|
|
|
7
9
|
# Add other redirects and rewrites here and/or in your netlify.toml
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
type LoaderArgs,
|
|
8
8
|
json,
|
|
9
9
|
} from "@remix-run/server-runtime";
|
|
10
|
-
import
|
|
10
|
+
import { useLoaderData } from "@remix-run/react";
|
|
11
|
+
import type { Page as PageType, ProjectMeta } from "@webstudio-is/sdk";
|
|
11
12
|
import { ReactSdkContext } from "@webstudio-is/react-sdk";
|
|
12
13
|
import { n8nHandler, getFormId } from "@webstudio-is/form-handlers";
|
|
13
14
|
import {
|
|
@@ -19,16 +20,21 @@ import {
|
|
|
19
20
|
formsProperties,
|
|
20
21
|
Page,
|
|
21
22
|
imageAssets,
|
|
23
|
+
getRemixParams,
|
|
22
24
|
} from "../__generated__/index";
|
|
25
|
+
import { loadResources } from "../__generated__/index.server";
|
|
23
26
|
import css from "../__generated__/index.css";
|
|
24
27
|
import { assetBaseUrl, imageBaseUrl, imageLoader } from "~/constants.mjs";
|
|
25
28
|
|
|
26
29
|
export type PageData = {
|
|
27
|
-
|
|
30
|
+
project?: ProjectMeta;
|
|
28
31
|
page: PageType;
|
|
29
32
|
};
|
|
30
33
|
|
|
31
34
|
export const loader = async (arg: LoaderArgs) => {
|
|
35
|
+
const params = getRemixParams(arg.params);
|
|
36
|
+
const resources = await loadResources({ params });
|
|
37
|
+
|
|
32
38
|
const host =
|
|
33
39
|
arg.request.headers.get("x-forwarded-host") ||
|
|
34
40
|
arg.request.headers.get("host") ||
|
|
@@ -46,6 +52,8 @@ export const loader = async (arg: LoaderArgs) => {
|
|
|
46
52
|
host,
|
|
47
53
|
url: url.href,
|
|
48
54
|
excludeFromSearch: arg.context.EXCLUDE_FROM_SEARCH,
|
|
55
|
+
params,
|
|
56
|
+
resources,
|
|
49
57
|
},
|
|
50
58
|
// No way for current information to change, so add cache for 10 minutes
|
|
51
59
|
// In case of CRM Data, this should be set to 0
|
|
@@ -60,7 +68,7 @@ export const headers = () => {
|
|
|
60
68
|
};
|
|
61
69
|
|
|
62
70
|
export const meta: V2_ServerRuntimeMetaFunction<typeof loader> = ({ data }) => {
|
|
63
|
-
const { page,
|
|
71
|
+
const { page, project } = pageData;
|
|
64
72
|
|
|
65
73
|
const metas: ReturnType<V2_ServerRuntimeMetaFunction> = [];
|
|
66
74
|
|
|
@@ -84,16 +92,16 @@ export const meta: V2_ServerRuntimeMetaFunction<typeof loader> = ({ data }) => {
|
|
|
84
92
|
|
|
85
93
|
const origin = `https://${data?.host}`;
|
|
86
94
|
|
|
87
|
-
if (
|
|
95
|
+
if (project?.siteName) {
|
|
88
96
|
metas.push({
|
|
89
97
|
property: "og:site_name",
|
|
90
|
-
content:
|
|
98
|
+
content: project.siteName,
|
|
91
99
|
});
|
|
92
100
|
metas.push({
|
|
93
101
|
"script:ld+json": {
|
|
94
102
|
"@context": "https://schema.org",
|
|
95
103
|
"@type": "WebSite",
|
|
96
|
-
name:
|
|
104
|
+
name: project.siteName,
|
|
97
105
|
url: origin,
|
|
98
106
|
},
|
|
99
107
|
});
|
|
@@ -152,11 +160,11 @@ export const links: LinksFunction = () => {
|
|
|
152
160
|
href: css,
|
|
153
161
|
});
|
|
154
162
|
|
|
155
|
-
const {
|
|
163
|
+
const { project } = pageData;
|
|
156
164
|
|
|
157
|
-
if (
|
|
165
|
+
if (project?.faviconAssetId) {
|
|
158
166
|
const imageAsset = imageAssets.find(
|
|
159
|
-
(asset) => asset.id ===
|
|
167
|
+
(asset) => asset.id === project.faviconAssetId
|
|
160
168
|
);
|
|
161
169
|
|
|
162
170
|
if (imageAsset) {
|
|
@@ -282,6 +290,7 @@ export const action = async ({ request, context }: ActionArgs) => {
|
|
|
282
290
|
};
|
|
283
291
|
|
|
284
292
|
const Outlet = () => {
|
|
293
|
+
const { params, resources } = useLoaderData<typeof loader>();
|
|
285
294
|
return (
|
|
286
295
|
<ReactSdkContext.Provider
|
|
287
296
|
value={{
|
|
@@ -291,7 +300,7 @@ const Outlet = () => {
|
|
|
291
300
|
pagesPaths,
|
|
292
301
|
}}
|
|
293
302
|
>
|
|
294
|
-
<Page />
|
|
303
|
+
<Page params={params} resources={resources} />
|
|
295
304
|
</ReactSdkContext.Provider>
|
|
296
305
|
);
|
|
297
306
|
};
|