feat: scaffold Astro + Tailwind project
This commit is contained in:
14
node_modules/astro/dist/core/server-islands/endpoint.d.ts
generated
vendored
Normal file
14
node_modules/astro/dist/core/server-islands/endpoint.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { ComponentInstance, RoutesList } from '../../types/astro.js';
|
||||
import type { SSRManifest } from '../../types/public/internal.js';
|
||||
export declare const SERVER_ISLAND_ROUTE = "/_server-islands/[name]";
|
||||
export declare const SERVER_ISLAND_COMPONENT = "_server-islands.astro";
|
||||
type ConfigFields = Pick<SSRManifest, 'base' | 'trailingSlash'>;
|
||||
export declare function injectServerIslandRoute(config: ConfigFields, routeManifest: RoutesList): void;
|
||||
export type RenderOptions = {
|
||||
encryptedComponentExport: string;
|
||||
encryptedProps: string;
|
||||
encryptedSlots: string;
|
||||
};
|
||||
export declare function getRequestData(request: Request, bodySizeLimit?: number): Promise<Response | RenderOptions>;
|
||||
export declare function createEndpoint(manifest: SSRManifest): ComponentInstance;
|
||||
export {};
|
||||
173
node_modules/astro/dist/core/server-islands/endpoint.js
generated
vendored
Normal file
173
node_modules/astro/dist/core/server-islands/endpoint.js
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
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 { BodySizeLimitError, readBodyWithLimit } from "../request-body.js";
|
||||
import { getPattern } from "../routing/pattern.js";
|
||||
const SERVER_ISLAND_ROUTE = "/_server-islands/[name]";
|
||||
const SERVER_ISLAND_COMPONENT = "_server-islands.astro";
|
||||
function getServerIslandRouteData(config) {
|
||||
const segments = [
|
||||
[{ content: "_server-islands", dynamic: false, spread: false }],
|
||||
[{ content: "name", dynamic: true, spread: false }]
|
||||
];
|
||||
const route = {
|
||||
type: "page",
|
||||
component: SERVER_ISLAND_COMPONENT,
|
||||
params: ["name"],
|
||||
segments,
|
||||
pattern: getPattern(segments, config.base, config.trailingSlash),
|
||||
prerender: false,
|
||||
isIndex: false,
|
||||
fallbackRoutes: [],
|
||||
route: SERVER_ISLAND_ROUTE,
|
||||
origin: "internal",
|
||||
distURL: []
|
||||
};
|
||||
return route;
|
||||
}
|
||||
function injectServerIslandRoute(config, routeManifest) {
|
||||
routeManifest.routes.unshift(getServerIslandRouteData(config));
|
||||
}
|
||||
function badRequest(reason) {
|
||||
return new Response(null, {
|
||||
status: 400,
|
||||
statusText: "Bad request: " + reason
|
||||
});
|
||||
}
|
||||
const DEFAULT_BODY_SIZE_LIMIT = 1024 * 1024;
|
||||
async function getRequestData(request, bodySizeLimit = DEFAULT_BODY_SIZE_LIMIT) {
|
||||
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 encryptedSlots = params.get("s");
|
||||
return {
|
||||
encryptedComponentExport: params.get("e"),
|
||||
encryptedProps: params.get("p"),
|
||||
encryptedSlots
|
||||
};
|
||||
}
|
||||
case "POST": {
|
||||
try {
|
||||
const body = await readBodyWithLimit(request, bodySizeLimit);
|
||||
const raw = new TextDecoder().decode(body);
|
||||
const data = JSON.parse(raw);
|
||||
if (Object.hasOwn(data, "slots") && typeof data.slots === "object") {
|
||||
return badRequest("Plaintext slots are not allowed. Slots must be encrypted.");
|
||||
}
|
||||
if (Object.hasOwn(data, "componentExport") && typeof data.componentExport === "string") {
|
||||
return badRequest(
|
||||
"Plaintext componentExport is not allowed. componentExport must be encrypted."
|
||||
);
|
||||
}
|
||||
return data;
|
||||
} catch (e) {
|
||||
if (e instanceof BodySizeLimitError) {
|
||||
return new Response(null, {
|
||||
status: 413,
|
||||
statusText: e.message
|
||||
});
|
||||
}
|
||||
if (e instanceof SyntaxError) {
|
||||
return badRequest("Request format is invalid.");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return new Response(null, { status: 405 });
|
||||
}
|
||||
}
|
||||
}
|
||||
function createEndpoint(manifest) {
|
||||
const page = async (result) => {
|
||||
const params = result.params;
|
||||
if (!params.name) {
|
||||
return new Response(null, {
|
||||
status: 400,
|
||||
statusText: "Bad request"
|
||||
});
|
||||
}
|
||||
const componentId = params.name;
|
||||
const data = await getRequestData(result.request, manifest.serverIslandBodySizeLimit);
|
||||
if (data instanceof Response) {
|
||||
return data;
|
||||
}
|
||||
const serverIslandMappings = await manifest.serverIslandMappings?.();
|
||||
const serverIslandMap = await serverIslandMappings?.serverIslandMap;
|
||||
let imp = serverIslandMap?.get(componentId);
|
||||
if (!imp) {
|
||||
return new Response(null, {
|
||||
status: 404,
|
||||
statusText: "Not found"
|
||||
});
|
||||
}
|
||||
const key = await manifest.key;
|
||||
let componentExport;
|
||||
try {
|
||||
componentExport = await decryptString(
|
||||
key,
|
||||
data.encryptedComponentExport,
|
||||
`export:${componentId}`
|
||||
);
|
||||
} catch (_e) {
|
||||
return badRequest("Encrypted componentExport value is invalid.");
|
||||
}
|
||||
const encryptedProps = data.encryptedProps;
|
||||
let props = {};
|
||||
if (encryptedProps !== "") {
|
||||
try {
|
||||
const propString = await decryptString(key, encryptedProps, `props:${componentId}`);
|
||||
props = JSON.parse(propString);
|
||||
} catch (_e) {
|
||||
return badRequest("Encrypted props value is invalid.");
|
||||
}
|
||||
}
|
||||
let decryptedSlots = {};
|
||||
const encryptedSlots = data.encryptedSlots;
|
||||
if (encryptedSlots !== "") {
|
||||
try {
|
||||
const slotsString = await decryptString(key, encryptedSlots, `slots:${componentId}`);
|
||||
decryptedSlots = JSON.parse(slotsString);
|
||||
} catch (_e) {
|
||||
return badRequest("Encrypted slots value is invalid.");
|
||||
}
|
||||
}
|
||||
const componentModule = await imp();
|
||||
let Component = componentModule[componentExport];
|
||||
const slots = {};
|
||||
for (const prop in decryptedSlots) {
|
||||
slots[prop] = createSlotValueFromString(decryptedSlots[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;
|
||||
const instance = {
|
||||
default: page,
|
||||
partial: true
|
||||
};
|
||||
return instance;
|
||||
}
|
||||
export {
|
||||
SERVER_ISLAND_COMPONENT,
|
||||
SERVER_ISLAND_ROUTE,
|
||||
createEndpoint,
|
||||
getRequestData,
|
||||
injectServerIslandRoute
|
||||
};
|
||||
44
node_modules/astro/dist/core/server-islands/shared-state.d.ts
generated
vendored
Normal file
44
node_modules/astro/dist/core/server-islands/shared-state.d.ts
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
type ServerIslandDiscovery = {
|
||||
resolvedPath: string;
|
||||
localName: string;
|
||||
specifier: string;
|
||||
importer: string;
|
||||
};
|
||||
type ServerIslandRecord = Omit<ServerIslandDiscovery, 'resolvedPath'> & {
|
||||
islandName: string;
|
||||
};
|
||||
export declare class ServerIslandsState {
|
||||
private islandsByResolvedPath;
|
||||
private resolvedPathByIslandName;
|
||||
private referenceIdByResolvedPath;
|
||||
hasIslands(): boolean;
|
||||
/**
|
||||
* Record a discovered server island.
|
||||
*
|
||||
* Dedupe is based on `resolvedPath`: if the same resolved path is discovered
|
||||
* again from a different importer/specifier, the first record is preserved.
|
||||
* This keeps island names stable across repeated scans.
|
||||
*/
|
||||
discover(island: ServerIslandDiscovery): ServerIslandRecord;
|
||||
getDiscoveredIslands(): Iterable<ServerIslandRecord>;
|
||||
hasReferenceId(resolvedPath: string): boolean;
|
||||
setReferenceId(resolvedPath: string, referenceId: string): void;
|
||||
getDiscoveredIslandEntries(): Iterable<[string, ServerIslandRecord]>;
|
||||
/**
|
||||
* Build import-map source from discovered islands.
|
||||
*
|
||||
* Used by non-SSR build output and dev replacement paths where we can import
|
||||
* directly from discovered component paths.
|
||||
*/
|
||||
createImportMapSourceFromDiscovered(toImportPath: (fileName: string) => string): string;
|
||||
/**
|
||||
* Build import-map source from Rollup reference ids.
|
||||
*
|
||||
* Used by SSR build output: reference ids are resolved to final emitted chunk
|
||||
* file names before generating import() mappings.
|
||||
*/
|
||||
createImportMapSourceFromReferences(resolveFileName: (referenceId: string) => string, toImportPath: (fileName: string) => string): string;
|
||||
createNameMapSource(): string;
|
||||
private createImportMapSource;
|
||||
}
|
||||
export {};
|
||||
96
node_modules/astro/dist/core/server-islands/shared-state.js
generated
vendored
Normal file
96
node_modules/astro/dist/core/server-islands/shared-state.js
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
class ServerIslandsState {
|
||||
// Canonical source of discovered islands keyed by resolved component path.
|
||||
islandsByResolvedPath = /* @__PURE__ */ new Map();
|
||||
// Reverse lookup used to keep island names unique and stable.
|
||||
resolvedPathByIslandName = /* @__PURE__ */ new Map();
|
||||
// Rollup reference ids emitted for SSR chunks, keyed by resolved path.
|
||||
referenceIdByResolvedPath = /* @__PURE__ */ new Map();
|
||||
hasIslands() {
|
||||
return this.islandsByResolvedPath.size > 0;
|
||||
}
|
||||
/**
|
||||
* Record a discovered server island.
|
||||
*
|
||||
* Dedupe is based on `resolvedPath`: if the same resolved path is discovered
|
||||
* again from a different importer/specifier, the first record is preserved.
|
||||
* This keeps island names stable across repeated scans.
|
||||
*/
|
||||
discover(island) {
|
||||
const { resolvedPath, ...discovery } = island;
|
||||
const existing = this.islandsByResolvedPath.get(resolvedPath);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
let name = island.localName;
|
||||
let idx = 1;
|
||||
while (this.resolvedPathByIslandName.has(name)) {
|
||||
name += idx++;
|
||||
}
|
||||
const record = {
|
||||
...discovery,
|
||||
islandName: name
|
||||
};
|
||||
this.islandsByResolvedPath.set(resolvedPath, record);
|
||||
this.resolvedPathByIslandName.set(name, resolvedPath);
|
||||
return record;
|
||||
}
|
||||
getDiscoveredIslands() {
|
||||
return this.islandsByResolvedPath.values();
|
||||
}
|
||||
hasReferenceId(resolvedPath) {
|
||||
return this.referenceIdByResolvedPath.has(resolvedPath);
|
||||
}
|
||||
setReferenceId(resolvedPath, referenceId) {
|
||||
this.referenceIdByResolvedPath.set(resolvedPath, referenceId);
|
||||
}
|
||||
getDiscoveredIslandEntries() {
|
||||
return this.islandsByResolvedPath.entries();
|
||||
}
|
||||
/**
|
||||
* Build import-map source from discovered islands.
|
||||
*
|
||||
* Used by non-SSR build output and dev replacement paths where we can import
|
||||
* directly from discovered component paths.
|
||||
*/
|
||||
createImportMapSourceFromDiscovered(toImportPath) {
|
||||
const entries = Array.from(
|
||||
this.islandsByResolvedPath,
|
||||
([resolvedPath, island]) => [island.islandName, resolvedPath]
|
||||
);
|
||||
return this.createImportMapSource(entries, toImportPath);
|
||||
}
|
||||
/**
|
||||
* Build import-map source from Rollup reference ids.
|
||||
*
|
||||
* Used by SSR build output: reference ids are resolved to final emitted chunk
|
||||
* file names before generating import() mappings.
|
||||
*/
|
||||
createImportMapSourceFromReferences(resolveFileName, toImportPath) {
|
||||
const entries = [];
|
||||
for (const [resolvedPath, referenceId] of this.referenceIdByResolvedPath) {
|
||||
const island = this.islandsByResolvedPath.get(resolvedPath);
|
||||
if (!island) continue;
|
||||
entries.push([island.islandName, resolveFileName(referenceId)]);
|
||||
}
|
||||
return this.createImportMapSource(entries, toImportPath);
|
||||
}
|
||||
createNameMapSource() {
|
||||
const entries = Array.from(
|
||||
this.islandsByResolvedPath,
|
||||
([resolvedPath, island]) => [resolvedPath, island.islandName]
|
||||
);
|
||||
return `new Map(${JSON.stringify(entries, null, 2)})`;
|
||||
}
|
||||
createImportMapSource(entries, toImportPath) {
|
||||
const mappings = Array.from(entries, ([islandName, fileName]) => {
|
||||
const importPath = toImportPath(fileName);
|
||||
return ` [${JSON.stringify(islandName)}, () => import(${JSON.stringify(importPath)})],`;
|
||||
});
|
||||
return `new Map([
|
||||
${mappings.join("\n")}
|
||||
])`;
|
||||
}
|
||||
}
|
||||
export {
|
||||
ServerIslandsState
|
||||
};
|
||||
8
node_modules/astro/dist/core/server-islands/vite-plugin-server-islands.d.ts
generated
vendored
Normal file
8
node_modules/astro/dist/core/server-islands/vite-plugin-server-islands.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { Plugin as VitePlugin } from 'vite';
|
||||
import type { AstroPluginOptions } from '../../types/astro.js';
|
||||
import type { ServerIslandsState } from './shared-state.js';
|
||||
export declare const SERVER_ISLAND_MANIFEST = "virtual:astro:server-island-manifest";
|
||||
export declare const SERVER_ISLAND_MAP_MARKER = "$$server-islands-map$$";
|
||||
export declare function vitePluginServerIslands({ settings, serverIslandsState, }: AstroPluginOptions & {
|
||||
serverIslandsState: ServerIslandsState;
|
||||
}): VitePlugin;
|
||||
170
node_modules/astro/dist/core/server-islands/vite-plugin-server-islands.js
generated
vendored
Normal file
170
node_modules/astro/dist/core/server-islands/vite-plugin-server-islands.js
generated
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../constants.js";
|
||||
import { AstroError, AstroErrorData } from "../errors/index.js";
|
||||
const SERVER_ISLAND_MANIFEST = "virtual:astro:server-island-manifest";
|
||||
const RESOLVED_SERVER_ISLAND_MANIFEST = "\0" + SERVER_ISLAND_MANIFEST;
|
||||
const serverIslandPlaceholderMap = "'$$server-islands-map$$'";
|
||||
const serverIslandPlaceholderNameMap = "'$$server-islands-name-map$$'";
|
||||
const SERVER_ISLAND_MAP_MARKER = "$$server-islands-map$$";
|
||||
const serverIslandMapReplaceExp = /['"]\$\$server-islands-map\$\$['"]/g;
|
||||
const serverIslandNameMapReplaceExp = /['"]\$\$server-islands-name-map\$\$['"]/g;
|
||||
function vitePluginServerIslands({
|
||||
settings,
|
||||
serverIslandsState
|
||||
}) {
|
||||
let command = "serve";
|
||||
let serverEnvironments = [];
|
||||
function ensureServerIslandReferenceIds(ctx) {
|
||||
for (const [resolvedPath, island] of serverIslandsState.getDiscoveredIslandEntries()) {
|
||||
if (serverIslandsState.hasReferenceId(resolvedPath)) continue;
|
||||
const referenceId = ctx.emitFile({
|
||||
type: "chunk",
|
||||
id: island.specifier,
|
||||
importer: island.importer,
|
||||
name: island.islandName
|
||||
});
|
||||
serverIslandsState.setReferenceId(resolvedPath, referenceId);
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: "astro:server-islands",
|
||||
enforce: "post",
|
||||
config(_config, { command: _command }) {
|
||||
command = _command;
|
||||
},
|
||||
buildStart() {
|
||||
if (command !== "build" || this.environment?.name !== ASTRO_VITE_ENVIRONMENT_NAMES.ssr) {
|
||||
return;
|
||||
}
|
||||
ensureServerIslandReferenceIds(this);
|
||||
},
|
||||
configureServer(server) {
|
||||
serverEnvironments = [];
|
||||
for (const name of [
|
||||
ASTRO_VITE_ENVIRONMENT_NAMES.ssr,
|
||||
ASTRO_VITE_ENVIRONMENT_NAMES.prerender,
|
||||
ASTRO_VITE_ENVIRONMENT_NAMES.astro
|
||||
]) {
|
||||
const env = server.environments[name];
|
||||
if (env) {
|
||||
serverEnvironments.push(env);
|
||||
}
|
||||
}
|
||||
},
|
||||
resolveId: {
|
||||
filter: {
|
||||
id: new RegExp(`^${SERVER_ISLAND_MANIFEST}$`)
|
||||
},
|
||||
handler() {
|
||||
return RESOLVED_SERVER_ISLAND_MANIFEST;
|
||||
}
|
||||
},
|
||||
load: {
|
||||
filter: {
|
||||
id: new RegExp(`^${RESOLVED_SERVER_ISLAND_MANIFEST}$`)
|
||||
},
|
||||
handler() {
|
||||
return {
|
||||
code: `export const serverIslandMap = ${serverIslandPlaceholderMap};
|
||||
|
||||
export const serverIslandNameMap = ${serverIslandPlaceholderNameMap};`
|
||||
};
|
||||
}
|
||||
},
|
||||
transform: {
|
||||
filter: {
|
||||
id: {
|
||||
include: [/\.(astro|mdx)$/, new RegExp(`^${RESOLVED_SERVER_ISLAND_MANIFEST}$`)]
|
||||
}
|
||||
},
|
||||
async handler(_code, id) {
|
||||
const info = this.getModuleInfo(id);
|
||||
const astro = info ? info.meta.astro : void 0;
|
||||
const isBuildSsr = command === "build" && this.environment?.name === ASTRO_VITE_ENVIRONMENT_NAMES.ssr;
|
||||
if (astro) {
|
||||
for (const comp of astro.serverComponents) {
|
||||
if (!settings.adapter) {
|
||||
throw new AstroError(AstroErrorData.NoAdapterInstalledServerIslands);
|
||||
}
|
||||
const island = serverIslandsState.discover({
|
||||
resolvedPath: comp.resolvedPath,
|
||||
localName: comp.localName,
|
||||
specifier: comp.specifier ?? comp.resolvedPath,
|
||||
importer: id
|
||||
});
|
||||
if (isBuildSsr && !serverIslandsState.hasReferenceId(comp.resolvedPath)) {
|
||||
const referenceId = this.emitFile({
|
||||
type: "chunk",
|
||||
id: island.specifier,
|
||||
importer: island.importer,
|
||||
name: island.islandName
|
||||
});
|
||||
serverIslandsState.setReferenceId(comp.resolvedPath, referenceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (serverIslandsState.hasIslands()) {
|
||||
for (const env of serverEnvironments) {
|
||||
const mod = env.moduleGraph.getModuleById(RESOLVED_SERVER_ISLAND_MANIFEST);
|
||||
if (mod) {
|
||||
env.moduleGraph.invalidateModule(mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (id === RESOLVED_SERVER_ISLAND_MANIFEST) {
|
||||
if (command === "build" && settings.buildOutput) {
|
||||
const hasServerIslands = serverIslandsState.hasIslands();
|
||||
if (hasServerIslands && settings.buildOutput !== "server") {
|
||||
throw new AstroError(AstroErrorData.NoAdapterInstalledServerIslands);
|
||||
}
|
||||
}
|
||||
if (command !== "build" && serverIslandsState.hasIslands()) {
|
||||
const mapSource = serverIslandsState.createImportMapSourceFromDiscovered(
|
||||
(fileName) => fileName
|
||||
);
|
||||
const nameMapSource = serverIslandsState.createNameMapSource();
|
||||
return {
|
||||
code: `
|
||||
export const serverIslandMap = ${mapSource};
|
||||
|
||||
export const serverIslandNameMap = ${nameMapSource};
|
||||
`
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
renderChunk(code, chunk) {
|
||||
if (!code.includes(SERVER_ISLAND_MAP_MARKER)) return;
|
||||
if (command === "build") {
|
||||
const envName = this.environment?.name;
|
||||
let mapSource;
|
||||
if (envName === ASTRO_VITE_ENVIRONMENT_NAMES.ssr) {
|
||||
const isRelativeChunk = !chunk.isEntry;
|
||||
const dots = isRelativeChunk ? ".." : ".";
|
||||
mapSource = serverIslandsState.createImportMapSourceFromReferences(
|
||||
(referenceId) => this.getFileName(referenceId),
|
||||
(fileName) => `${dots}/${fileName}`
|
||||
);
|
||||
} else {
|
||||
mapSource = serverIslandsState.createImportMapSourceFromDiscovered(
|
||||
(fileName) => fileName
|
||||
);
|
||||
}
|
||||
const nameMapSource = serverIslandsState.createNameMapSource();
|
||||
return {
|
||||
code: code.replace(serverIslandMapReplaceExp, mapSource).replace(serverIslandNameMapReplaceExp, nameMapSource),
|
||||
map: null
|
||||
};
|
||||
}
|
||||
return {
|
||||
code: code.replace(serverIslandMapReplaceExp, "new Map();").replace(serverIslandNameMapReplaceExp, "new Map()"),
|
||||
map: null
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
export {
|
||||
SERVER_ISLAND_MANIFEST,
|
||||
SERVER_ISLAND_MAP_MARKER,
|
||||
vitePluginServerIslands
|
||||
};
|
||||
Reference in New Issue
Block a user