Skip to content

Commit bccee97

Browse files
committed
fix: Xml namespaces support
1 parent afc77fa commit bccee97

File tree

9 files changed

+708
-38
lines changed

9 files changed

+708
-38
lines changed

fixtures/webstudio-remix-vercel/.webstudio/data.json

Lines changed: 499 additions & 5 deletions
Large diffs are not rendered by default.

fixtures/webstudio-remix-vercel/app/__generated__/$resources.sitemap.xml.ts

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fixtures/webstudio-remix-vercel/app/__generated__/[sitemap.xml]._index.server.tsx

Lines changed: 39 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fixtures/webstudio-remix-vercel/app/__generated__/[sitemap.xml]._index.tsx

Lines changed: 82 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fixtures/webstudio-remix-vercel/app/__generated__/index.css

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,79 @@
1-
import type { LoaderFunctionArgs } from "@remix-run/server-runtime";
1+
import { renderToString } from "react-dom/server";
2+
import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
3+
import { isLocalResource, loadResources } from "@webstudio-is/sdk";
4+
import { ReactSdkContext } from "@webstudio-is/react-sdk/runtime";
5+
import { Page } from "../__generated__/[sitemap.xml]._index";
6+
import {
7+
getPageMeta,
8+
getRemixParams,
9+
getResources,
10+
} from "../__generated__/[sitemap.xml]._index.server";
11+
import { assetBaseUrl, imageBaseUrl, imageLoader } from "../constants.mjs";
212
import { sitemap } from "../__generated__/$resources.sitemap.xml";
313

4-
export const loader = (arg: LoaderFunctionArgs) => {
14+
const customFetch: typeof fetch = (input, init) => {
15+
if (typeof input !== "string") {
16+
return fetch(input, init);
17+
}
18+
19+
if (isLocalResource(input, "sitemap.xml")) {
20+
// @todo: dynamic import sitemap ???
21+
const response = new Response(JSON.stringify(sitemap));
22+
response.headers.set("content-type", "application/json; charset=utf-8");
23+
return Promise.resolve(response);
24+
}
25+
26+
return fetch(input, init);
27+
};
28+
29+
export const loader = async (arg: LoaderFunctionArgs) => {
30+
const url = new URL(arg.request.url);
531
const host =
632
arg.request.headers.get("x-forwarded-host") ||
733
arg.request.headers.get("host") ||
834
"";
35+
url.host = host;
36+
url.protocol = "https";
937

10-
const urls = sitemap.map((page) => {
11-
const url = new URL(`https://${host}${page.path}`);
38+
const params = getRemixParams(arg.params);
1239

13-
return `
14-
<url>
15-
<loc>${url.href}</loc>
16-
<lastmod>${page.lastModified.split("T")[0]}</lastmod>
17-
</url>
18-
`;
19-
});
40+
const system = {
41+
params,
42+
search: Object.fromEntries(url.searchParams),
43+
origin: url.origin,
44+
};
2045

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-
}
46+
const resources = await loadResources(
47+
customFetch,
48+
getResources({ system }).data
3349
);
50+
const pageMeta = getPageMeta({ system, resources });
51+
52+
if (pageMeta.redirect) {
53+
const status =
54+
pageMeta.status === 301 || pageMeta.status === 302
55+
? pageMeta.status
56+
: 302;
57+
return redirect(pageMeta.redirect, status);
58+
}
59+
60+
// typecheck
61+
arg.context.EXCLUDE_FROM_SEARCH satisfies boolean;
62+
63+
const text = renderToString(
64+
<ReactSdkContext.Provider
65+
value={{
66+
imageLoader,
67+
assetBaseUrl,
68+
imageBaseUrl,
69+
resources,
70+
}}
71+
>
72+
<Page system={system} />
73+
</ReactSdkContext.Provider>
74+
);
75+
76+
return new Response(`<?xml version="1.0" encoding="UTF-8"?>\n${text}`, {
77+
headers: { "Content-Type": "application/xml" },
78+
});
3479
};

fixtures/webstudio-remix-vercel/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"typecheck": "tsc",
77
"cli": "NODE_OPTIONS='--conditions=webstudio --import=tsx' webstudio",
88
"fixtures:link": "pnpm cli link --link https://p-cddc1d44-af37-4cb6-a430-d300cf6f932d-dot-${BUILDER_HOST:-main.development.webstudio.is}'?authToken=1cdc6026-dd5b-4624-b89b-9bd45e9bcc3d'",
9-
"fixtures:sync": "pnpm cli sync --buildId 6876de3a-942a-466b-9761-ad7cb2fa2c21 && pnpm prettier --write ./.webstudio/",
9+
"fixtures:sync": "pnpm cli sync --buildId 1710e6a3-6f3b-44c9-8e4f-4176be77673e && pnpm prettier --write ./.webstudio/",
1010
"fixtures:build": "pnpm cli build --template vercel --template internal --preview && pnpm prettier --write ./app/ ./package.json ./tsconfig.json"
1111
},
1212
"private": true,

packages/cli/src/prebuild.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ export const prebuild = async (options: {
559559
.map((scopedName) =>
560560
scopedName === "Body"
561561
? `const ${scopedName} = (props: any) => props.children;`
562-
: `const ${scopedName} = () => null;`
562+
: `const ${scopedName} = (props: any) => null;`
563563
)
564564
.join("\n");
565565
}

packages/sdk-components-react/src/xml-node.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ export const defaultTag = "div";
1414
type Props = {
1515
tag: string;
1616
xmlns?: string;
17-
children: ReactNode;
17+
children?: ReactNode;
18+
rel?: string;
19+
hreflang?: string;
20+
href?: string;
21+
"xmlns:xhtml"?: string;
1822
};
1923

2024
export const XmlNode = forwardRef<ElementRef<"div">, Props>(
@@ -42,7 +46,7 @@ export const XmlNode = forwardRef<ElementRef<"div">, Props>(
4246
// Must start from letter or underscore
4347
.replace(/^[^\p{L}_]+/u, "")
4448
// Clear all non letter, number, underscore, dot, and dash
45-
.replaceAll(/[^\p{L}\p{N}\-._]+/gu, "");
49+
.replaceAll(/[^\p{L}\p{N}\-._:]+/gu, "");
4650

4751
const attributes = attributeEntries.map(
4852
([key, value]) => `${key}=${JSON.stringify(value)}`

0 commit comments

Comments
 (0)