kjelsrud.dev/node_modules/astro/dist/runtime/server/hydration.js
2023-07-19 21:31:30 +02:00

112 lines
3.6 KiB
JavaScript

import { AstroError, AstroErrorData } from "../../core/errors/index.js";
import { escapeHTML } from "./escape.js";
import { serializeProps } from "./serialize.js";
import { serializeListValue } from "./util.js";
function extractDirectives(inputProps, clientDirectives) {
let extracted = {
isPage: false,
hydration: null,
props: {}
};
for (const [key, value] of Object.entries(inputProps)) {
if (key.startsWith("server:")) {
if (key === "server:root") {
extracted.isPage = true;
}
}
if (key.startsWith("client:")) {
if (!extracted.hydration) {
extracted.hydration = {
directive: "",
value: "",
componentUrl: "",
componentExport: { value: "" }
};
}
switch (key) {
case "client:component-path": {
extracted.hydration.componentUrl = value;
break;
}
case "client:component-export": {
extracted.hydration.componentExport.value = value;
break;
}
case "client:component-hydration": {
break;
}
case "client:display-name": {
break;
}
default: {
extracted.hydration.directive = key.split(":")[1];
extracted.hydration.value = value;
if (!clientDirectives.has(extracted.hydration.directive)) {
const hydrationMethods = Array.from(clientDirectives.keys()).map((d) => `client:${d}`).join(", ");
throw new Error(
`Error: invalid hydration directive "${key}". Supported hydration methods: ${hydrationMethods}`
);
}
if (extracted.hydration.directive === "media" && typeof extracted.hydration.value !== "string") {
throw new AstroError(AstroErrorData.MissingMediaQueryDirective);
}
break;
}
}
} else if (key === "class:list") {
if (value) {
extracted.props[key.slice(0, -5)] = serializeListValue(value);
}
} else {
extracted.props[key] = value;
}
}
for (const sym of Object.getOwnPropertySymbols(inputProps)) {
extracted.props[sym] = inputProps[sym];
}
return extracted;
}
async function generateHydrateScript(scriptOptions, metadata) {
const { renderer, result, astroId, props, attrs } = scriptOptions;
const { hydrate, componentUrl, componentExport } = metadata;
if (!componentExport.value) {
throw new Error(
`Unable to resolve a valid export for "${metadata.displayName}"! Please open an issue at https://astro.build/issues!`
);
}
const island = {
children: "",
props: {
// This is for HMR, probably can avoid it in prod
uid: astroId
}
};
if (attrs) {
for (const [key, value] of Object.entries(attrs)) {
island.props[key] = escapeHTML(value);
}
}
island.props["component-url"] = await result.resolve(decodeURI(componentUrl));
if (renderer.clientEntrypoint) {
island.props["component-export"] = componentExport.value;
island.props["renderer-url"] = await result.resolve(decodeURI(renderer.clientEntrypoint));
island.props["props"] = escapeHTML(serializeProps(props, metadata));
}
island.props["ssr"] = "";
island.props["client"] = hydrate;
let beforeHydrationUrl = await result.resolve("astro:scripts/before-hydration.js");
if (beforeHydrationUrl.length) {
island.props["before-hydration-url"] = beforeHydrationUrl;
}
island.props["opts"] = escapeHTML(
JSON.stringify({
name: metadata.displayName,
value: metadata.hydrateArgs || ""
})
);
return island;
}
export {
extractDirectives,
generateHydrateScript
};