full site update

This commit is contained in:
2025-07-24 18:46:24 +02:00
parent bfe2b90d8d
commit 37a6e0ab31
6912 changed files with 540482 additions and 361712 deletions

View File

@@ -1,8 +1,10 @@
import type { ComponentInstance, ManifestData, RouteData, SSRManifest } from '../../@types/astro.js';
import type { ComponentInstance, RoutesList } from '../../types/astro.js';
import type { RouteData, SSRManifest } from '../../types/public/internal.js';
export declare const SERVER_ISLAND_ROUTE = "/_server-islands/[name]";
export declare const SERVER_ISLAND_COMPONENT = "_server-islands.astro";
export declare const SERVER_ISLAND_BASE_PREFIX = "_server-islands";
type ConfigFields = Pick<SSRManifest, 'base' | 'trailingSlash'>;
export declare function getServerIslandRouteData(config: ConfigFields): RouteData;
export declare function ensureServerIslandRoute(config: ConfigFields, routeManifest: ManifestData): void;
export declare function injectServerIslandRoute(config: ConfigFields, routeManifest: RoutesList): void;
export declare function createEndpoint(manifest: SSRManifest): ComponentInstance;
export {};

View File

@@ -2,11 +2,13 @@ import {
renderComponent,
renderTemplate
} from "../../runtime/server/index.js";
import { isAstroComponentFactory } from "../../runtime/server/render/astro/factory.js";
import { createSlotValueFromString } from "../../runtime/server/render/slot.js";
import { decryptString } from "../encryption.js";
import { getPattern } from "../routing/manifest/pattern.js";
const SERVER_ISLAND_ROUTE = "/_server-islands/[name]";
const SERVER_ISLAND_COMPONENT = "_server-islands.astro";
const SERVER_ISLAND_BASE_PREFIX = "_server-islands";
function getServerIslandRouteData(config) {
const segments = [
[{ content: "_server-islands", dynamic: false, spread: false }],
@@ -22,22 +24,56 @@ function getServerIslandRouteData(config) {
prerender: false,
isIndex: false,
fallbackRoutes: [],
route: SERVER_ISLAND_ROUTE
route: SERVER_ISLAND_ROUTE,
origin: "internal"
};
return route;
}
function ensureServerIslandRoute(config, routeManifest) {
if (routeManifest.routes.some((route) => route.route === "/_server-islands/[name]")) {
return;
}
function injectServerIslandRoute(config, routeManifest) {
routeManifest.routes.unshift(getServerIslandRouteData(config));
}
function badRequest(reason) {
return new Response(null, {
status: 400,
statusText: "Bad request: " + reason
});
}
async function getRequestData(request) {
switch (request.method) {
case "GET": {
const url = new URL(request.url);
const params = url.searchParams;
if (!params.has("s") || !params.has("e") || !params.has("p")) {
return badRequest("Missing required query parameters.");
}
const rawSlots = params.get("s");
try {
return {
componentExport: params.get("e"),
encryptedProps: params.get("p"),
slots: JSON.parse(rawSlots)
};
} catch {
return badRequest("Invalid slots format.");
}
}
case "POST": {
try {
const raw = await request.text();
const data = JSON.parse(raw);
return data;
} catch {
return badRequest("Request format is invalid.");
}
}
default: {
return new Response(null, { status: 405 });
}
}
}
function createEndpoint(manifest) {
const page = async (result) => {
const params = result.params;
const request = result.request;
const raw = await request.text();
const data = JSON.parse(raw);
if (!params.name) {
return new Response(null, {
status: 400,
@@ -45,6 +81,10 @@ function createEndpoint(manifest) {
});
}
const componentId = params.name;
const data = await getRequestData(result.request);
if (data instanceof Response) {
return data;
}
const imp = manifest.serverIslandMap?.get(componentId);
if (!imp) {
return new Response(null, {
@@ -54,14 +94,23 @@ function createEndpoint(manifest) {
}
const key = await manifest.key;
const encryptedProps = data.encryptedProps;
const propString = await decryptString(key, encryptedProps);
const propString = encryptedProps === "" ? "{}" : await decryptString(key, encryptedProps);
const props = JSON.parse(propString);
const componentModule = await imp();
const Component = componentModule[data.componentExport];
let Component = componentModule[data.componentExport];
const slots = {};
for (const prop in data.slots) {
slots[prop] = createSlotValueFromString(data.slots[prop]);
}
result.response.headers.set("X-Robots-Tag", "noindex");
if (isAstroComponentFactory(Component)) {
const ServerIsland = Component;
Component = function(...args) {
return ServerIsland.apply(this, args);
};
Object.assign(Component, ServerIsland);
Component.propagation = "self";
}
return renderTemplate`${renderComponent(result, "Component", Component, props, slots)}`;
};
page.isAstroComponentFactory = true;
@@ -72,9 +121,10 @@ function createEndpoint(manifest) {
return instance;
}
export {
SERVER_ISLAND_BASE_PREFIX,
SERVER_ISLAND_COMPONENT,
SERVER_ISLAND_ROUTE,
createEndpoint,
ensureServerIslandRoute,
getServerIslandRouteData
getServerIslandRouteData,
injectServerIslandRoute
};

View File

@@ -1,7 +1,4 @@
import type { Plugin as VitePlugin } from 'vite';
import type { AstroSettings } from '../../@types/astro.js';
import type { AstroPluginOptions } from '../../types/astro.js';
export declare const VIRTUAL_ISLAND_MAP_ID = "@astro-server-islands";
export declare const RESOLVED_VIRTUAL_ISLAND_MAP_ID: string;
export declare function vitePluginServerIslands({ settings }: {
settings: AstroSettings;
}): VitePlugin;
export declare function vitePluginServerIslands({ settings, logger }: AstroPluginOptions): VitePlugin;

View File

@@ -1,7 +1,8 @@
import MagicString from "magic-string";
const VIRTUAL_ISLAND_MAP_ID = "@astro-server-islands";
const RESOLVED_VIRTUAL_ISLAND_MAP_ID = "\0" + VIRTUAL_ISLAND_MAP_ID;
const serverIslandPlaceholder = "'$$server-islands$$'";
function vitePluginServerIslands({ settings }) {
function vitePluginServerIslands({ settings, logger }) {
let command = "serve";
let viteServer = null;
const referenceIdMap = /* @__PURE__ */ new Map();
@@ -21,46 +22,53 @@ function vitePluginServerIslands({ settings }) {
},
load(id) {
if (id === RESOLVED_VIRTUAL_ISLAND_MAP_ID) {
return `export const serverIslandMap = ${serverIslandPlaceholder};`;
return { code: `export const serverIslandMap = ${serverIslandPlaceholder};` };
}
},
transform(_code, id) {
if (id.endsWith(".astro")) {
const info = this.getModuleInfo(id);
if (info?.meta) {
const astro = info.meta.astro;
if (astro?.serverComponents.length) {
for (const comp of astro.serverComponents) {
if (!settings.serverIslandNameMap.has(comp.resolvedPath)) {
let name = comp.localName;
let idx = 1;
while (true) {
if (!settings.serverIslandMap.has(name)) {
break;
}
name += idx++;
}
settings.serverIslandNameMap.set(comp.resolvedPath, name);
settings.serverIslandMap.set(name, () => {
return viteServer?.ssrLoadModule(comp.resolvedPath);
});
if (command === "build") {
let referenceId = this.emitFile({
type: "chunk",
id: comp.specifier,
importer: id,
name: comp.localName
});
referenceIdMap.set(comp.resolvedPath, referenceId);
}
}
const info = this.getModuleInfo(id);
if (!info?.meta?.astro) return;
const astro = info.meta.astro;
for (const comp of astro.serverComponents) {
if (!settings.serverIslandNameMap.has(comp.resolvedPath)) {
if (!settings.adapter) {
logger.error(
"islands",
"You tried to render a server island without an adapter added to your project. An adapter is required to use the `server:defer` attribute on any component. Your project will fail to build unless you add an adapter or remove the attribute."
);
}
let name = comp.localName;
let idx = 1;
while (true) {
if (!settings.serverIslandMap.has(name)) {
break;
}
name += idx++;
}
settings.serverIslandNameMap.set(comp.resolvedPath, name);
settings.serverIslandMap.set(name, () => {
return viteServer?.ssrLoadModule(comp.resolvedPath);
});
if (command === "build") {
let referenceId = this.emitFile({
type: "chunk",
id: comp.specifier,
importer: id,
name: comp.localName
});
referenceIdMap.set(comp.resolvedPath, referenceId);
}
}
}
},
renderChunk(code) {
if (code.includes(serverIslandPlaceholder)) {
if (referenceIdMap.size === 0) {
return {
code: code.replace(serverIslandPlaceholder, "new Map();"),
map: null
};
}
let mapSource = "new Map([";
for (let [resolvedPath, referenceId] of referenceIdMap) {
const fileName = this.getFileName(referenceId);
@@ -70,13 +78,17 @@ function vitePluginServerIslands({ settings }) {
}
mapSource += "\n]);";
referenceIdMap.clear();
return code.replace(serverIslandPlaceholder, mapSource);
const ms = new MagicString(code);
ms.replace(serverIslandPlaceholder, mapSource);
return {
code: ms.toString(),
map: ms.generateMap({ hires: "boundary" })
};
}
}
};
}
export {
RESOLVED_VIRTUAL_ISLAND_MAP_ID,
VIRTUAL_ISLAND_MAP_ID,
vitePluginServerIslands
};