Skip to content

Commit

Permalink
fix: Xml namespaces support
Browse files Browse the repository at this point in the history
  • Loading branch information
istarkov committed Oct 28, 2024
1 parent afc77fa commit bccee97
Show file tree
Hide file tree
Showing 9 changed files with 708 additions and 38 deletions.
504 changes: 499 additions & 5 deletions fixtures/webstudio-remix-vercel/.webstudio/data.json

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions fixtures/webstudio-remix-vercel/app/__generated__/index.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

91 changes: 68 additions & 23 deletions fixtures/webstudio-remix-vercel/app/routes/[sitemap.xml]._index.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,79 @@
import type { LoaderFunctionArgs } from "@remix-run/server-runtime";
import { renderToString } from "react-dom/server";
import { type LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
import { isLocalResource, loadResources } from "@webstudio-is/sdk";
import { ReactSdkContext } from "@webstudio-is/react-sdk/runtime";
import { Page } from "../__generated__/[sitemap.xml]._index";
import {
getPageMeta,
getRemixParams,
getResources,
} from "../__generated__/[sitemap.xml]._index.server";
import { assetBaseUrl, imageBaseUrl, imageLoader } from "../constants.mjs";
import { sitemap } from "../__generated__/$resources.sitemap.xml";

export const loader = (arg: LoaderFunctionArgs) => {
const customFetch: typeof fetch = (input, init) => {
if (typeof input !== "string") {
return fetch(input, init);
}

if (isLocalResource(input, "sitemap.xml")) {
// @todo: dynamic import sitemap ???
const response = new Response(JSON.stringify(sitemap));
response.headers.set("content-type", "application/json; charset=utf-8");
return Promise.resolve(response);
}

return fetch(input, init);
};

export const loader = async (arg: LoaderFunctionArgs) => {
const url = new URL(arg.request.url);
const host =
arg.request.headers.get("x-forwarded-host") ||
arg.request.headers.get("host") ||
"";
url.host = host;
url.protocol = "https";

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

return `
<url>
<loc>${url.href}</loc>
<lastmod>${page.lastModified.split("T")[0]}</lastmod>
</url>
`;
});
const system = {
params,
search: Object.fromEntries(url.searchParams),
origin: url.origin,
};

return new Response(
`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.join("")}
</urlset>
`,
{
headers: {
"Content-Type": "application/xml",
},
status: 200,
}
const resources = await loadResources(
customFetch,
getResources({ system }).data
);
const pageMeta = getPageMeta({ system, resources });

if (pageMeta.redirect) {
const status =
pageMeta.status === 301 || pageMeta.status === 302
? pageMeta.status
: 302;
return redirect(pageMeta.redirect, status);
}

// typecheck
arg.context.EXCLUDE_FROM_SEARCH satisfies boolean;

const text = renderToString(
<ReactSdkContext.Provider
value={{
imageLoader,
assetBaseUrl,
imageBaseUrl,
resources,
}}
>
<Page system={system} />
</ReactSdkContext.Provider>
);

return new Response(`<?xml version="1.0" encoding="UTF-8"?>\n${text}`, {
headers: { "Content-Type": "application/xml" },
});
};
2 changes: 1 addition & 1 deletion fixtures/webstudio-remix-vercel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"typecheck": "tsc",
"cli": "NODE_OPTIONS='--conditions=webstudio --import=tsx' webstudio",
"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'",
"fixtures:sync": "pnpm cli sync --buildId 6876de3a-942a-466b-9761-ad7cb2fa2c21 && pnpm prettier --write ./.webstudio/",
"fixtures:sync": "pnpm cli sync --buildId 1710e6a3-6f3b-44c9-8e4f-4176be77673e && pnpm prettier --write ./.webstudio/",
"fixtures:build": "pnpm cli build --template vercel --template internal --preview && pnpm prettier --write ./app/ ./package.json ./tsconfig.json"
},
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/prebuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ export const prebuild = async (options: {
.map((scopedName) =>
scopedName === "Body"
? `const ${scopedName} = (props: any) => props.children;`
: `const ${scopedName} = () => null;`
: `const ${scopedName} = (props: any) => null;`
)
.join("\n");
}
Expand Down
8 changes: 6 additions & 2 deletions packages/sdk-components-react/src/xml-node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ export const defaultTag = "div";
type Props = {
tag: string;
xmlns?: string;
children: ReactNode;
children?: ReactNode;
rel?: string;
hreflang?: string;
href?: string;
"xmlns:xhtml"?: string;
};

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

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

0 comments on commit bccee97

Please sign in to comment.