Initial commit: New MoreminiMore website with fresh design
This commit is contained in:
2
node_modules/astro/dist/runtime/server/render/any.d.ts
generated
vendored
Normal file
2
node_modules/astro/dist/runtime/server/render/any.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import { type RenderDestination } from './common.js';
|
||||
export declare function renderChild(destination: RenderDestination, child: any): void | Promise<void>;
|
||||
105
node_modules/astro/dist/runtime/server/render/any.js
generated
vendored
Normal file
105
node_modules/astro/dist/runtime/server/render/any.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
import { escapeHTML, isHTMLString, markHTMLString } from "../escape.js";
|
||||
import { isPromise } from "../util.js";
|
||||
import { isAstroComponentInstance, isRenderTemplateResult } from "./astro/index.js";
|
||||
import { isRenderInstance } from "./common.js";
|
||||
import { SlotString } from "./slot.js";
|
||||
import { createBufferedRenderer } from "./util.js";
|
||||
function renderChild(destination, child) {
|
||||
if (typeof child === "string") {
|
||||
destination.write(markHTMLString(escapeHTML(child)));
|
||||
return;
|
||||
}
|
||||
if (isPromise(child)) {
|
||||
return child.then((x) => renderChild(destination, x));
|
||||
}
|
||||
if (child instanceof SlotString) {
|
||||
destination.write(child);
|
||||
return;
|
||||
}
|
||||
if (isHTMLString(child)) {
|
||||
destination.write(child);
|
||||
return;
|
||||
}
|
||||
if (!child && child !== 0) {
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(child)) {
|
||||
return renderArray(destination, child);
|
||||
}
|
||||
if (typeof child === "function") {
|
||||
return renderChild(destination, child());
|
||||
}
|
||||
if (isRenderInstance(child)) {
|
||||
return child.render(destination);
|
||||
}
|
||||
if (isRenderTemplateResult(child)) {
|
||||
return child.render(destination);
|
||||
}
|
||||
if (isAstroComponentInstance(child)) {
|
||||
return child.render(destination);
|
||||
}
|
||||
if (ArrayBuffer.isView(child)) {
|
||||
destination.write(child);
|
||||
return;
|
||||
}
|
||||
if (typeof child === "object" && (Symbol.asyncIterator in child || Symbol.iterator in child)) {
|
||||
if (Symbol.asyncIterator in child) {
|
||||
return renderAsyncIterable(destination, child);
|
||||
}
|
||||
return renderIterable(destination, child);
|
||||
}
|
||||
destination.write(child);
|
||||
}
|
||||
function renderArray(destination, children) {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const result = renderChild(destination, children[i]);
|
||||
if (isPromise(result)) {
|
||||
if (i + 1 >= children.length) {
|
||||
return result;
|
||||
}
|
||||
const remaining = children.length - i - 1;
|
||||
const flushers = new Array(remaining);
|
||||
for (let j = 0; j < remaining; j++) {
|
||||
flushers[j] = createBufferedRenderer(destination, (bufferDestination) => {
|
||||
return renderChild(bufferDestination, children[i + 1 + j]);
|
||||
});
|
||||
}
|
||||
return result.then(() => {
|
||||
let k = 0;
|
||||
const iterate = () => {
|
||||
while (k < flushers.length) {
|
||||
const flushResult = flushers[k++].flush();
|
||||
if (isPromise(flushResult)) {
|
||||
return flushResult.then(iterate);
|
||||
}
|
||||
}
|
||||
};
|
||||
return iterate();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
function renderIterable(destination, children) {
|
||||
const iterator = children[Symbol.iterator]();
|
||||
const iterate = () => {
|
||||
for (; ; ) {
|
||||
const { value, done } = iterator.next();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
const result = renderChild(destination, value);
|
||||
if (isPromise(result)) {
|
||||
return result.then(iterate);
|
||||
}
|
||||
}
|
||||
};
|
||||
return iterate();
|
||||
}
|
||||
async function renderAsyncIterable(destination, children) {
|
||||
for await (const value of children) {
|
||||
await renderChild(destination, value);
|
||||
}
|
||||
}
|
||||
export {
|
||||
renderChild
|
||||
};
|
||||
13
node_modules/astro/dist/runtime/server/render/astro/factory.d.ts
generated
vendored
Normal file
13
node_modules/astro/dist/runtime/server/render/astro/factory.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { PropagationHint, SSRResult } from '../../../../types/public/internal.js';
|
||||
import type { HeadAndContent, ThinHead } from './head-and-content.js';
|
||||
import type { RenderTemplateResult } from './render-template.js';
|
||||
export type AstroFactoryReturnValue = RenderTemplateResult | Response | HeadAndContent | ThinHead;
|
||||
export interface AstroComponentFactory {
|
||||
(result: any, props: any, slots: any): AstroFactoryReturnValue | Promise<AstroFactoryReturnValue>;
|
||||
isAstroComponentFactory?: boolean;
|
||||
moduleId?: string | undefined;
|
||||
propagation?: PropagationHint;
|
||||
}
|
||||
export declare function isAstroComponentFactory(obj: any): obj is AstroComponentFactory;
|
||||
export declare function isAPropagatingComponent(result: SSRResult, factory: AstroComponentFactory): boolean;
|
||||
export declare function getPropagationHint(result: SSRResult, factory: AstroComponentFactory): PropagationHint;
|
||||
18
node_modules/astro/dist/runtime/server/render/astro/factory.js
generated
vendored
Normal file
18
node_modules/astro/dist/runtime/server/render/astro/factory.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import {
|
||||
getPropagationHint as getHint,
|
||||
isPropagatingHint
|
||||
} from "../../../../core/head-propagation/resolver.js";
|
||||
function isAstroComponentFactory(obj) {
|
||||
return obj == null ? false : obj.isAstroComponentFactory === true;
|
||||
}
|
||||
function isAPropagatingComponent(result, factory) {
|
||||
return isPropagatingHint(getPropagationHint(result, factory));
|
||||
}
|
||||
function getPropagationHint(result, factory) {
|
||||
return getHint(result, factory);
|
||||
}
|
||||
export {
|
||||
getPropagationHint,
|
||||
isAPropagatingComponent,
|
||||
isAstroComponentFactory
|
||||
};
|
||||
17
node_modules/astro/dist/runtime/server/render/astro/head-and-content.d.ts
generated
vendored
Normal file
17
node_modules/astro/dist/runtime/server/render/astro/head-and-content.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { RenderTemplateResult } from './render-template.js';
|
||||
declare const headAndContentSym: unique symbol;
|
||||
export type HeadAndContent = {
|
||||
[headAndContentSym]: true;
|
||||
head: string;
|
||||
content: RenderTemplateResult;
|
||||
};
|
||||
/**
|
||||
* A head that doesn't contain any content
|
||||
*/
|
||||
export type ThinHead = {
|
||||
[headAndContentSym]: true;
|
||||
};
|
||||
export declare function isHeadAndContent(obj: unknown): obj is HeadAndContent;
|
||||
export declare function createHeadAndContent(head: string, content: RenderTemplateResult): HeadAndContent;
|
||||
export declare function createThinHead(): ThinHead;
|
||||
export {};
|
||||
21
node_modules/astro/dist/runtime/server/render/astro/head-and-content.js
generated
vendored
Normal file
21
node_modules/astro/dist/runtime/server/render/astro/head-and-content.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
const headAndContentSym = /* @__PURE__ */ Symbol.for("astro.headAndContent");
|
||||
function isHeadAndContent(obj) {
|
||||
return typeof obj === "object" && obj !== null && !!obj[headAndContentSym];
|
||||
}
|
||||
function createHeadAndContent(head, content) {
|
||||
return {
|
||||
[headAndContentSym]: true,
|
||||
head,
|
||||
content
|
||||
};
|
||||
}
|
||||
function createThinHead() {
|
||||
return {
|
||||
[headAndContentSym]: true
|
||||
};
|
||||
}
|
||||
export {
|
||||
createHeadAndContent,
|
||||
createThinHead,
|
||||
isHeadAndContent
|
||||
};
|
||||
7
node_modules/astro/dist/runtime/server/render/astro/index.d.ts
generated
vendored
Normal file
7
node_modules/astro/dist/runtime/server/render/astro/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export type { AstroComponentFactory } from './factory.js';
|
||||
export { isAstroComponentFactory } from './factory.js';
|
||||
export { createHeadAndContent, isHeadAndContent } from './head-and-content.js';
|
||||
export type { AstroComponentInstance } from './instance.js';
|
||||
export { createAstroComponentInstance, isAstroComponentInstance } from './instance.js';
|
||||
export { renderToReadableStream, renderToString } from './render.js';
|
||||
export { isRenderTemplateResult, renderTemplate } from './render-template.js';
|
||||
16
node_modules/astro/dist/runtime/server/render/astro/index.js
generated
vendored
Normal file
16
node_modules/astro/dist/runtime/server/render/astro/index.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { isAstroComponentFactory } from "./factory.js";
|
||||
import { createHeadAndContent, isHeadAndContent } from "./head-and-content.js";
|
||||
import { createAstroComponentInstance, isAstroComponentInstance } from "./instance.js";
|
||||
import { renderToReadableStream, renderToString } from "./render.js";
|
||||
import { isRenderTemplateResult, renderTemplate } from "./render-template.js";
|
||||
export {
|
||||
createAstroComponentInstance,
|
||||
createHeadAndContent,
|
||||
isAstroComponentFactory,
|
||||
isAstroComponentInstance,
|
||||
isHeadAndContent,
|
||||
isRenderTemplateResult,
|
||||
renderTemplate,
|
||||
renderToReadableStream,
|
||||
renderToString
|
||||
};
|
||||
21
node_modules/astro/dist/runtime/server/render/astro/instance.d.ts
generated
vendored
Normal file
21
node_modules/astro/dist/runtime/server/render/astro/instance.d.ts
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { SSRResult } from '../../../../types/public/internal.js';
|
||||
import type { RenderDestination } from '../common.js';
|
||||
import type { ComponentSlots } from '../slot.js';
|
||||
import type { AstroComponentFactory, AstroFactoryReturnValue } from './factory.js';
|
||||
type ComponentProps = Record<string | number, any>;
|
||||
declare const astroComponentInstanceSym: unique symbol;
|
||||
export declare class AstroComponentInstance {
|
||||
[astroComponentInstanceSym]: boolean;
|
||||
private readonly result;
|
||||
private readonly props;
|
||||
private readonly slotValues;
|
||||
private readonly factory;
|
||||
private returnValue;
|
||||
constructor(result: SSRResult, props: ComponentProps, slots: ComponentSlots, factory: AstroComponentFactory);
|
||||
init(result: SSRResult): AstroFactoryReturnValue | Promise<AstroFactoryReturnValue>;
|
||||
render(destination: RenderDestination): void | Promise<void>;
|
||||
private renderImpl;
|
||||
}
|
||||
export declare function createAstroComponentInstance(result: SSRResult, displayName: string, factory: AstroComponentFactory, props: ComponentProps, slots?: any): AstroComponentInstance;
|
||||
export declare function isAstroComponentInstance(obj: unknown): obj is AstroComponentInstance;
|
||||
export {};
|
||||
83
node_modules/astro/dist/runtime/server/render/astro/instance.js
generated
vendored
Normal file
83
node_modules/astro/dist/runtime/server/render/astro/instance.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
import { isPromise } from "../../util.js";
|
||||
import { renderChild } from "../any.js";
|
||||
import { registerIfPropagating } from "../head-propagation/runtime.js";
|
||||
import { isHeadAndContent } from "./head-and-content.js";
|
||||
const astroComponentInstanceSym = /* @__PURE__ */ Symbol.for("astro.componentInstance");
|
||||
class AstroComponentInstance {
|
||||
[astroComponentInstanceSym] = true;
|
||||
result;
|
||||
props;
|
||||
slotValues;
|
||||
factory;
|
||||
returnValue;
|
||||
constructor(result, props, slots, factory) {
|
||||
this.result = result;
|
||||
this.props = props;
|
||||
this.factory = factory;
|
||||
this.slotValues = {};
|
||||
for (const name in slots) {
|
||||
let didRender = false;
|
||||
let value = slots[name](result);
|
||||
this.slotValues[name] = () => {
|
||||
if (!didRender) {
|
||||
didRender = true;
|
||||
return value;
|
||||
}
|
||||
return slots[name](result);
|
||||
};
|
||||
}
|
||||
}
|
||||
init(result) {
|
||||
if (this.returnValue !== void 0) {
|
||||
return this.returnValue;
|
||||
}
|
||||
this.returnValue = this.factory(result, this.props, this.slotValues);
|
||||
if (isPromise(this.returnValue)) {
|
||||
this.returnValue.then((resolved) => {
|
||||
this.returnValue = resolved;
|
||||
}).catch(() => {
|
||||
});
|
||||
}
|
||||
return this.returnValue;
|
||||
}
|
||||
render(destination) {
|
||||
const returnValue = this.init(this.result);
|
||||
if (isPromise(returnValue)) {
|
||||
return returnValue.then((x) => this.renderImpl(destination, x));
|
||||
}
|
||||
return this.renderImpl(destination, returnValue);
|
||||
}
|
||||
renderImpl(destination, returnValue) {
|
||||
if (isHeadAndContent(returnValue)) {
|
||||
return returnValue.content.render(destination);
|
||||
} else {
|
||||
return renderChild(destination, returnValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
function validateComponentProps(props, clientDirectives, displayName) {
|
||||
if (props != null) {
|
||||
const directives = [...clientDirectives.keys()].map((directive) => `client:${directive}`);
|
||||
for (const prop of Object.keys(props)) {
|
||||
if (directives.includes(prop)) {
|
||||
console.warn(
|
||||
`You are attempting to render <${displayName} ${prop} />, but ${displayName} is an Astro component. Astro components do not render in the client and should not have a hydration directive. Please use a framework component for client rendering.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function createAstroComponentInstance(result, displayName, factory, props, slots = {}) {
|
||||
validateComponentProps(props, result.clientDirectives, displayName);
|
||||
const instance = new AstroComponentInstance(result, props, slots, factory);
|
||||
registerIfPropagating(result, factory, instance);
|
||||
return instance;
|
||||
}
|
||||
function isAstroComponentInstance(obj) {
|
||||
return typeof obj === "object" && obj !== null && !!obj[astroComponentInstanceSym];
|
||||
}
|
||||
export {
|
||||
AstroComponentInstance,
|
||||
createAstroComponentInstance,
|
||||
isAstroComponentInstance
|
||||
};
|
||||
13
node_modules/astro/dist/runtime/server/render/astro/render-template.d.ts
generated
vendored
Normal file
13
node_modules/astro/dist/runtime/server/render/astro/render-template.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { RenderDestination } from '../common.js';
|
||||
declare const renderTemplateResultSym: unique symbol;
|
||||
export declare class RenderTemplateResult {
|
||||
[renderTemplateResultSym]: boolean;
|
||||
private htmlParts;
|
||||
expressions: any[];
|
||||
private error;
|
||||
constructor(htmlParts: TemplateStringsArray, expressions: unknown[]);
|
||||
render(destination: RenderDestination): void | Promise<void>;
|
||||
}
|
||||
export declare function isRenderTemplateResult(obj: unknown): obj is RenderTemplateResult;
|
||||
export declare function renderTemplate(htmlParts: TemplateStringsArray, ...expressions: any[]): RenderTemplateResult;
|
||||
export {};
|
||||
83
node_modules/astro/dist/runtime/server/render/astro/render-template.js
generated
vendored
Normal file
83
node_modules/astro/dist/runtime/server/render/astro/render-template.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
import { markHTMLString } from "../../escape.js";
|
||||
import { isPromise } from "../../util.js";
|
||||
import { renderChild } from "../any.js";
|
||||
import { createBufferedRenderer } from "../util.js";
|
||||
const renderTemplateResultSym = /* @__PURE__ */ Symbol.for("astro.renderTemplateResult");
|
||||
class RenderTemplateResult {
|
||||
[renderTemplateResultSym] = true;
|
||||
htmlParts;
|
||||
expressions;
|
||||
error;
|
||||
constructor(htmlParts, expressions) {
|
||||
this.htmlParts = htmlParts;
|
||||
this.error = void 0;
|
||||
this.expressions = expressions.map((expression) => {
|
||||
if (isPromise(expression)) {
|
||||
return Promise.resolve(expression).catch((err) => {
|
||||
if (!this.error) {
|
||||
this.error = err;
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
||||
return expression;
|
||||
});
|
||||
}
|
||||
render(destination) {
|
||||
const { htmlParts, expressions } = this;
|
||||
for (let i = 0; i < htmlParts.length; i++) {
|
||||
const html = htmlParts[i];
|
||||
if (html) {
|
||||
destination.write(markHTMLString(html));
|
||||
}
|
||||
if (i >= expressions.length) break;
|
||||
const exp = expressions[i];
|
||||
if (!(exp || exp === 0)) continue;
|
||||
const result = renderChild(destination, exp);
|
||||
if (isPromise(result)) {
|
||||
const startIdx = i + 1;
|
||||
const remaining = expressions.length - startIdx;
|
||||
const flushers = new Array(remaining);
|
||||
for (let j = 0; j < remaining; j++) {
|
||||
const rExp = expressions[startIdx + j];
|
||||
flushers[j] = createBufferedRenderer(destination, (bufferDestination) => {
|
||||
if (rExp || rExp === 0) {
|
||||
return renderChild(bufferDestination, rExp);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result.then(() => {
|
||||
let k = 0;
|
||||
const iterate = () => {
|
||||
while (k < flushers.length) {
|
||||
const rHtml = htmlParts[startIdx + k];
|
||||
if (rHtml) {
|
||||
destination.write(markHTMLString(rHtml));
|
||||
}
|
||||
const flushResult = flushers[k++].flush();
|
||||
if (isPromise(flushResult)) {
|
||||
return flushResult.then(iterate);
|
||||
}
|
||||
}
|
||||
const lastHtml = htmlParts[htmlParts.length - 1];
|
||||
if (lastHtml) {
|
||||
destination.write(markHTMLString(lastHtml));
|
||||
}
|
||||
};
|
||||
return iterate();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function isRenderTemplateResult(obj) {
|
||||
return typeof obj === "object" && obj !== null && !!obj[renderTemplateResultSym];
|
||||
}
|
||||
function renderTemplate(htmlParts, ...expressions) {
|
||||
return new RenderTemplateResult(htmlParts, expressions);
|
||||
}
|
||||
export {
|
||||
RenderTemplateResult,
|
||||
isRenderTemplateResult,
|
||||
renderTemplate
|
||||
};
|
||||
10
node_modules/astro/dist/runtime/server/render/astro/render.d.ts
generated
vendored
Normal file
10
node_modules/astro/dist/runtime/server/render/astro/render.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { RouteData, SSRResult } from '../../../../types/public/internal.js';
|
||||
import type { AstroComponentFactory } from './factory.js';
|
||||
/**
|
||||
* Queue-based rendering to AsyncIterable
|
||||
* NOTE: Currently disabled for .astro files. Kept for potential future use.
|
||||
*/
|
||||
export declare function renderToString(result: SSRResult, componentFactory: AstroComponentFactory, props: any, children: any, isPage?: boolean, route?: RouteData): Promise<string | Response>;
|
||||
export declare function renderToReadableStream(result: SSRResult, componentFactory: AstroComponentFactory, props: any, children: any, isPage?: boolean, route?: RouteData): Promise<ReadableStream | Response>;
|
||||
export declare function bufferHeadContent(result: SSRResult): Promise<void>;
|
||||
export declare function renderToAsyncIterable(result: SSRResult, componentFactory: AstroComponentFactory, props: any, children: any, isPage?: boolean, route?: RouteData): Promise<AsyncIterable<Uint8Array> | Response>;
|
||||
250
node_modules/astro/dist/runtime/server/render/astro/render.js
generated
vendored
Normal file
250
node_modules/astro/dist/runtime/server/render/astro/render.js
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
import { AstroError, AstroErrorData } from "../../../../core/errors/index.js";
|
||||
import { isPromise } from "../../util.js";
|
||||
import {
|
||||
chunkToByteArray,
|
||||
chunkToByteArrayOrString,
|
||||
chunkToString,
|
||||
encoder
|
||||
} from "../common.js";
|
||||
import { promiseWithResolvers } from "../util.js";
|
||||
import { bufferPropagatedHead } from "../head-propagation/runtime.js";
|
||||
import { isHeadAndContent } from "./head-and-content.js";
|
||||
import { isRenderTemplateResult } from "./render-template.js";
|
||||
const DOCTYPE_EXP = /<!doctype html/i;
|
||||
async function renderToString(result, componentFactory, props, children, isPage = false, route) {
|
||||
const templateResult = await callComponentAsTemplateResultOrResponse(
|
||||
result,
|
||||
componentFactory,
|
||||
props,
|
||||
children,
|
||||
route
|
||||
);
|
||||
if (templateResult instanceof Response) return templateResult;
|
||||
let str = "";
|
||||
let renderedFirstPageChunk = false;
|
||||
if (isPage) {
|
||||
await bufferHeadContent(result);
|
||||
}
|
||||
const destination = {
|
||||
write(chunk) {
|
||||
if (isPage && !renderedFirstPageChunk) {
|
||||
renderedFirstPageChunk = true;
|
||||
if (!result.partial && !DOCTYPE_EXP.test(String(chunk))) {
|
||||
const doctype = result.compressHTML ? "<!DOCTYPE html>" : "<!DOCTYPE html>\n";
|
||||
str += doctype;
|
||||
}
|
||||
}
|
||||
if (chunk instanceof Response) return;
|
||||
str += chunkToString(result, chunk);
|
||||
}
|
||||
};
|
||||
await templateResult.render(destination);
|
||||
return str;
|
||||
}
|
||||
async function renderToReadableStream(result, componentFactory, props, children, isPage = false, route) {
|
||||
const templateResult = await callComponentAsTemplateResultOrResponse(
|
||||
result,
|
||||
componentFactory,
|
||||
props,
|
||||
children,
|
||||
route
|
||||
);
|
||||
if (templateResult instanceof Response) return templateResult;
|
||||
let renderedFirstPageChunk = false;
|
||||
if (isPage) {
|
||||
await bufferHeadContent(result);
|
||||
}
|
||||
return new ReadableStream({
|
||||
start(controller) {
|
||||
const destination = {
|
||||
write(chunk) {
|
||||
if (isPage && !renderedFirstPageChunk) {
|
||||
renderedFirstPageChunk = true;
|
||||
if (!result.partial && !DOCTYPE_EXP.test(String(chunk))) {
|
||||
const doctype = result.compressHTML ? "<!DOCTYPE html>" : "<!DOCTYPE html>\n";
|
||||
controller.enqueue(encoder.encode(doctype));
|
||||
}
|
||||
}
|
||||
if (chunk instanceof Response) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.ResponseSentError
|
||||
});
|
||||
}
|
||||
const bytes = chunkToByteArray(result, chunk);
|
||||
controller.enqueue(bytes);
|
||||
}
|
||||
};
|
||||
(async () => {
|
||||
try {
|
||||
await templateResult.render(destination);
|
||||
controller.close();
|
||||
} catch (e) {
|
||||
if (AstroError.is(e) && !e.loc) {
|
||||
e.setLocation({
|
||||
file: route?.component
|
||||
});
|
||||
}
|
||||
setTimeout(() => controller.error(e), 0);
|
||||
}
|
||||
})();
|
||||
},
|
||||
cancel() {
|
||||
result.cancelled = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
async function callComponentAsTemplateResultOrResponse(result, componentFactory, props, children, route) {
|
||||
const factoryResult = await componentFactory(result, props, children);
|
||||
if (factoryResult instanceof Response) {
|
||||
return factoryResult;
|
||||
} else if (isHeadAndContent(factoryResult)) {
|
||||
if (!isRenderTemplateResult(factoryResult.content)) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.OnlyResponseCanBeReturned,
|
||||
message: AstroErrorData.OnlyResponseCanBeReturned.message(
|
||||
route?.route,
|
||||
typeof factoryResult
|
||||
),
|
||||
location: {
|
||||
file: route?.component
|
||||
}
|
||||
});
|
||||
}
|
||||
return factoryResult.content;
|
||||
} else if (!isRenderTemplateResult(factoryResult)) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.OnlyResponseCanBeReturned,
|
||||
message: AstroErrorData.OnlyResponseCanBeReturned.message(route?.route, typeof factoryResult),
|
||||
location: {
|
||||
file: route?.component
|
||||
}
|
||||
});
|
||||
}
|
||||
return factoryResult;
|
||||
}
|
||||
async function bufferHeadContent(result) {
|
||||
await bufferPropagatedHead(result);
|
||||
}
|
||||
async function renderToAsyncIterable(result, componentFactory, props, children, isPage = false, route) {
|
||||
const templateResult = await callComponentAsTemplateResultOrResponse(
|
||||
result,
|
||||
componentFactory,
|
||||
props,
|
||||
children,
|
||||
route
|
||||
);
|
||||
if (templateResult instanceof Response) return templateResult;
|
||||
let renderedFirstPageChunk = false;
|
||||
if (isPage) {
|
||||
await bufferHeadContent(result);
|
||||
}
|
||||
let error = null;
|
||||
let next = null;
|
||||
const buffer = [];
|
||||
let renderingComplete = false;
|
||||
const iterator = {
|
||||
async next() {
|
||||
if (result.cancelled) return { done: true, value: void 0 };
|
||||
if (next !== null) {
|
||||
await next.promise;
|
||||
} else if (!renderingComplete && !buffer.length) {
|
||||
next = promiseWithResolvers();
|
||||
await next.promise;
|
||||
}
|
||||
if (!renderingComplete) {
|
||||
next = promiseWithResolvers();
|
||||
}
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
let length = 0;
|
||||
let stringToEncode = "";
|
||||
for (let i = 0, len = buffer.length; i < len; i++) {
|
||||
const bufferEntry = buffer[i];
|
||||
if (typeof bufferEntry === "string") {
|
||||
const nextIsString = i + 1 < len && typeof buffer[i + 1] === "string";
|
||||
stringToEncode += bufferEntry;
|
||||
if (!nextIsString) {
|
||||
const encoded = encoder.encode(stringToEncode);
|
||||
length += encoded.length;
|
||||
stringToEncode = "";
|
||||
buffer[i] = encoded;
|
||||
} else {
|
||||
buffer[i] = "";
|
||||
}
|
||||
} else {
|
||||
length += bufferEntry.length;
|
||||
}
|
||||
}
|
||||
let mergedArray = new Uint8Array(length);
|
||||
let offset = 0;
|
||||
for (let i = 0, len = buffer.length; i < len; i++) {
|
||||
const item = buffer[i];
|
||||
if (item === "") {
|
||||
continue;
|
||||
}
|
||||
mergedArray.set(item, offset);
|
||||
offset += item.length;
|
||||
}
|
||||
buffer.length = 0;
|
||||
const returnValue = {
|
||||
// The iterator is done when rendering has finished
|
||||
// and there are no more chunks to return.
|
||||
done: length === 0 && renderingComplete,
|
||||
value: mergedArray
|
||||
};
|
||||
return returnValue;
|
||||
},
|
||||
async return() {
|
||||
result.cancelled = true;
|
||||
return { done: true, value: void 0 };
|
||||
}
|
||||
};
|
||||
const destination = {
|
||||
write(chunk) {
|
||||
if (isPage && !renderedFirstPageChunk) {
|
||||
renderedFirstPageChunk = true;
|
||||
if (!result.partial && !DOCTYPE_EXP.test(String(chunk))) {
|
||||
const doctype = result.compressHTML ? "<!DOCTYPE html>" : "<!DOCTYPE html>\n";
|
||||
buffer.push(encoder.encode(doctype));
|
||||
}
|
||||
}
|
||||
if (chunk instanceof Response) {
|
||||
throw new AstroError(AstroErrorData.ResponseSentError);
|
||||
}
|
||||
const bytes = chunkToByteArrayOrString(result, chunk);
|
||||
if (bytes.length > 0) {
|
||||
buffer.push(bytes);
|
||||
next?.resolve();
|
||||
} else if (buffer.length > 0) {
|
||||
next?.resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
const renderResult = toPromise(() => templateResult.render(destination));
|
||||
renderResult.catch((err) => {
|
||||
error = err;
|
||||
}).finally(() => {
|
||||
renderingComplete = true;
|
||||
next?.resolve();
|
||||
});
|
||||
return {
|
||||
[Symbol.asyncIterator]() {
|
||||
return iterator;
|
||||
}
|
||||
};
|
||||
}
|
||||
function toPromise(fn) {
|
||||
try {
|
||||
const result = fn();
|
||||
return isPromise(result) ? result : Promise.resolve(result);
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
export {
|
||||
bufferHeadContent,
|
||||
renderToAsyncIterable,
|
||||
renderToReadableStream,
|
||||
renderToString
|
||||
};
|
||||
31
node_modules/astro/dist/runtime/server/render/common.d.ts
generated
vendored
Normal file
31
node_modules/astro/dist/runtime/server/render/common.d.ts
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { SSRResult } from '../../../types/public/internal.js';
|
||||
import type { HTMLBytes, HTMLString } from '../escape.js';
|
||||
import type { RenderInstruction } from './instruction.js';
|
||||
import { type SlotString } from './slot.js';
|
||||
/**
|
||||
* Possible chunk types to be written to the destination, and it'll
|
||||
* handle stringifying them at the end.
|
||||
*
|
||||
* NOTE: Try to reduce adding new types here. If possible, serialize
|
||||
* the custom types to a string in `renderChild` in `any.ts`.
|
||||
*/
|
||||
export type RenderDestinationChunk = string | HTMLBytes | HTMLString | SlotString | ArrayBufferView | RenderInstruction | Response;
|
||||
export interface RenderDestination {
|
||||
/**
|
||||
* Any rendering logic should call this to construct the HTML output.
|
||||
* See the `chunk` parameter for possible writable values.
|
||||
*/
|
||||
write(chunk: RenderDestinationChunk): void;
|
||||
}
|
||||
export interface RenderInstance {
|
||||
render: RenderFunction;
|
||||
}
|
||||
export type RenderFunction = (destination: RenderDestination) => Promise<void> | void;
|
||||
export declare const Fragment: unique symbol;
|
||||
export declare const Renderer: unique symbol;
|
||||
export declare const encoder: TextEncoder;
|
||||
export declare const decoder: TextDecoder;
|
||||
export declare function chunkToString(result: SSRResult, chunk: Exclude<RenderDestinationChunk, Response>): string;
|
||||
export declare function chunkToByteArray(result: SSRResult, chunk: Exclude<RenderDestinationChunk, Response>): Uint8Array;
|
||||
export declare function chunkToByteArrayOrString(result: SSRResult, chunk: Exclude<RenderDestinationChunk, Response>): Uint8Array | string;
|
||||
export declare function isRenderInstance(obj: unknown): obj is RenderInstance;
|
||||
123
node_modules/astro/dist/runtime/server/render/common.js
generated
vendored
Normal file
123
node_modules/astro/dist/runtime/server/render/common.js
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
import { markHTMLString } from "../escape.js";
|
||||
import {
|
||||
determineIfNeedsHydrationScript,
|
||||
determinesIfNeedsDirectiveScript,
|
||||
getPrescripts
|
||||
} from "../scripts.js";
|
||||
import { getInstructionRenderState, shouldRenderInstruction } from "./head-propagation/runtime.js";
|
||||
import { renderAllHeadContent } from "./head.js";
|
||||
import { isRenderInstruction } from "./instruction.js";
|
||||
import { renderServerIslandRuntime } from "./server-islands.js";
|
||||
import { isSlotString } from "./slot.js";
|
||||
const Fragment = /* @__PURE__ */ Symbol.for("astro:fragment");
|
||||
const Renderer = /* @__PURE__ */ Symbol.for("astro:renderer");
|
||||
const encoder = new TextEncoder();
|
||||
const decoder = new TextDecoder();
|
||||
function stringifyChunk(result, chunk) {
|
||||
if (isRenderInstruction(chunk)) {
|
||||
const instruction = chunk;
|
||||
switch (instruction.type) {
|
||||
case "directive": {
|
||||
const { hydration } = instruction;
|
||||
let needsHydrationScript = hydration && determineIfNeedsHydrationScript(result);
|
||||
let needsDirectiveScript = hydration && determinesIfNeedsDirectiveScript(result, hydration.directive);
|
||||
if (needsHydrationScript) {
|
||||
let prescripts = getPrescripts(result, "both", hydration.directive);
|
||||
return markHTMLString(prescripts);
|
||||
} else if (needsDirectiveScript) {
|
||||
let prescripts = getPrescripts(result, "directive", hydration.directive);
|
||||
return markHTMLString(prescripts);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
case "head": {
|
||||
if (!shouldRenderInstruction("head", getInstructionRenderState(result))) {
|
||||
return "";
|
||||
}
|
||||
return renderAllHeadContent(result);
|
||||
}
|
||||
case "maybe-head": {
|
||||
if (!shouldRenderInstruction("maybe-head", getInstructionRenderState(result))) {
|
||||
return "";
|
||||
}
|
||||
return renderAllHeadContent(result);
|
||||
}
|
||||
case "renderer-hydration-script": {
|
||||
const { rendererSpecificHydrationScripts } = result._metadata;
|
||||
const { rendererName } = instruction;
|
||||
if (!rendererSpecificHydrationScripts.has(rendererName)) {
|
||||
rendererSpecificHydrationScripts.add(rendererName);
|
||||
return instruction.render();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
case "server-island-runtime": {
|
||||
if (result._metadata.hasRenderedServerIslandRuntime) {
|
||||
return "";
|
||||
}
|
||||
result._metadata.hasRenderedServerIslandRuntime = true;
|
||||
return renderServerIslandRuntime();
|
||||
}
|
||||
case "script": {
|
||||
const { id, content } = instruction;
|
||||
if (result._metadata.renderedScripts.has(id)) {
|
||||
return "";
|
||||
}
|
||||
result._metadata.renderedScripts.add(id);
|
||||
return content;
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unknown chunk type: ${chunk.type}`);
|
||||
}
|
||||
}
|
||||
} else if (chunk instanceof Response) {
|
||||
return "";
|
||||
} else if (isSlotString(chunk)) {
|
||||
let out = "";
|
||||
const c = chunk;
|
||||
if (c.instructions) {
|
||||
for (const instr of c.instructions) {
|
||||
out += stringifyChunk(result, instr);
|
||||
}
|
||||
}
|
||||
out += chunk.toString();
|
||||
return out;
|
||||
}
|
||||
return chunk.toString();
|
||||
}
|
||||
function chunkToString(result, chunk) {
|
||||
if (ArrayBuffer.isView(chunk)) {
|
||||
return decoder.decode(chunk);
|
||||
} else {
|
||||
return stringifyChunk(result, chunk);
|
||||
}
|
||||
}
|
||||
function chunkToByteArray(result, chunk) {
|
||||
if (ArrayBuffer.isView(chunk)) {
|
||||
return chunk;
|
||||
} else {
|
||||
const stringified = stringifyChunk(result, chunk);
|
||||
return encoder.encode(stringified.toString());
|
||||
}
|
||||
}
|
||||
function chunkToByteArrayOrString(result, chunk) {
|
||||
if (ArrayBuffer.isView(chunk)) {
|
||||
return chunk;
|
||||
} else {
|
||||
return stringifyChunk(result, chunk).toString();
|
||||
}
|
||||
}
|
||||
function isRenderInstance(obj) {
|
||||
return !!obj && typeof obj === "object" && "render" in obj && typeof obj.render === "function";
|
||||
}
|
||||
export {
|
||||
Fragment,
|
||||
Renderer,
|
||||
chunkToByteArray,
|
||||
chunkToByteArrayOrString,
|
||||
chunkToString,
|
||||
decoder,
|
||||
encoder,
|
||||
isRenderInstance
|
||||
};
|
||||
11
node_modules/astro/dist/runtime/server/render/component.d.ts
generated
vendored
Normal file
11
node_modules/astro/dist/runtime/server/render/component.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { RouteData, SSRResult } from '../../../types/public/internal.js';
|
||||
import { type RenderInstance } from './common.js';
|
||||
import { type ComponentSlots } from './slot.js';
|
||||
declare const needsHeadRenderingSymbol: unique symbol;
|
||||
export declare function renderComponent(result: SSRResult, displayName: string, Component: unknown, props: Record<string | number, any>, slots?: ComponentSlots): RenderInstance | Promise<RenderInstance>;
|
||||
export declare function renderComponentToString(result: SSRResult, displayName: string, Component: unknown, props: Record<string | number, any>, slots?: any, isPage?: boolean, route?: RouteData): Promise<string>;
|
||||
export type NonAstroPageComponent = {
|
||||
name: string;
|
||||
[needsHeadRenderingSymbol]: boolean;
|
||||
};
|
||||
export {};
|
||||
447
node_modules/astro/dist/runtime/server/render/component.js
generated
vendored
Normal file
447
node_modules/astro/dist/runtime/server/render/component.js
generated
vendored
Normal file
@@ -0,0 +1,447 @@
|
||||
import { clsx } from "clsx";
|
||||
import { AstroError, AstroErrorData } from "../../../core/errors/index.js";
|
||||
import { markHTMLString } from "../escape.js";
|
||||
import { extractDirectives, generateHydrateScript } from "../hydration.js";
|
||||
import { serializeProps } from "../serialize.js";
|
||||
import { shorthash } from "../shorthash.js";
|
||||
import { isPromise } from "../util.js";
|
||||
import { isAstroComponentFactory } from "./astro/factory.js";
|
||||
import { renderTemplate } from "./astro/index.js";
|
||||
import { createAstroComponentInstance } from "./astro/instance.js";
|
||||
import { bufferHeadContent } from "./astro/render.js";
|
||||
import {
|
||||
chunkToString,
|
||||
Fragment,
|
||||
Renderer
|
||||
} from "./common.js";
|
||||
import { componentIsHTMLElement, renderHTMLElement } from "./dom.js";
|
||||
import { maybeRenderHead } from "./head.js";
|
||||
import { createRenderInstruction } from "./instruction.js";
|
||||
import { containsServerDirective, ServerIslandComponent } from "./server-islands.js";
|
||||
import { renderSlot, renderSlots, renderSlotToString } from "./slot.js";
|
||||
import { formatList, internalSpreadAttributes, renderElement, voidElementNames } from "./util.js";
|
||||
const needsHeadRenderingSymbol = /* @__PURE__ */ Symbol.for("astro.needsHeadRendering");
|
||||
const rendererAliases = /* @__PURE__ */ new Map([["solid", "solid-js"]]);
|
||||
const clientOnlyValues = /* @__PURE__ */ new Set(["solid-js", "react", "preact", "vue", "svelte"]);
|
||||
function guessRenderers(componentUrl) {
|
||||
const extname = componentUrl?.split(".").pop();
|
||||
switch (extname) {
|
||||
case "svelte":
|
||||
return ["@astrojs/svelte"];
|
||||
case "vue":
|
||||
return ["@astrojs/vue"];
|
||||
case "jsx":
|
||||
case "tsx":
|
||||
return ["@astrojs/react", "@astrojs/preact", "@astrojs/solid-js", "@astrojs/vue (jsx)"];
|
||||
case void 0:
|
||||
default:
|
||||
return [
|
||||
"@astrojs/react",
|
||||
"@astrojs/preact",
|
||||
"@astrojs/solid-js",
|
||||
"@astrojs/vue",
|
||||
"@astrojs/svelte"
|
||||
];
|
||||
}
|
||||
}
|
||||
function isFragmentComponent(Component) {
|
||||
return Component === Fragment;
|
||||
}
|
||||
function isHTMLComponent(Component) {
|
||||
return Component && Component["astro:html"] === true;
|
||||
}
|
||||
const ASTRO_SLOT_EXP = /<\/?astro-slot\b[^>]*>/g;
|
||||
const ASTRO_STATIC_SLOT_EXP = /<\/?astro-static-slot\b[^>]*>/g;
|
||||
function removeStaticAstroSlot(html, supportsAstroStaticSlot = true) {
|
||||
const exp = supportsAstroStaticSlot ? ASTRO_STATIC_SLOT_EXP : ASTRO_SLOT_EXP;
|
||||
return html.replace(exp, "");
|
||||
}
|
||||
async function renderFrameworkComponent(result, displayName, Component, _props, slots = {}) {
|
||||
if (!Component && "client:only" in _props === false) {
|
||||
throw new Error(
|
||||
`Unable to render ${displayName} because it is ${Component}!
|
||||
Did you forget to import the component or is it possible there is a typo?`
|
||||
);
|
||||
}
|
||||
const { renderers, clientDirectives } = result;
|
||||
const metadata = {
|
||||
astroStaticSlot: true,
|
||||
displayName
|
||||
};
|
||||
const { hydration, isPage, props, propsWithoutTransitionAttributes } = extractDirectives(
|
||||
_props,
|
||||
clientDirectives
|
||||
);
|
||||
let html = "";
|
||||
let attrs = void 0;
|
||||
if (hydration) {
|
||||
metadata.hydrate = hydration.directive;
|
||||
metadata.hydrateArgs = hydration.value;
|
||||
metadata.componentExport = hydration.componentExport;
|
||||
metadata.componentUrl = hydration.componentUrl;
|
||||
}
|
||||
const probableRendererNames = guessRenderers(metadata.componentUrl);
|
||||
const validRenderers = renderers.filter((r) => r.name !== "astro:jsx");
|
||||
const { children, slotInstructions } = await renderSlots(result, slots);
|
||||
let renderer;
|
||||
if (metadata.hydrate !== "only") {
|
||||
let isTagged = false;
|
||||
try {
|
||||
isTagged = Component && Component[Renderer];
|
||||
} catch {
|
||||
}
|
||||
if (isTagged) {
|
||||
const rendererName = Component[Renderer];
|
||||
renderer = renderers.find(({ name }) => name === rendererName);
|
||||
}
|
||||
if (!renderer) {
|
||||
let error;
|
||||
for (const r of renderers) {
|
||||
try {
|
||||
if (await r.ssr.check.call({ result }, Component, props, children, metadata)) {
|
||||
renderer = r;
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
error ??= e;
|
||||
}
|
||||
}
|
||||
if (!renderer && error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
if (!renderer && typeof HTMLElement === "function" && componentIsHTMLElement(Component)) {
|
||||
const output = await renderHTMLElement(
|
||||
result,
|
||||
Component,
|
||||
_props,
|
||||
slots
|
||||
);
|
||||
return {
|
||||
render(destination) {
|
||||
destination.write(output);
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (metadata.hydrateArgs) {
|
||||
const rendererName = rendererAliases.has(metadata.hydrateArgs) ? rendererAliases.get(metadata.hydrateArgs) : metadata.hydrateArgs;
|
||||
if (clientOnlyValues.has(rendererName)) {
|
||||
renderer = renderers.find(
|
||||
({ name }) => name === `@astrojs/${rendererName}` || name === rendererName
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!renderer && validRenderers.length === 1) {
|
||||
renderer = validRenderers[0];
|
||||
}
|
||||
if (!renderer) {
|
||||
const extname = metadata.componentUrl?.split(".").pop();
|
||||
renderer = renderers.find(({ name }) => name === `@astrojs/${extname}` || name === extname);
|
||||
}
|
||||
if (!renderer && metadata.hydrateArgs) {
|
||||
const rendererName = metadata.hydrateArgs;
|
||||
if (typeof rendererName === "string") {
|
||||
renderer = renderers.find(({ name }) => name === rendererName);
|
||||
}
|
||||
}
|
||||
}
|
||||
let componentServerRenderEndTime;
|
||||
if (!renderer) {
|
||||
if (metadata.hydrate === "only") {
|
||||
const rendererName = rendererAliases.has(metadata.hydrateArgs) ? rendererAliases.get(metadata.hydrateArgs) : metadata.hydrateArgs;
|
||||
if (clientOnlyValues.has(rendererName)) {
|
||||
const plural = validRenderers.length > 1;
|
||||
throw new AstroError({
|
||||
...AstroErrorData.NoMatchingRenderer,
|
||||
message: AstroErrorData.NoMatchingRenderer.message(
|
||||
metadata.displayName,
|
||||
metadata?.componentUrl?.split(".").pop(),
|
||||
plural,
|
||||
validRenderers.length
|
||||
),
|
||||
hint: AstroErrorData.NoMatchingRenderer.hint(
|
||||
formatList(probableRendererNames.map((r) => "`" + r + "`"))
|
||||
)
|
||||
});
|
||||
} else {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.NoClientOnlyHint,
|
||||
message: AstroErrorData.NoClientOnlyHint.message(metadata.displayName),
|
||||
hint: AstroErrorData.NoClientOnlyHint.hint(
|
||||
probableRendererNames.map((r) => r.replace("@astrojs/", "")).join("|")
|
||||
)
|
||||
});
|
||||
}
|
||||
} else if (typeof Component !== "string") {
|
||||
const matchingRenderers = validRenderers.filter(
|
||||
(r) => probableRendererNames.includes(r.name)
|
||||
);
|
||||
const plural = validRenderers.length > 1;
|
||||
if (matchingRenderers.length === 0) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.NoMatchingRenderer,
|
||||
message: AstroErrorData.NoMatchingRenderer.message(
|
||||
metadata.displayName,
|
||||
metadata?.componentUrl?.split(".").pop(),
|
||||
plural,
|
||||
validRenderers.length
|
||||
),
|
||||
hint: AstroErrorData.NoMatchingRenderer.hint(
|
||||
formatList(probableRendererNames.map((r) => "`" + r + "`"))
|
||||
)
|
||||
});
|
||||
} else if (matchingRenderers.length === 1) {
|
||||
renderer = matchingRenderers[0];
|
||||
({ html, attrs } = await renderer.ssr.renderToStaticMarkup.call(
|
||||
{ result },
|
||||
Component,
|
||||
propsWithoutTransitionAttributes,
|
||||
children,
|
||||
metadata
|
||||
));
|
||||
} else {
|
||||
throw new Error(`Unable to render ${metadata.displayName}!
|
||||
|
||||
This component likely uses ${formatList(probableRendererNames)},
|
||||
but Astro encountered an error during server-side rendering.
|
||||
|
||||
Please ensure that ${metadata.displayName}:
|
||||
1. Does not unconditionally access browser-specific globals like \`window\` or \`document\`.
|
||||
If this is unavoidable, use the \`client:only\` hydration directive.
|
||||
2. Does not conditionally return \`null\` or \`undefined\` when rendered on the server.
|
||||
3. If using multiple JSX frameworks at the same time (e.g. React + Preact), pass the correct \`include\`/\`exclude\` options to integrations.
|
||||
|
||||
If you're still stuck, please open an issue on GitHub or join us at https://astro.build/chat.`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (metadata.hydrate === "only") {
|
||||
html = await renderSlotToString(result, slots?.fallback);
|
||||
} else {
|
||||
const componentRenderStartTime = performance.now();
|
||||
({ html, attrs } = await renderer.ssr.renderToStaticMarkup.call(
|
||||
{ result },
|
||||
Component,
|
||||
propsWithoutTransitionAttributes,
|
||||
children,
|
||||
metadata
|
||||
));
|
||||
if (process.env.NODE_ENV === "development")
|
||||
componentServerRenderEndTime = performance.now() - componentRenderStartTime;
|
||||
}
|
||||
}
|
||||
if (!html && typeof Component === "string") {
|
||||
const Tag = sanitizeElementName(Component);
|
||||
const childSlots = Object.values(children).join("");
|
||||
const renderTemplateResult = renderTemplate`<${Tag}${internalSpreadAttributes(
|
||||
props,
|
||||
true,
|
||||
Tag
|
||||
)}${markHTMLString(
|
||||
childSlots === "" && voidElementNames.test(Tag) ? `/>` : `>${childSlots}</${Tag}>`
|
||||
)}`;
|
||||
html = "";
|
||||
const destination = {
|
||||
write(chunk) {
|
||||
if (chunk instanceof Response) return;
|
||||
html += chunkToString(result, chunk);
|
||||
}
|
||||
};
|
||||
await renderTemplateResult.render(destination);
|
||||
}
|
||||
if (!hydration) {
|
||||
return {
|
||||
render(destination) {
|
||||
if (slotInstructions) {
|
||||
for (const instruction of slotInstructions) {
|
||||
destination.write(instruction);
|
||||
}
|
||||
}
|
||||
if (isPage || renderer?.name === "astro:jsx") {
|
||||
destination.write(html);
|
||||
} else if (html && html.length > 0) {
|
||||
destination.write(
|
||||
markHTMLString(removeStaticAstroSlot(html, renderer?.ssr?.supportsAstroStaticSlot))
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
const astroId = shorthash(
|
||||
`<!--${metadata.componentExport.value}:${metadata.componentUrl}-->
|
||||
${html}
|
||||
${serializeProps(
|
||||
props,
|
||||
metadata
|
||||
)}`
|
||||
);
|
||||
const island = await generateHydrateScript(
|
||||
{ renderer, result, astroId, props, attrs },
|
||||
metadata
|
||||
);
|
||||
if (componentServerRenderEndTime && process.env.NODE_ENV === "development")
|
||||
island.props["server-render-time"] = componentServerRenderEndTime;
|
||||
let unrenderedSlots = [];
|
||||
if (html) {
|
||||
if (Object.keys(children).length > 0) {
|
||||
for (const key of Object.keys(children)) {
|
||||
let tagName = renderer?.ssr?.supportsAstroStaticSlot ? !!metadata.hydrate ? "astro-slot" : "astro-static-slot" : "astro-slot";
|
||||
let expectedHTML = key === "default" ? `<${tagName}>` : `<${tagName} name="${key}">`;
|
||||
if (!html.includes(expectedHTML)) {
|
||||
unrenderedSlots.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unrenderedSlots = Object.keys(children);
|
||||
}
|
||||
const template = unrenderedSlots.length > 0 ? unrenderedSlots.map(
|
||||
(key) => `<template data-astro-template${key !== "default" ? `="${key}"` : ""}>${children[key]}</template>`
|
||||
).join("") : "";
|
||||
island.children = `${html ?? ""}${template}`;
|
||||
if (island.children) {
|
||||
island.props["await-children"] = "";
|
||||
island.children += `<!--astro:end-->`;
|
||||
}
|
||||
return {
|
||||
render(destination) {
|
||||
if (slotInstructions) {
|
||||
for (const instruction of slotInstructions) {
|
||||
destination.write(instruction);
|
||||
}
|
||||
}
|
||||
destination.write(createRenderInstruction({ type: "directive", hydration }));
|
||||
if (hydration.directive !== "only" && renderer?.ssr.renderHydrationScript) {
|
||||
destination.write(
|
||||
createRenderInstruction({
|
||||
type: "renderer-hydration-script",
|
||||
rendererName: renderer.name,
|
||||
render: renderer.ssr.renderHydrationScript
|
||||
})
|
||||
);
|
||||
}
|
||||
const renderedElement = renderElement("astro-island", island, false);
|
||||
destination.write(markHTMLString(renderedElement));
|
||||
}
|
||||
};
|
||||
}
|
||||
function sanitizeElementName(tag) {
|
||||
const unsafe = /[&<>'"\s]+/;
|
||||
if (!unsafe.test(tag)) return tag;
|
||||
return tag.trim().split(unsafe)[0].trim();
|
||||
}
|
||||
function renderFragmentComponent(result, slots = {}) {
|
||||
const slot = slots?.default;
|
||||
return {
|
||||
render(destination) {
|
||||
if (slot == null) return;
|
||||
return renderSlot(result, slot).render(destination);
|
||||
}
|
||||
};
|
||||
}
|
||||
async function renderHTMLComponent(result, Component, _props, slots = {}) {
|
||||
const { slotInstructions, children } = await renderSlots(result, slots);
|
||||
const html = Component({ slots: children });
|
||||
const hydrationHtml = slotInstructions ? slotInstructions.map((instr) => chunkToString(result, instr)).join("") : "";
|
||||
return {
|
||||
render(destination) {
|
||||
destination.write(markHTMLString(hydrationHtml + html));
|
||||
}
|
||||
};
|
||||
}
|
||||
function renderAstroComponent(result, displayName, Component, props, slots = {}) {
|
||||
if (containsServerDirective(props)) {
|
||||
const serverIslandComponent = new ServerIslandComponent(result, props, slots, displayName);
|
||||
result._metadata.propagators.add(serverIslandComponent);
|
||||
return serverIslandComponent;
|
||||
}
|
||||
const instance = createAstroComponentInstance(result, displayName, Component, props, slots);
|
||||
return {
|
||||
render(destination) {
|
||||
return instance.render(destination);
|
||||
}
|
||||
};
|
||||
}
|
||||
function renderComponent(result, displayName, Component, props, slots = {}) {
|
||||
if (isPromise(Component)) {
|
||||
return Component.catch(handleCancellation).then((x) => {
|
||||
return renderComponent(result, displayName, x, props, slots);
|
||||
});
|
||||
}
|
||||
if (isFragmentComponent(Component)) {
|
||||
return renderFragmentComponent(result, slots);
|
||||
}
|
||||
props = normalizeProps(props);
|
||||
if (isHTMLComponent(Component)) {
|
||||
return renderHTMLComponent(result, Component, props, slots).catch(handleCancellation);
|
||||
}
|
||||
if (isAstroComponentFactory(Component)) {
|
||||
return renderAstroComponent(result, displayName, Component, props, slots);
|
||||
}
|
||||
return renderFrameworkComponent(result, displayName, Component, props, slots).catch(
|
||||
handleCancellation
|
||||
);
|
||||
function handleCancellation(e) {
|
||||
if (result.cancelled)
|
||||
return {
|
||||
render() {
|
||||
}
|
||||
};
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
function normalizeProps(props) {
|
||||
if (props["class:list"] !== void 0) {
|
||||
const value = props["class:list"];
|
||||
delete props["class:list"];
|
||||
props["class"] = clsx(props["class"], value);
|
||||
if (props["class"] === "") {
|
||||
delete props["class"];
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
async function renderComponentToString(result, displayName, Component, props, slots = {}, isPage = false, route) {
|
||||
let str = "";
|
||||
let renderedFirstPageChunk = false;
|
||||
let head = "";
|
||||
if (isPage && !result.partial && nonAstroPageNeedsHeadInjection(Component)) {
|
||||
head += chunkToString(result, maybeRenderHead());
|
||||
}
|
||||
try {
|
||||
const destination = {
|
||||
write(chunk) {
|
||||
if (isPage && !result.partial && !renderedFirstPageChunk) {
|
||||
renderedFirstPageChunk = true;
|
||||
if (!/<!doctype html/i.test(String(chunk))) {
|
||||
const doctype = result.compressHTML ? "<!DOCTYPE html>" : "<!DOCTYPE html>\n";
|
||||
str += doctype + head;
|
||||
}
|
||||
}
|
||||
if (chunk instanceof Response) return;
|
||||
str += chunkToString(result, chunk);
|
||||
}
|
||||
};
|
||||
const renderInstance = await renderComponent(result, displayName, Component, props, slots);
|
||||
if (containsServerDirective(props)) {
|
||||
await bufferHeadContent(result);
|
||||
}
|
||||
await renderInstance.render(destination);
|
||||
} catch (e) {
|
||||
if (AstroError.is(e) && !e.loc) {
|
||||
e.setLocation({
|
||||
file: route?.component
|
||||
});
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function nonAstroPageNeedsHeadInjection(pageComponent) {
|
||||
return !!pageComponent?.[needsHeadRenderingSymbol];
|
||||
}
|
||||
export {
|
||||
renderComponent,
|
||||
renderComponentToString
|
||||
};
|
||||
2
node_modules/astro/dist/runtime/server/render/csp.d.ts
generated
vendored
Normal file
2
node_modules/astro/dist/runtime/server/render/csp.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import type { SSRResult } from '../../../types/public/index.js';
|
||||
export declare function renderCspContent(result: SSRResult): string;
|
||||
35
node_modules/astro/dist/runtime/server/render/csp.js
generated
vendored
Normal file
35
node_modules/astro/dist/runtime/server/render/csp.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
function renderCspContent(result) {
|
||||
const finalScriptHashes = /* @__PURE__ */ new Set();
|
||||
const finalStyleHashes = /* @__PURE__ */ new Set();
|
||||
for (const scriptHash of result.scriptHashes) {
|
||||
finalScriptHashes.add(`'${scriptHash}'`);
|
||||
}
|
||||
for (const styleHash of result.styleHashes) {
|
||||
finalStyleHashes.add(`'${styleHash}'`);
|
||||
}
|
||||
for (const styleHash of result._metadata.extraStyleHashes) {
|
||||
finalStyleHashes.add(`'${styleHash}'`);
|
||||
}
|
||||
for (const scriptHash of result._metadata.extraScriptHashes) {
|
||||
finalScriptHashes.add(`'${scriptHash}'`);
|
||||
}
|
||||
let directives;
|
||||
if (result.directives.length > 0) {
|
||||
directives = result.directives.join(";") + ";";
|
||||
}
|
||||
let scriptResources = "'self'";
|
||||
if (result.scriptResources.length > 0) {
|
||||
scriptResources = result.scriptResources.map((r) => `${r}`).join(" ");
|
||||
}
|
||||
let styleResources = "'self'";
|
||||
if (result.styleResources.length > 0) {
|
||||
styleResources = result.styleResources.map((r) => `${r}`).join(" ");
|
||||
}
|
||||
const strictDynamic = result.isStrictDynamic ? ` 'strict-dynamic'` : "";
|
||||
const scriptSrc = `script-src ${scriptResources} ${Array.from(finalScriptHashes).join(" ")}${strictDynamic};`;
|
||||
const styleSrc = `style-src ${styleResources} ${Array.from(finalStyleHashes).join(" ")};`;
|
||||
return [directives, scriptSrc, styleSrc].filter(Boolean).join(" ");
|
||||
}
|
||||
export {
|
||||
renderCspContent
|
||||
};
|
||||
3
node_modules/astro/dist/runtime/server/render/dom.d.ts
generated
vendored
Normal file
3
node_modules/astro/dist/runtime/server/render/dom.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import type { SSRResult } from '../../../types/public/internal.js';
|
||||
export declare function componentIsHTMLElement(Component: unknown): boolean;
|
||||
export declare function renderHTMLElement(result: SSRResult, constructor: typeof HTMLElement, props: any, slots: any): Promise<string>;
|
||||
26
node_modules/astro/dist/runtime/server/render/dom.js
generated
vendored
Normal file
26
node_modules/astro/dist/runtime/server/render/dom.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import { markHTMLString } from "../escape.js";
|
||||
import { renderSlotToString } from "./slot.js";
|
||||
import { toAttributeString } from "./util.js";
|
||||
function componentIsHTMLElement(Component) {
|
||||
return typeof HTMLElement !== "undefined" && HTMLElement.isPrototypeOf(Component);
|
||||
}
|
||||
async function renderHTMLElement(result, constructor, props, slots) {
|
||||
const name = getHTMLElementName(constructor);
|
||||
let attrHTML = "";
|
||||
for (const attr in props) {
|
||||
attrHTML += ` ${attr}="${toAttributeString(await props[attr])}"`;
|
||||
}
|
||||
return markHTMLString(
|
||||
`<${name}${attrHTML}>${await renderSlotToString(result, slots?.default)}</${name}>`
|
||||
);
|
||||
}
|
||||
function getHTMLElementName(constructor) {
|
||||
const definedName = customElements.getName(constructor);
|
||||
if (definedName) return definedName;
|
||||
const assignedName = constructor.name.replace(/^HTML|Element$/g, "").replace(/[A-Z]/g, "-$&").toLowerCase().replace(/^-/, "html-");
|
||||
return assignedName;
|
||||
}
|
||||
export {
|
||||
componentIsHTMLElement,
|
||||
renderHTMLElement
|
||||
};
|
||||
20
node_modules/astro/dist/runtime/server/render/head-propagation/runtime.d.ts
generated
vendored
Normal file
20
node_modules/astro/dist/runtime/server/render/head-propagation/runtime.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import { type HeadInstructionRenderState } from '../../../../core/head-propagation/policy.js';
|
||||
import type { SSRResult } from '../../../../types/public/internal.js';
|
||||
import type { AstroComponentFactory } from '../astro/factory.js';
|
||||
/** Facade helper used by runtime adapters to read effective hint resolution. */
|
||||
export declare function getPropagationHint(result: SSRResult, factory: AstroComponentFactory): import("../../../../types/public/internal.js").PropagationHint;
|
||||
/**
|
||||
* Registers an instance in the propagation set when its hint requires buffering.
|
||||
*
|
||||
* @example
|
||||
* A runtime-created component with `propagation: 'self'` is registered so its
|
||||
* styles can be collected before head flush.
|
||||
*/
|
||||
export declare function registerIfPropagating(result: SSRResult, factory: AstroComponentFactory, instance: {
|
||||
init(result: SSRResult): unknown | Promise<unknown>;
|
||||
}): void;
|
||||
export declare function bufferPropagatedHead(result: SSRResult): Promise<void>;
|
||||
/** Facade helper for render instruction gating (`head` vs `maybe-head`). */
|
||||
export declare function shouldRenderInstruction(type: 'head' | 'maybe-head', state: HeadInstructionRenderState): boolean;
|
||||
/** Projects `SSRResult` into the minimal state needed by instruction policy. */
|
||||
export declare function getInstructionRenderState(result: SSRResult): HeadInstructionRenderState;
|
||||
53
node_modules/astro/dist/runtime/server/render/head-propagation/runtime.js
generated
vendored
Normal file
53
node_modules/astro/dist/runtime/server/render/head-propagation/runtime.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
import { collectPropagatedHeadParts } from "../../../../core/head-propagation/buffer.js";
|
||||
import {
|
||||
getPropagationHint as getHint,
|
||||
isPropagatingHint
|
||||
} from "../../../../core/head-propagation/resolver.js";
|
||||
import {
|
||||
shouldRenderInstruction as shouldRenderInstructionByPolicy
|
||||
} from "../../../../core/head-propagation/policy.js";
|
||||
import { isHeadAndContent } from "../astro/head-and-content.js";
|
||||
function getPropagationHint(result, factory) {
|
||||
return getHint(result, factory);
|
||||
}
|
||||
function registerIfPropagating(result, factory, instance) {
|
||||
if (factory.propagation === "self" || factory.propagation === "in-tree") {
|
||||
result._metadata.propagators.add(
|
||||
instance
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (factory.moduleId) {
|
||||
const hint = result.componentMetadata.get(factory.moduleId)?.propagation;
|
||||
if (isPropagatingHint(hint ?? "none")) {
|
||||
result._metadata.propagators.add(
|
||||
instance
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function bufferPropagatedHead(result) {
|
||||
const collected = await collectPropagatedHeadParts({
|
||||
propagators: result._metadata.propagators,
|
||||
result,
|
||||
isHeadAndContent
|
||||
});
|
||||
result._metadata.extraHead.push(...collected);
|
||||
}
|
||||
function shouldRenderInstruction(type, state) {
|
||||
return shouldRenderInstructionByPolicy(type, state);
|
||||
}
|
||||
function getInstructionRenderState(result) {
|
||||
return {
|
||||
hasRenderedHead: result._metadata.hasRenderedHead,
|
||||
headInTree: result._metadata.headInTree,
|
||||
partial: result.partial
|
||||
};
|
||||
}
|
||||
export {
|
||||
bufferPropagatedHead,
|
||||
getInstructionRenderState,
|
||||
getPropagationHint,
|
||||
registerIfPropagating,
|
||||
shouldRenderInstruction
|
||||
};
|
||||
5
node_modules/astro/dist/runtime/server/render/head.d.ts
generated
vendored
Normal file
5
node_modules/astro/dist/runtime/server/render/head.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { SSRResult } from '../../../types/public/internal.js';
|
||||
import type { MaybeRenderHeadInstruction, RenderHeadInstruction } from './instruction.js';
|
||||
export declare function renderAllHeadContent(result: SSRResult): any;
|
||||
export declare function renderHead(): RenderHeadInstruction;
|
||||
export declare function maybeRenderHead(): MaybeRenderHeadInstruction;
|
||||
72
node_modules/astro/dist/runtime/server/render/head.js
generated
vendored
Normal file
72
node_modules/astro/dist/runtime/server/render/head.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
import { markHTMLString } from "../escape.js";
|
||||
import { renderCspContent } from "./csp.js";
|
||||
import { createRenderInstruction } from "./instruction.js";
|
||||
import { renderElement } from "./util.js";
|
||||
function stablePropsKey(props) {
|
||||
const keys = Object.keys(props).sort();
|
||||
let result = "{";
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (i > 0) result += ",";
|
||||
result += JSON.stringify(keys[i]) + ":" + JSON.stringify(props[keys[i]]);
|
||||
}
|
||||
result += "}";
|
||||
return result;
|
||||
}
|
||||
function deduplicateElements(elements) {
|
||||
if (elements.length <= 1) return elements;
|
||||
const seen = /* @__PURE__ */ new Set();
|
||||
return elements.filter((item) => {
|
||||
const key = stablePropsKey(item.props) + item.children;
|
||||
if (seen.has(key)) return false;
|
||||
seen.add(key);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
function renderAllHeadContent(result) {
|
||||
result._metadata.hasRenderedHead = true;
|
||||
let content = "";
|
||||
if (result.shouldInjectCspMetaTags && result.cspDestination === "meta") {
|
||||
content += renderElement(
|
||||
"meta",
|
||||
{
|
||||
props: {
|
||||
"http-equiv": "content-security-policy",
|
||||
content: renderCspContent(result)
|
||||
},
|
||||
children: ""
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
const styles = deduplicateElements(Array.from(result.styles)).map(
|
||||
(style) => style.props.rel === "stylesheet" ? renderElement("link", style) : renderElement("style", style)
|
||||
);
|
||||
result.styles.clear();
|
||||
const scripts = deduplicateElements(Array.from(result.scripts)).map((script) => {
|
||||
if (result.userAssetsBase) {
|
||||
script.props.src = (result.base === "/" ? "" : result.base) + result.userAssetsBase + script.props.src;
|
||||
}
|
||||
return renderElement("script", script, false);
|
||||
});
|
||||
const links = deduplicateElements(Array.from(result.links)).map(
|
||||
(link) => renderElement("link", link, false)
|
||||
);
|
||||
content += styles.join("\n") + links.join("\n") + scripts.join("\n");
|
||||
if (result._metadata.extraHead.length > 0) {
|
||||
for (const part of result._metadata.extraHead) {
|
||||
content += part;
|
||||
}
|
||||
}
|
||||
return markHTMLString(content);
|
||||
}
|
||||
function renderHead() {
|
||||
return createRenderInstruction({ type: "head" });
|
||||
}
|
||||
function maybeRenderHead() {
|
||||
return createRenderInstruction({ type: "maybe-head" });
|
||||
}
|
||||
export {
|
||||
maybeRenderHead,
|
||||
renderAllHeadContent,
|
||||
renderHead
|
||||
};
|
||||
12
node_modules/astro/dist/runtime/server/render/index.d.ts
generated
vendored
Normal file
12
node_modules/astro/dist/runtime/server/render/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export type { AstroComponentFactory, AstroComponentInstance } from './astro/index.js';
|
||||
export { createHeadAndContent, renderTemplate, renderToString } from './astro/index.js';
|
||||
export { chunkToByteArray, chunkToString, Fragment, Renderer } from './common.js';
|
||||
export { renderComponent, renderComponentToString } from './component.js';
|
||||
export { renderHTMLElement } from './dom.js';
|
||||
export { maybeRenderHead, renderHead } from './head.js';
|
||||
export type { RenderInstruction } from './instruction.js';
|
||||
export { renderPage } from './page.js';
|
||||
export { renderScript } from './script.js';
|
||||
export { type ComponentSlots, renderSlot, renderSlotToString } from './slot.js';
|
||||
export { renderScriptElement, renderUniqueStylesheet } from './tags.js';
|
||||
export { addAttribute, defineScriptVars, voidElementNames } from './util.js';
|
||||
33
node_modules/astro/dist/runtime/server/render/index.js
generated
vendored
Normal file
33
node_modules/astro/dist/runtime/server/render/index.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createHeadAndContent, renderTemplate, renderToString } from "./astro/index.js";
|
||||
import { chunkToByteArray, chunkToString, Fragment, Renderer } from "./common.js";
|
||||
import { renderComponent, renderComponentToString } from "./component.js";
|
||||
import { renderHTMLElement } from "./dom.js";
|
||||
import { maybeRenderHead, renderHead } from "./head.js";
|
||||
import { renderPage } from "./page.js";
|
||||
import { renderScript } from "./script.js";
|
||||
import { renderSlot, renderSlotToString } from "./slot.js";
|
||||
import { renderScriptElement, renderUniqueStylesheet } from "./tags.js";
|
||||
import { addAttribute, defineScriptVars, voidElementNames } from "./util.js";
|
||||
export {
|
||||
Fragment,
|
||||
Renderer,
|
||||
addAttribute,
|
||||
chunkToByteArray,
|
||||
chunkToString,
|
||||
createHeadAndContent,
|
||||
defineScriptVars,
|
||||
maybeRenderHead,
|
||||
renderComponent,
|
||||
renderComponentToString,
|
||||
renderHTMLElement,
|
||||
renderHead,
|
||||
renderPage,
|
||||
renderScript,
|
||||
renderScriptElement,
|
||||
renderSlot,
|
||||
renderSlotToString,
|
||||
renderTemplate,
|
||||
renderToString,
|
||||
renderUniqueStylesheet,
|
||||
voidElementNames
|
||||
};
|
||||
31
node_modules/astro/dist/runtime/server/render/instruction.d.ts
generated
vendored
Normal file
31
node_modules/astro/dist/runtime/server/render/instruction.d.ts
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { HydrationMetadata } from '../hydration.js';
|
||||
export type RenderDirectiveInstruction = {
|
||||
type: 'directive';
|
||||
hydration: HydrationMetadata;
|
||||
};
|
||||
export type RenderHeadInstruction = {
|
||||
type: 'head';
|
||||
};
|
||||
/**
|
||||
* Render a renderer-specific hydration script before the first component of that
|
||||
* framework
|
||||
*/
|
||||
export type RendererHydrationScriptInstruction = {
|
||||
type: 'renderer-hydration-script';
|
||||
rendererName: string;
|
||||
render: () => string;
|
||||
};
|
||||
export type MaybeRenderHeadInstruction = {
|
||||
type: 'maybe-head';
|
||||
};
|
||||
export type ServerIslandRuntimeInstruction = {
|
||||
type: 'server-island-runtime';
|
||||
};
|
||||
export type RenderScriptInstruction = {
|
||||
type: 'script';
|
||||
id: string;
|
||||
content: string;
|
||||
};
|
||||
export type RenderInstruction = RenderDirectiveInstruction | RenderHeadInstruction | MaybeRenderHeadInstruction | RendererHydrationScriptInstruction | ServerIslandRuntimeInstruction | RenderScriptInstruction;
|
||||
export declare function createRenderInstruction<T extends RenderInstruction>(instruction: T): T;
|
||||
export declare function isRenderInstruction(chunk: any): chunk is RenderInstruction;
|
||||
13
node_modules/astro/dist/runtime/server/render/instruction.js
generated
vendored
Normal file
13
node_modules/astro/dist/runtime/server/render/instruction.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
const RenderInstructionSymbol = /* @__PURE__ */ Symbol.for("astro:render");
|
||||
function createRenderInstruction(instruction) {
|
||||
return Object.defineProperty(instruction, RenderInstructionSymbol, {
|
||||
value: true
|
||||
});
|
||||
}
|
||||
function isRenderInstruction(chunk) {
|
||||
return chunk && typeof chunk === "object" && chunk[RenderInstructionSymbol];
|
||||
}
|
||||
export {
|
||||
createRenderInstruction,
|
||||
isRenderInstruction
|
||||
};
|
||||
4
node_modules/astro/dist/runtime/server/render/page.d.ts
generated
vendored
Normal file
4
node_modules/astro/dist/runtime/server/render/page.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { RouteData, SSRResult } from '../../../types/public/internal.js';
|
||||
import { type NonAstroPageComponent } from './component.js';
|
||||
import type { AstroComponentFactory } from './index.js';
|
||||
export declare function renderPage(result: SSRResult, componentFactory: AstroComponentFactory | NonAstroPageComponent, props: any, children: any, streaming: boolean, route?: RouteData): Promise<Response>;
|
||||
118
node_modules/astro/dist/runtime/server/render/page.js
generated
vendored
Normal file
118
node_modules/astro/dist/runtime/server/render/page.js
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
import { renderToAsyncIterable, renderToReadableStream, renderToString } from "./astro/render.js";
|
||||
import { encoder } from "./common.js";
|
||||
import { renderComponentToString } from "./component.js";
|
||||
import { markHTMLString } from "../escape.js";
|
||||
import { renderCspContent } from "./csp.js";
|
||||
import { isDeno, isNode } from "./util.js";
|
||||
import { isAstroComponentFactory } from "./astro/factory.js";
|
||||
import { buildRenderQueue } from "./queue/builder.js";
|
||||
import { renderQueue } from "./queue/renderer.js";
|
||||
import { chunkToString } from "./common.js";
|
||||
async function renderPage(result, componentFactory, props, children, streaming, route) {
|
||||
if (!isAstroComponentFactory(componentFactory)) {
|
||||
result._metadata.headInTree = result.componentMetadata.get(componentFactory.moduleId)?.containsHead ?? false;
|
||||
const pageProps = { ...props ?? {}, "server:root": true };
|
||||
let str;
|
||||
if (result._experimentalQueuedRendering && result._experimentalQueuedRendering.enabled) {
|
||||
let vnode = await componentFactory(pageProps);
|
||||
if (componentFactory["astro:html"] && typeof vnode === "string") {
|
||||
vnode = markHTMLString(vnode);
|
||||
}
|
||||
const queue = await buildRenderQueue(
|
||||
vnode,
|
||||
result,
|
||||
result._experimentalQueuedRendering.pool
|
||||
);
|
||||
let html = "";
|
||||
let renderedFirst = false;
|
||||
const destination = {
|
||||
write(chunk) {
|
||||
if (chunk instanceof Response) return;
|
||||
if (!renderedFirst && !result.partial) {
|
||||
renderedFirst = true;
|
||||
const chunkStr = String(chunk);
|
||||
if (!/<!doctype html/i.test(chunkStr)) {
|
||||
const doctype = result.compressHTML ? "<!DOCTYPE html>" : "<!DOCTYPE html>\n";
|
||||
html += doctype;
|
||||
}
|
||||
}
|
||||
html += chunkToString(result, chunk);
|
||||
}
|
||||
};
|
||||
await renderQueue(queue, destination);
|
||||
str = html;
|
||||
} else {
|
||||
str = await renderComponentToString(
|
||||
result,
|
||||
componentFactory.name,
|
||||
componentFactory,
|
||||
pageProps,
|
||||
{},
|
||||
true,
|
||||
route
|
||||
);
|
||||
}
|
||||
const bytes = encoder.encode(str);
|
||||
const headers2 = new Headers([
|
||||
["Content-Type", "text/html"],
|
||||
["Content-Length", bytes.byteLength.toString()]
|
||||
]);
|
||||
if (result.shouldInjectCspMetaTags && (result.cspDestination === "header" || result.cspDestination === "adapter")) {
|
||||
headers2.set("content-security-policy", renderCspContent(result));
|
||||
}
|
||||
return new Response(bytes, {
|
||||
headers: headers2,
|
||||
status: result.response.status
|
||||
});
|
||||
}
|
||||
result._metadata.headInTree = result.componentMetadata.get(componentFactory.moduleId)?.containsHead ?? false;
|
||||
let body;
|
||||
if (streaming) {
|
||||
if (isNode && !isDeno) {
|
||||
const nodeBody = await renderToAsyncIterable(
|
||||
result,
|
||||
componentFactory,
|
||||
props,
|
||||
children,
|
||||
true,
|
||||
route
|
||||
);
|
||||
body = nodeBody;
|
||||
} else {
|
||||
body = await renderToReadableStream(result, componentFactory, props, children, true, route);
|
||||
}
|
||||
} else {
|
||||
body = await renderToString(result, componentFactory, props, children, true, route);
|
||||
}
|
||||
if (body instanceof Response) return body;
|
||||
const init = result.response;
|
||||
const headers = new Headers(init.headers);
|
||||
if (result.shouldInjectCspMetaTags && result.cspDestination === "header" || result.cspDestination === "adapter") {
|
||||
headers.set("content-security-policy", renderCspContent(result));
|
||||
}
|
||||
if (!streaming && typeof body === "string") {
|
||||
body = encoder.encode(body);
|
||||
headers.set("Content-Length", body.byteLength.toString());
|
||||
}
|
||||
let status = init.status;
|
||||
let statusText = init.statusText;
|
||||
if (route?.route === "/404") {
|
||||
status = 404;
|
||||
if (statusText === "OK") {
|
||||
statusText = "Not Found";
|
||||
}
|
||||
} else if (route?.route === "/500") {
|
||||
status = 500;
|
||||
if (statusText === "OK") {
|
||||
statusText = "Internal Server Error";
|
||||
}
|
||||
}
|
||||
if (status) {
|
||||
return new Response(body, { ...init, headers, status, statusText });
|
||||
} else {
|
||||
return new Response(body, { ...init, headers });
|
||||
}
|
||||
}
|
||||
export {
|
||||
renderPage
|
||||
};
|
||||
14
node_modules/astro/dist/runtime/server/render/queue/builder.d.ts
generated
vendored
Normal file
14
node_modules/astro/dist/runtime/server/render/queue/builder.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { SSRResult } from '../../../../types/public/internal.js';
|
||||
import type { RenderQueue } from './types.js';
|
||||
import type { NodePool } from './pool.js';
|
||||
/**
|
||||
* Builds a render queue from a component tree.
|
||||
* This function traverses the tree depth-first and creates a flat queue
|
||||
* of nodes to be rendered, with parent tracking.
|
||||
*
|
||||
* @param root - The root component/value to render
|
||||
* @param result - SSR result context
|
||||
* @param pool
|
||||
* @returns A render queue ready for rendering
|
||||
*/
|
||||
export declare function buildRenderQueue(root: any, result: SSRResult, pool: NodePool): Promise<RenderQueue>;
|
||||
182
node_modules/astro/dist/runtime/server/render/queue/builder.js
generated
vendored
Normal file
182
node_modules/astro/dist/runtime/server/render/queue/builder.js
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
import { isPromise } from "../../util.js";
|
||||
import { isHTMLString, markHTMLString } from "../../escape.js";
|
||||
import { isAstroComponentFactory, isAPropagatingComponent } from "../astro/factory.js";
|
||||
import { createAstroComponentInstance, isAstroComponentInstance } from "../astro/instance.js";
|
||||
import { isRenderInstance } from "../common.js";
|
||||
import { isRenderInstruction } from "../instruction.js";
|
||||
import { SlotString } from "../slot.js";
|
||||
import { isRenderTemplateResult } from "../astro/render-template.js";
|
||||
import { isHeadAndContent } from "../astro/head-and-content.js";
|
||||
import { isVNode } from "../../../../jsx-runtime/index.js";
|
||||
import { renderJSXToQueue } from "./jsx-builder.js";
|
||||
async function buildRenderQueue(root, result, pool) {
|
||||
const queue = {
|
||||
nodes: [],
|
||||
result,
|
||||
pool,
|
||||
htmlStringCache: result._experimentalQueuedRendering?.htmlStringCache
|
||||
};
|
||||
const stack = [{ node: root, parent: null }];
|
||||
while (stack.length > 0) {
|
||||
const item = stack.pop();
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
let { node, parent } = item;
|
||||
if (isPromise(node)) {
|
||||
try {
|
||||
const resolved = await node;
|
||||
stack.push({ node: resolved, parent, metadata: item.metadata });
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node == null || node === false) {
|
||||
continue;
|
||||
}
|
||||
if (typeof node === "string") {
|
||||
const queueNode = pool.acquire("text", node);
|
||||
queueNode.content = node;
|
||||
queue.nodes.push(queueNode);
|
||||
continue;
|
||||
}
|
||||
if (typeof node === "number" || typeof node === "boolean") {
|
||||
const str = String(node);
|
||||
const queueNode = pool.acquire("text", str);
|
||||
queueNode.content = str;
|
||||
queue.nodes.push(queueNode);
|
||||
continue;
|
||||
}
|
||||
if (isHTMLString(node)) {
|
||||
const html = node.toString();
|
||||
const queueNode = pool.acquire("html-string", html);
|
||||
queueNode.html = html;
|
||||
queue.nodes.push(queueNode);
|
||||
continue;
|
||||
}
|
||||
if (node instanceof SlotString) {
|
||||
const html = node.toString();
|
||||
const queueNode = pool.acquire("html-string", html);
|
||||
queueNode.html = html;
|
||||
queue.nodes.push(queueNode);
|
||||
continue;
|
||||
}
|
||||
if (isVNode(node)) {
|
||||
renderJSXToQueue(node, result, queue, pool, stack, parent, item.metadata);
|
||||
continue;
|
||||
}
|
||||
if (Array.isArray(node)) {
|
||||
for (const n of node) {
|
||||
stack.push({ node: n, parent, metadata: item.metadata });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isRenderInstruction(node)) {
|
||||
const queueNode = pool.acquire("instruction");
|
||||
queueNode.instruction = node;
|
||||
queue.nodes.push(queueNode);
|
||||
continue;
|
||||
}
|
||||
if (isRenderTemplateResult(node)) {
|
||||
const htmlParts = node["htmlParts"];
|
||||
const expressions = node["expressions"];
|
||||
if (htmlParts[0]) {
|
||||
const htmlString = queue.htmlStringCache ? queue.htmlStringCache.getOrCreate(htmlParts[0]) : markHTMLString(htmlParts[0]);
|
||||
stack.push({
|
||||
node: htmlString,
|
||||
parent,
|
||||
metadata: item.metadata
|
||||
});
|
||||
}
|
||||
for (let i = 0; i < expressions.length; i = i + 1) {
|
||||
stack.push({ node: expressions[i], parent, metadata: item.metadata });
|
||||
if (htmlParts[i + 1]) {
|
||||
const htmlString = queue.htmlStringCache ? queue.htmlStringCache.getOrCreate(htmlParts[i + 1]) : markHTMLString(htmlParts[i + 1]);
|
||||
stack.push({
|
||||
node: htmlString,
|
||||
parent,
|
||||
metadata: item.metadata
|
||||
});
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isAstroComponentInstance(node)) {
|
||||
const queueNode = pool.acquire("component");
|
||||
queueNode.instance = node;
|
||||
queue.nodes.push(queueNode);
|
||||
continue;
|
||||
}
|
||||
if (isAstroComponentFactory(node)) {
|
||||
const factory = node;
|
||||
const props = item.metadata?.props || {};
|
||||
const slots = item.metadata?.slots || {};
|
||||
const displayName = item.metadata?.displayName || factory.name || "Anonymous";
|
||||
const instance = createAstroComponentInstance(result, displayName, factory, props, slots);
|
||||
const queueNode = pool.acquire("component");
|
||||
queueNode.instance = instance;
|
||||
if (isAPropagatingComponent(result, factory)) {
|
||||
try {
|
||||
const returnValue = await instance.init(result);
|
||||
if (isHeadAndContent(returnValue) && returnValue.head) {
|
||||
result._metadata.extraHead.push(returnValue.head);
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
queue.nodes.push(queueNode);
|
||||
continue;
|
||||
}
|
||||
if (isRenderInstance(node)) {
|
||||
const queueNode = pool.acquire("component");
|
||||
queueNode.instance = node;
|
||||
queue.nodes.push(queueNode);
|
||||
continue;
|
||||
}
|
||||
if (typeof node === "object" && Symbol.iterator in node) {
|
||||
const items = Array.from(node);
|
||||
for (const iterItem of items) {
|
||||
stack.push({ node: iterItem, parent, metadata: item.metadata });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (typeof node === "object" && Symbol.asyncIterator in node) {
|
||||
try {
|
||||
const items = [];
|
||||
for await (const asyncItem of node) {
|
||||
items.push(asyncItem);
|
||||
}
|
||||
for (const iterItem of items) {
|
||||
stack.push({ node: iterItem, parent, metadata: item.metadata });
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (node instanceof Response) {
|
||||
const queueNode = pool.acquire("html-string", "");
|
||||
queueNode.html = "";
|
||||
queue.nodes.push(queueNode);
|
||||
continue;
|
||||
}
|
||||
if (isHTMLString(node)) {
|
||||
const html = String(node);
|
||||
const queueNode = pool.acquire("html-string", html);
|
||||
queueNode.html = html;
|
||||
queue.nodes.push(queueNode);
|
||||
} else {
|
||||
const str = String(node);
|
||||
const queueNode = pool.acquire("text", str);
|
||||
queueNode.content = str;
|
||||
queue.nodes.push(queueNode);
|
||||
}
|
||||
}
|
||||
queue.nodes.reverse();
|
||||
return queue;
|
||||
}
|
||||
export {
|
||||
buildRenderQueue
|
||||
};
|
||||
33
node_modules/astro/dist/runtime/server/render/queue/jsx-builder.d.ts
generated
vendored
Normal file
33
node_modules/astro/dist/runtime/server/render/queue/jsx-builder.d.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { SSRResult } from '../../../../types/public/internal.js';
|
||||
import type { RenderQueue, StackItem, QueueNode } from './types.js';
|
||||
import type { NodePool } from './pool.js';
|
||||
/**
|
||||
* Get JSX queue rendering statistics
|
||||
*/
|
||||
export declare function getJSXQueueStats(): {
|
||||
vnodeCount: number;
|
||||
elementCount: number;
|
||||
componentCount: number;
|
||||
hasLogged: boolean;
|
||||
};
|
||||
/**
|
||||
* Reset JSX queue rendering statistics
|
||||
*/
|
||||
export declare function resetJSXQueueStats(): void;
|
||||
/**
|
||||
* Processes JSX VNodes and adds them to the render queue.
|
||||
* Unlike renderJSX(), this doesn't build strings recursively -
|
||||
* it pushes nodes directly to the queue for batching and memory efficiency.
|
||||
*
|
||||
* This function handles JSX created by astro:jsx (JSX in .astro files).
|
||||
* It converts VNodes to queue nodes, enabling content-aware pooling and batching.
|
||||
*
|
||||
* @param vnode - JSX VNode to process
|
||||
* @param result - SSR result context
|
||||
* @param queue - Queue to append nodes to
|
||||
* @param pool - Node pool for memory efficiency
|
||||
* @param stack - Stack for depth-first traversal
|
||||
* @param parent - Parent queue node (for tracking)
|
||||
* @param metadata - Metadata passed through stack (props, slots, displayName)
|
||||
*/
|
||||
export declare function renderJSXToQueue(vnode: any, result: SSRResult, queue: RenderQueue, pool: NodePool, stack: StackItem[], parent: QueueNode | null, metadata?: StackItem['metadata']): void;
|
||||
146
node_modules/astro/dist/runtime/server/render/queue/jsx-builder.js
generated
vendored
Normal file
146
node_modules/astro/dist/runtime/server/render/queue/jsx-builder.js
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
import { isVNode } from "../../../../jsx-runtime/index.js";
|
||||
import { HTMLString, markHTMLString, spreadAttributes, voidElementNames } from "../../index.js";
|
||||
import { isAstroComponentFactory } from "../astro/factory.js";
|
||||
import { createAstroComponentInstance } from "../astro/instance.js";
|
||||
import { renderJSX } from "../../jsx.js";
|
||||
const ClientOnlyPlaceholder = "astro-client-only";
|
||||
let jsxQueueStats = {
|
||||
vnodeCount: 0,
|
||||
elementCount: 0,
|
||||
componentCount: 0,
|
||||
hasLogged: false
|
||||
};
|
||||
function getJSXQueueStats() {
|
||||
return { ...jsxQueueStats };
|
||||
}
|
||||
function resetJSXQueueStats() {
|
||||
jsxQueueStats = {
|
||||
vnodeCount: 0,
|
||||
elementCount: 0,
|
||||
componentCount: 0,
|
||||
hasLogged: false
|
||||
};
|
||||
}
|
||||
function renderJSXToQueue(vnode, result, queue, pool, stack, parent, metadata) {
|
||||
jsxQueueStats.vnodeCount = jsxQueueStats.vnodeCount + 1;
|
||||
if (vnode instanceof HTMLString) {
|
||||
const html = vnode.toString();
|
||||
if (html.trim() === "") return;
|
||||
const node = pool.acquire("html-string", html);
|
||||
node.html = html;
|
||||
queue.nodes.push(node);
|
||||
return;
|
||||
}
|
||||
if (typeof vnode === "string") {
|
||||
const node = pool.acquire("text", vnode);
|
||||
node.content = vnode;
|
||||
queue.nodes.push(node);
|
||||
return;
|
||||
}
|
||||
if (typeof vnode === "number" || typeof vnode === "boolean") {
|
||||
const str = String(vnode);
|
||||
const node = pool.acquire("text", str);
|
||||
node.content = str;
|
||||
queue.nodes.push(node);
|
||||
return;
|
||||
}
|
||||
if (vnode == null || vnode === false) {
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(vnode)) {
|
||||
for (let i = vnode.length - 1; i >= 0; i = i - 1) {
|
||||
stack.push({ node: vnode[i], parent, metadata });
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!isVNode(vnode)) {
|
||||
const str = String(vnode);
|
||||
const node = pool.acquire("text", str);
|
||||
node.content = str;
|
||||
queue.nodes.push(node);
|
||||
return;
|
||||
}
|
||||
handleVNode(vnode, result, queue, pool, stack, parent, metadata);
|
||||
}
|
||||
function handleVNode(vnode, result, queue, pool, stack, parent, metadata) {
|
||||
if (!vnode.type) {
|
||||
throw new Error(
|
||||
`Unable to render ${result.pathname} because it contains an undefined Component!
|
||||
Did you forget to import the component or is it possible there is a typo?`
|
||||
);
|
||||
}
|
||||
if (vnode.type === /* @__PURE__ */ Symbol.for("astro:fragment")) {
|
||||
stack.push({ node: vnode.props?.children, parent, metadata });
|
||||
return;
|
||||
}
|
||||
if (isAstroComponentFactory(vnode.type)) {
|
||||
jsxQueueStats.componentCount = jsxQueueStats.componentCount + 1;
|
||||
const factory = vnode.type;
|
||||
let props = {};
|
||||
let slots = {};
|
||||
for (const [key, value] of Object.entries(vnode.props ?? {})) {
|
||||
if (key === "children" || value && typeof value === "object" && value["$$slot"]) {
|
||||
slots[key === "children" ? "default" : key] = () => renderJSX(result, value);
|
||||
} else {
|
||||
props[key] = value;
|
||||
}
|
||||
}
|
||||
const displayName = metadata?.displayName || factory.name || "Anonymous";
|
||||
const instance = createAstroComponentInstance(result, displayName, factory, props, slots);
|
||||
const queueNode = pool.acquire("component");
|
||||
queueNode.instance = instance;
|
||||
queue.nodes.push(queueNode);
|
||||
return;
|
||||
}
|
||||
if (typeof vnode.type === "string" && vnode.type !== ClientOnlyPlaceholder) {
|
||||
jsxQueueStats.elementCount = jsxQueueStats.elementCount + 1;
|
||||
renderHTMLElement(vnode, result, queue, pool, stack, parent, metadata);
|
||||
return;
|
||||
}
|
||||
if (typeof vnode.type === "function") {
|
||||
if (vnode.props?.["server:root"]) {
|
||||
const output3 = vnode.type(vnode.props ?? {});
|
||||
stack.push({ node: output3, parent, metadata });
|
||||
return;
|
||||
}
|
||||
const output2 = vnode.type(vnode.props ?? {});
|
||||
stack.push({ node: output2, parent, metadata });
|
||||
return;
|
||||
}
|
||||
const output = renderJSX(result, vnode);
|
||||
stack.push({ node: output, parent, metadata });
|
||||
}
|
||||
function renderHTMLElement(vnode, _result, queue, pool, stack, parent, metadata) {
|
||||
const tag = vnode.type;
|
||||
const { children, ...props } = vnode.props ?? {};
|
||||
const attrs = spreadAttributes(props);
|
||||
const isVoidElement = (children == null || children === "") && voidElementNames.test(tag);
|
||||
if (isVoidElement) {
|
||||
const html = `<${tag}${attrs}/>`;
|
||||
const node = pool.acquire("html-string", html);
|
||||
node.html = html;
|
||||
queue.nodes.push(node);
|
||||
return;
|
||||
}
|
||||
const openTag = `<${tag}${attrs}>`;
|
||||
const openTagHtml = queue.htmlStringCache ? queue.htmlStringCache.getOrCreate(openTag) : markHTMLString(openTag);
|
||||
stack.push({ node: openTagHtml, parent, metadata });
|
||||
if (children != null && children !== "") {
|
||||
const processedChildren = prerenderElementChildren(tag, children, queue.htmlStringCache);
|
||||
stack.push({ node: processedChildren, parent, metadata });
|
||||
}
|
||||
const closeTag = `</${tag}>`;
|
||||
const closeTagHtml = queue.htmlStringCache ? queue.htmlStringCache.getOrCreate(closeTag) : markHTMLString(closeTag);
|
||||
stack.push({ node: closeTagHtml, parent, metadata });
|
||||
}
|
||||
function prerenderElementChildren(tag, children, htmlStringCache) {
|
||||
if (typeof children === "string" && (tag === "style" || tag === "script")) {
|
||||
return htmlStringCache ? htmlStringCache.getOrCreate(children) : markHTMLString(children);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
export {
|
||||
getJSXQueueStats,
|
||||
renderJSXToQueue,
|
||||
resetJSXQueueStats
|
||||
};
|
||||
123
node_modules/astro/dist/runtime/server/render/queue/pool.d.ts
generated
vendored
Normal file
123
node_modules/astro/dist/runtime/server/render/queue/pool.d.ts
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
import type { QueueNode } from './types.js';
|
||||
import type { SSRManifest } from '../../../../core/app/types.js';
|
||||
/**
|
||||
* Raw statistics tracked by the node pool.
|
||||
*/
|
||||
export interface PoolStats {
|
||||
/** Number of times a node was successfully acquired from the pool */
|
||||
acquireFromPool: number;
|
||||
/** Number of times a new node had to be created (pool was empty) */
|
||||
acquireNew: number;
|
||||
/** Number of nodes successfully returned to the pool */
|
||||
released: number;
|
||||
/** Number of nodes that couldn't be returned (pool was full) */
|
||||
releasedDropped: number;
|
||||
}
|
||||
/**
|
||||
* Extended statistics report with computed metrics.
|
||||
* Returned by NodePool.getStats() for debugging and monitoring.
|
||||
*/
|
||||
export interface PoolStatsReport extends PoolStats {
|
||||
/** Current number of nodes available in the pool */
|
||||
poolSize: number;
|
||||
/** Maximum pool capacity */
|
||||
maxSize: number;
|
||||
/** Pool hit rate as a percentage (0-100) - higher is better */
|
||||
hitRate: number;
|
||||
}
|
||||
/**
|
||||
* Object pool for `QueueNode` instances to reduce allocations and GC pressure.
|
||||
*
|
||||
* Uses type-aware sub-pools so that released nodes are reused by the same
|
||||
* node type, preserving V8 hidden classes and avoiding shape transitions.
|
||||
* Nodes are acquired from the pool, used during queue building, and released
|
||||
* back to the pool for reuse across renders.
|
||||
*
|
||||
* String deduplication is handled separately by `HTMLStringCache`.
|
||||
*/
|
||||
export declare class NodePool {
|
||||
private textPool;
|
||||
private htmlStringPool;
|
||||
private componentPool;
|
||||
private instructionPool;
|
||||
readonly maxSize: number;
|
||||
private readonly enableStats;
|
||||
private stats;
|
||||
/**
|
||||
* Creates a new object pool for queue nodes.
|
||||
*
|
||||
* @param maxSize - Maximum number of nodes to keep in the pool (default: 1000).
|
||||
* The cap is shared across all typed sub-pools.
|
||||
* @param enableStats - Enable statistics tracking (default: false for performance)
|
||||
*/
|
||||
constructor(maxSize?: number, enableStats?: boolean);
|
||||
/**
|
||||
* Acquires a queue node from the pool or creates a new one if the pool is empty.
|
||||
* Pops from the type-specific sub-pool to reuse an existing object when available.
|
||||
*
|
||||
* @param type - The type of queue node to acquire
|
||||
* @param content - Optional content to set on the node (for text or html-string types)
|
||||
* @returns A queue node ready to be populated with data
|
||||
*/
|
||||
acquire(type: QueueNode['type'], content?: string): QueueNode;
|
||||
/**
|
||||
* Creates a new node of the specified type with the given content.
|
||||
* Helper method to reduce branching in acquire().
|
||||
*/
|
||||
private createNode;
|
||||
/**
|
||||
* Pops a node from the type-specific sub-pool.
|
||||
* Returns undefined if the sub-pool for the requested type is empty.
|
||||
*/
|
||||
private popFromTypedPool;
|
||||
/**
|
||||
* Resets the content/value field on a reused pooled node.
|
||||
* The type discriminant is already correct since we pop from the matching sub-pool.
|
||||
*/
|
||||
private resetNodeContent;
|
||||
/**
|
||||
* Returns the total number of nodes across all typed sub-pools.
|
||||
*/
|
||||
private totalPoolSize;
|
||||
/**
|
||||
* Releases a queue node back to the pool for reuse.
|
||||
* If the pool is at max capacity, the node is discarded (will be GC'd).
|
||||
*
|
||||
* @param node - The node to release back to the pool
|
||||
*/
|
||||
release(node: QueueNode): void;
|
||||
/**
|
||||
* Releases all nodes in an array back to the pool.
|
||||
* This is a convenience method for releasing multiple nodes at once.
|
||||
*
|
||||
* @param nodes - Array of nodes to release
|
||||
*/
|
||||
releaseAll(nodes: QueueNode[]): void;
|
||||
/**
|
||||
* Clears all typed sub-pools, discarding all cached nodes.
|
||||
* This can be useful if you want to free memory after a large render.
|
||||
*/
|
||||
clear(): void;
|
||||
/**
|
||||
* Gets the current total number of nodes across all typed sub-pools.
|
||||
* Useful for monitoring pool usage and tuning maxSize.
|
||||
*
|
||||
* @returns Number of nodes currently available in the pool
|
||||
*/
|
||||
size(): number;
|
||||
/**
|
||||
* Gets pool statistics for debugging.
|
||||
*
|
||||
* @returns Pool usage statistics including computed metrics
|
||||
*/
|
||||
getStats(): PoolStatsReport;
|
||||
/**
|
||||
* Resets pool statistics.
|
||||
*/
|
||||
resetStats(): void;
|
||||
}
|
||||
/**
|
||||
* Returns an instance of the `NodePool` based on its configuration.
|
||||
* @param config - The queued rendering configuration from the SSR manifest
|
||||
*/
|
||||
export declare function newNodePool(config: NonNullable<SSRManifest['experimentalQueuedRendering']>): NodePool;
|
||||
203
node_modules/astro/dist/runtime/server/render/queue/pool.js
generated
vendored
Normal file
203
node_modules/astro/dist/runtime/server/render/queue/pool.js
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
import { queuePoolSize } from "../../../../core/app/manifest.js";
|
||||
class NodePool {
|
||||
textPool = [];
|
||||
htmlStringPool = [];
|
||||
componentPool = [];
|
||||
instructionPool = [];
|
||||
maxSize;
|
||||
enableStats;
|
||||
stats = {
|
||||
acquireFromPool: 0,
|
||||
acquireNew: 0,
|
||||
released: 0,
|
||||
releasedDropped: 0
|
||||
};
|
||||
/**
|
||||
* Creates a new object pool for queue nodes.
|
||||
*
|
||||
* @param maxSize - Maximum number of nodes to keep in the pool (default: 1000).
|
||||
* The cap is shared across all typed sub-pools.
|
||||
* @param enableStats - Enable statistics tracking (default: false for performance)
|
||||
*/
|
||||
constructor(maxSize = 1e3, enableStats = false) {
|
||||
this.maxSize = maxSize;
|
||||
this.enableStats = enableStats;
|
||||
}
|
||||
/**
|
||||
* Acquires a queue node from the pool or creates a new one if the pool is empty.
|
||||
* Pops from the type-specific sub-pool to reuse an existing object when available.
|
||||
*
|
||||
* @param type - The type of queue node to acquire
|
||||
* @param content - Optional content to set on the node (for text or html-string types)
|
||||
* @returns A queue node ready to be populated with data
|
||||
*/
|
||||
acquire(type, content) {
|
||||
const pooledNode = this.popFromTypedPool(type);
|
||||
if (pooledNode) {
|
||||
if (this.enableStats) {
|
||||
this.stats.acquireFromPool = this.stats.acquireFromPool + 1;
|
||||
}
|
||||
this.resetNodeContent(pooledNode, type, content);
|
||||
return pooledNode;
|
||||
}
|
||||
if (this.enableStats) {
|
||||
this.stats.acquireNew = this.stats.acquireNew + 1;
|
||||
}
|
||||
return this.createNode(type, content);
|
||||
}
|
||||
/**
|
||||
* Creates a new node of the specified type with the given content.
|
||||
* Helper method to reduce branching in acquire().
|
||||
*/
|
||||
createNode(type, content = "") {
|
||||
switch (type) {
|
||||
case "text":
|
||||
return { type: "text", content };
|
||||
case "html-string":
|
||||
return { type: "html-string", html: content };
|
||||
case "component":
|
||||
return { type: "component", instance: void 0 };
|
||||
case "instruction":
|
||||
return { type: "instruction", instruction: void 0 };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Pops a node from the type-specific sub-pool.
|
||||
* Returns undefined if the sub-pool for the requested type is empty.
|
||||
*/
|
||||
popFromTypedPool(type) {
|
||||
switch (type) {
|
||||
case "text":
|
||||
return this.textPool.pop();
|
||||
case "html-string":
|
||||
return this.htmlStringPool.pop();
|
||||
case "component":
|
||||
return this.componentPool.pop();
|
||||
case "instruction":
|
||||
return this.instructionPool.pop();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Resets the content/value field on a reused pooled node.
|
||||
* The type discriminant is already correct since we pop from the matching sub-pool.
|
||||
*/
|
||||
resetNodeContent(node, type, content) {
|
||||
switch (type) {
|
||||
case "text":
|
||||
node.content = content ?? "";
|
||||
break;
|
||||
case "html-string":
|
||||
node.html = content ?? "";
|
||||
break;
|
||||
case "component":
|
||||
node.instance = void 0;
|
||||
break;
|
||||
case "instruction":
|
||||
node.instruction = void 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the total number of nodes across all typed sub-pools.
|
||||
*/
|
||||
totalPoolSize() {
|
||||
return this.textPool.length + this.htmlStringPool.length + this.componentPool.length + this.instructionPool.length;
|
||||
}
|
||||
/**
|
||||
* Releases a queue node back to the pool for reuse.
|
||||
* If the pool is at max capacity, the node is discarded (will be GC'd).
|
||||
*
|
||||
* @param node - The node to release back to the pool
|
||||
*/
|
||||
release(node) {
|
||||
if (this.totalPoolSize() >= this.maxSize) {
|
||||
if (this.enableStats) {
|
||||
this.stats.releasedDropped = this.stats.releasedDropped + 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (node.type) {
|
||||
case "text":
|
||||
node.content = "";
|
||||
this.textPool.push(node);
|
||||
break;
|
||||
case "html-string":
|
||||
node.html = "";
|
||||
this.htmlStringPool.push(node);
|
||||
break;
|
||||
case "component":
|
||||
node.instance = void 0;
|
||||
this.componentPool.push(node);
|
||||
break;
|
||||
case "instruction":
|
||||
node.instruction = void 0;
|
||||
this.instructionPool.push(node);
|
||||
break;
|
||||
}
|
||||
if (this.enableStats) {
|
||||
this.stats.released = this.stats.released + 1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Releases all nodes in an array back to the pool.
|
||||
* This is a convenience method for releasing multiple nodes at once.
|
||||
*
|
||||
* @param nodes - Array of nodes to release
|
||||
*/
|
||||
releaseAll(nodes) {
|
||||
for (const node of nodes) {
|
||||
this.release(node);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Clears all typed sub-pools, discarding all cached nodes.
|
||||
* This can be useful if you want to free memory after a large render.
|
||||
*/
|
||||
clear() {
|
||||
this.textPool.length = 0;
|
||||
this.htmlStringPool.length = 0;
|
||||
this.componentPool.length = 0;
|
||||
this.instructionPool.length = 0;
|
||||
}
|
||||
/**
|
||||
* Gets the current total number of nodes across all typed sub-pools.
|
||||
* Useful for monitoring pool usage and tuning maxSize.
|
||||
*
|
||||
* @returns Number of nodes currently available in the pool
|
||||
*/
|
||||
size() {
|
||||
return this.totalPoolSize();
|
||||
}
|
||||
/**
|
||||
* Gets pool statistics for debugging.
|
||||
*
|
||||
* @returns Pool usage statistics including computed metrics
|
||||
*/
|
||||
getStats() {
|
||||
return {
|
||||
...this.stats,
|
||||
poolSize: this.totalPoolSize(),
|
||||
maxSize: this.maxSize,
|
||||
hitRate: this.stats.acquireFromPool + this.stats.acquireNew > 0 ? this.stats.acquireFromPool / (this.stats.acquireFromPool + this.stats.acquireNew) * 100 : 0
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Resets pool statistics.
|
||||
*/
|
||||
resetStats() {
|
||||
this.stats = {
|
||||
acquireFromPool: 0,
|
||||
acquireNew: 0,
|
||||
released: 0,
|
||||
releasedDropped: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
function newNodePool(config) {
|
||||
const poolSize = queuePoolSize(config);
|
||||
return new NodePool(poolSize);
|
||||
}
|
||||
export {
|
||||
NodePool,
|
||||
newNodePool
|
||||
};
|
||||
12
node_modules/astro/dist/runtime/server/render/queue/renderer.d.ts
generated
vendored
Normal file
12
node_modules/astro/dist/runtime/server/render/queue/renderer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { type RenderDestination } from '../common.js';
|
||||
import type { RenderQueue } from './types.js';
|
||||
/**
|
||||
* Renders a queue of nodes to a destination.
|
||||
* This function processes nodes sequentially with batching optimization.
|
||||
* Consecutive batchable nodes (text, HTML-string, simple elements) are
|
||||
* combined into a single write to reduce overhead.
|
||||
*
|
||||
* @param queue - The render queue to process
|
||||
* @param destination - Where to write the output
|
||||
*/
|
||||
export declare function renderQueue(queue: RenderQueue, destination: RenderDestination): Promise<void>;
|
||||
103
node_modules/astro/dist/runtime/server/render/queue/renderer.js
generated
vendored
Normal file
103
node_modules/astro/dist/runtime/server/render/queue/renderer.js
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
import { markHTMLString, escapeHTML } from "../../escape.js";
|
||||
import { chunkToString } from "../common.js";
|
||||
async function renderQueue(queue, destination) {
|
||||
const result = queue.result;
|
||||
const pool = queue.pool;
|
||||
const cache = queue.htmlStringCache;
|
||||
let batchBuffer = "";
|
||||
let i = 0;
|
||||
while (i < queue.nodes.length) {
|
||||
const node = queue.nodes[i];
|
||||
try {
|
||||
if (canBatch(node)) {
|
||||
const batchStart = i;
|
||||
while (i < queue.nodes.length && canBatch(queue.nodes[i])) {
|
||||
batchBuffer += renderNodeToString(queue.nodes[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
if (batchBuffer) {
|
||||
const htmlString = cache ? cache.getOrCreate(batchBuffer) : markHTMLString(batchBuffer);
|
||||
destination.write(htmlString);
|
||||
batchBuffer = "";
|
||||
}
|
||||
if (pool) {
|
||||
for (let j = batchStart; j < i; j++) {
|
||||
pool.release(queue.nodes[j]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await renderNode(node, destination, result);
|
||||
if (pool) {
|
||||
pool.release(node);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
if (batchBuffer) {
|
||||
const htmlString = cache ? cache.getOrCreate(batchBuffer) : markHTMLString(batchBuffer);
|
||||
destination.write(htmlString);
|
||||
}
|
||||
}
|
||||
function canBatch(node) {
|
||||
return node.type === "text" || node.type === "html-string";
|
||||
}
|
||||
function renderNodeToString(node) {
|
||||
switch (node.type) {
|
||||
case "text":
|
||||
return node.content ? escapeHTML(node.content) : "";
|
||||
case "html-string":
|
||||
return node.html || "";
|
||||
case "component":
|
||||
case "instruction": {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
async function renderNode(node, destination, result) {
|
||||
const cache = result._experimentalQueuedRendering?.htmlStringCache;
|
||||
switch (node.type) {
|
||||
case "text": {
|
||||
if (node.content) {
|
||||
const escaped = escapeHTML(node.content);
|
||||
const htmlString = cache ? cache.getOrCreate(escaped) : markHTMLString(escaped);
|
||||
destination.write(htmlString);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "html-string": {
|
||||
if (node.html) {
|
||||
const htmlString = cache ? cache.getOrCreate(node.html) : markHTMLString(node.html);
|
||||
destination.write(htmlString);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "instruction": {
|
||||
if (node.instruction) {
|
||||
destination.write(node.instruction);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "component": {
|
||||
if (node.instance) {
|
||||
let componentHtml = "";
|
||||
const componentDestination = {
|
||||
write(chunk) {
|
||||
if (chunk instanceof Response) return;
|
||||
componentHtml += chunkToString(result, chunk);
|
||||
}
|
||||
};
|
||||
await node.instance.render(componentDestination);
|
||||
if (componentHtml) {
|
||||
destination.write(componentHtml);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
export {
|
||||
renderQueue
|
||||
};
|
||||
81
node_modules/astro/dist/runtime/server/render/queue/types.d.ts
generated
vendored
Normal file
81
node_modules/astro/dist/runtime/server/render/queue/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
import type { SSRResult } from '../../../../types/public/internal.js';
|
||||
import type { AstroComponentInstance } from '../astro/instance.js';
|
||||
import type { RenderInstruction } from '../instruction.js';
|
||||
import type { ServerIslandComponent } from '../server-islands.js';
|
||||
import type { NodePool } from './pool.js';
|
||||
import type { HTMLStringCache } from '../../html-string-cache.js';
|
||||
/**
|
||||
* Text node containing plain text content that will be HTML-escaped during rendering
|
||||
*/
|
||||
export interface TextNode {
|
||||
type: 'text';
|
||||
content: string;
|
||||
}
|
||||
/**
|
||||
* HTML string node containing pre-rendered HTML markup that is already safe
|
||||
*/
|
||||
export interface HtmlStringNode {
|
||||
type: 'html-string';
|
||||
html: string;
|
||||
}
|
||||
/**
|
||||
* Component node containing an Astro component instance to be rendered
|
||||
*/
|
||||
export interface ComponentNode {
|
||||
type: 'component';
|
||||
instance: AstroComponentInstance | ServerIslandComponent;
|
||||
}
|
||||
/**
|
||||
* Instruction node containing rendering instructions (head content, hydration scripts, etc.)
|
||||
*/
|
||||
export interface InstructionNode {
|
||||
type: 'instruction';
|
||||
instruction: RenderInstruction;
|
||||
}
|
||||
/**
|
||||
* Discriminated union of all queue node types.
|
||||
* TypeScript will narrow the type based on the 'type' field.
|
||||
*/
|
||||
export type QueueNode = TextNode | HtmlStringNode | ComponentNode | InstructionNode;
|
||||
/**
|
||||
* The render queue containing all nodes to be rendered
|
||||
*/
|
||||
export interface RenderQueue {
|
||||
/**
|
||||
* All nodes in rendering order (after reversing the built queue)
|
||||
*/
|
||||
nodes: QueueNode[];
|
||||
/**
|
||||
* SSRResult context
|
||||
*/
|
||||
result: SSRResult;
|
||||
/**
|
||||
* Object pool instance used for node acquisition
|
||||
*/
|
||||
pool?: NodePool;
|
||||
/**
|
||||
* HTMLString cache instance for reducing memory allocations
|
||||
*/
|
||||
htmlStringCache?: HTMLStringCache;
|
||||
}
|
||||
/**
|
||||
* Stack item used during queue building (internal use only)
|
||||
*/
|
||||
export interface StackItem {
|
||||
/**
|
||||
* The value to process
|
||||
*/
|
||||
node: any;
|
||||
/**
|
||||
* Parent queue node (tracked but not used during rendering)
|
||||
*/
|
||||
parent: QueueNode | null;
|
||||
/**
|
||||
* Additional metadata passed through the stack (component props, slots, displayName)
|
||||
*/
|
||||
metadata?: {
|
||||
displayName?: string;
|
||||
props?: Record<string, any>;
|
||||
slots?: any;
|
||||
};
|
||||
}
|
||||
0
node_modules/astro/dist/runtime/server/render/queue/types.js
generated
vendored
Normal file
0
node_modules/astro/dist/runtime/server/render/queue/types.js
generated
vendored
Normal file
10
node_modules/astro/dist/runtime/server/render/script.d.ts
generated
vendored
Normal file
10
node_modules/astro/dist/runtime/server/render/script.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { SSRResult } from '../../../types/public/internal.js';
|
||||
/**
|
||||
* Relies on the `renderScript: true` compiler option
|
||||
* @experimental
|
||||
*/
|
||||
export declare function renderScript(result: SSRResult, id: string): Promise<{
|
||||
type: "script";
|
||||
id: string;
|
||||
content: string;
|
||||
}>;
|
||||
17
node_modules/astro/dist/runtime/server/render/script.js
generated
vendored
Normal file
17
node_modules/astro/dist/runtime/server/render/script.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createRenderInstruction } from "./instruction.js";
|
||||
async function renderScript(result, id) {
|
||||
const inlined = result.inlinedScripts.get(id);
|
||||
let content = "";
|
||||
if (inlined != null) {
|
||||
if (inlined) {
|
||||
content = `<script type="module">${inlined}</script>`;
|
||||
}
|
||||
} else {
|
||||
const resolved = await result.resolve(id);
|
||||
content = `<script type="module" src="${result.userAssetsBase ? (result.base === "/" ? "" : result.base) + result.userAssetsBase : ""}${resolved}"></script>`;
|
||||
}
|
||||
return createRenderInstruction({ type: "script", id, content });
|
||||
}
|
||||
export {
|
||||
renderScript
|
||||
};
|
||||
24
node_modules/astro/dist/runtime/server/render/server-islands.d.ts
generated
vendored
Normal file
24
node_modules/astro/dist/runtime/server/render/server-islands.d.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { SSRResult } from '../../../types/public/internal.js';
|
||||
import { type ThinHead } from './astro/head-and-content.js';
|
||||
import type { RenderDestination } from './common.js';
|
||||
import { type ComponentSlots } from './slot.js';
|
||||
export declare function containsServerDirective(props: Record<string | number, any>): boolean;
|
||||
export declare class ServerIslandComponent {
|
||||
result: SSRResult;
|
||||
props: Record<string | number, any>;
|
||||
slots: ComponentSlots;
|
||||
displayName: string;
|
||||
hostId: string | undefined;
|
||||
islandContent: string | undefined;
|
||||
componentPath: string | undefined;
|
||||
componentExport: string | undefined;
|
||||
componentId: string | undefined;
|
||||
constructor(result: SSRResult, props: Record<string | number, any>, slots: ComponentSlots, displayName: string);
|
||||
init(): Promise<ThinHead>;
|
||||
render(destination: RenderDestination): Promise<void>;
|
||||
getComponentPath(): string;
|
||||
getComponentExport(): string;
|
||||
getHostId(): Promise<string>;
|
||||
getIslandContent(): Promise<string>;
|
||||
}
|
||||
export declare const renderServerIslandRuntime: () => string;
|
||||
197
node_modules/astro/dist/runtime/server/render/server-islands.js
generated
vendored
Normal file
197
node_modules/astro/dist/runtime/server/render/server-islands.js
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
import { encryptString, generateCspDigest } from "../../../core/encryption.js";
|
||||
import { markHTMLString, stringifyForScript } from "../escape.js";
|
||||
import { renderChild } from "./any.js";
|
||||
import { createThinHead } from "./astro/head-and-content.js";
|
||||
import { createRenderInstruction } from "./instruction.js";
|
||||
import { renderSlotToString } from "./slot.js";
|
||||
const internalProps = /* @__PURE__ */ new Set([
|
||||
"server:component-path",
|
||||
"server:component-export",
|
||||
"server:component-directive",
|
||||
"server:defer"
|
||||
]);
|
||||
function containsServerDirective(props) {
|
||||
return "server:component-directive" in props;
|
||||
}
|
||||
function createSearchParams(encryptedComponentExport, encryptedProps, slots) {
|
||||
const params = new URLSearchParams();
|
||||
params.set("e", encryptedComponentExport);
|
||||
params.set("p", encryptedProps);
|
||||
params.set("s", slots);
|
||||
return params;
|
||||
}
|
||||
function isWithinURLLimit(pathname, params) {
|
||||
const url = pathname + "?" + params.toString();
|
||||
const chars = url.length;
|
||||
return chars < 2048;
|
||||
}
|
||||
class ServerIslandComponent {
|
||||
result;
|
||||
props;
|
||||
slots;
|
||||
displayName;
|
||||
hostId;
|
||||
islandContent;
|
||||
componentPath;
|
||||
componentExport;
|
||||
componentId;
|
||||
constructor(result, props, slots, displayName) {
|
||||
this.result = result;
|
||||
this.props = props;
|
||||
this.slots = slots;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
async init() {
|
||||
const content = await this.getIslandContent();
|
||||
if (this.result.cspDestination) {
|
||||
this.result._metadata.extraScriptHashes.push(
|
||||
await generateCspDigest(SERVER_ISLAND_REPLACER, this.result.cspAlgorithm)
|
||||
);
|
||||
const contentDigest = await generateCspDigest(content, this.result.cspAlgorithm);
|
||||
this.result._metadata.extraScriptHashes.push(contentDigest);
|
||||
}
|
||||
return createThinHead();
|
||||
}
|
||||
async render(destination) {
|
||||
const hostId = await this.getHostId();
|
||||
const islandContent = await this.getIslandContent();
|
||||
destination.write(createRenderInstruction({ type: "server-island-runtime" }));
|
||||
destination.write("<!--[if astro]>server-island-start<![endif]-->");
|
||||
for (const name in this.slots) {
|
||||
if (name === "fallback") {
|
||||
await renderChild(destination, this.slots.fallback(this.result));
|
||||
}
|
||||
}
|
||||
destination.write(
|
||||
`<script type="module" data-astro-rerun data-island-id="${hostId}">${islandContent}</script>`
|
||||
);
|
||||
}
|
||||
getComponentPath() {
|
||||
if (this.componentPath) {
|
||||
return this.componentPath;
|
||||
}
|
||||
const componentPath = this.props["server:component-path"];
|
||||
if (!componentPath) {
|
||||
throw new Error(`Could not find server component path`);
|
||||
}
|
||||
this.componentPath = componentPath;
|
||||
return componentPath;
|
||||
}
|
||||
getComponentExport() {
|
||||
if (this.componentExport) {
|
||||
return this.componentExport;
|
||||
}
|
||||
const componentExport = this.props["server:component-export"];
|
||||
if (!componentExport) {
|
||||
throw new Error(`Could not find server component export`);
|
||||
}
|
||||
this.componentExport = componentExport;
|
||||
return componentExport;
|
||||
}
|
||||
async getHostId() {
|
||||
if (!this.hostId) {
|
||||
this.hostId = await crypto.randomUUID();
|
||||
}
|
||||
return this.hostId;
|
||||
}
|
||||
async getIslandContent() {
|
||||
if (this.islandContent) {
|
||||
return this.islandContent;
|
||||
}
|
||||
const componentPath = this.getComponentPath();
|
||||
const componentExport = this.getComponentExport();
|
||||
let componentId = this.result.serverIslandNameMap.get(componentPath);
|
||||
if (!componentId) {
|
||||
throw new Error(`Could not find server component name ${componentPath}`);
|
||||
}
|
||||
for (const key2 of Object.keys(this.props)) {
|
||||
if (internalProps.has(key2)) {
|
||||
delete this.props[key2];
|
||||
}
|
||||
}
|
||||
const renderedSlots = {};
|
||||
for (const name in this.slots) {
|
||||
if (name !== "fallback") {
|
||||
const content = await renderSlotToString(this.result, this.slots[name]);
|
||||
let slotHtml = content.toString();
|
||||
const slotContent = content;
|
||||
if (Array.isArray(slotContent.instructions)) {
|
||||
for (const instruction of slotContent.instructions) {
|
||||
if (instruction.type === "script") {
|
||||
slotHtml += instruction.content;
|
||||
}
|
||||
}
|
||||
}
|
||||
renderedSlots[name] = slotHtml;
|
||||
}
|
||||
}
|
||||
const key = await this.result.key;
|
||||
const componentExportEncrypted = await encryptString(key, componentExport);
|
||||
const propsEncrypted = Object.keys(this.props).length === 0 ? "" : await encryptString(key, JSON.stringify(this.props));
|
||||
const slotsEncrypted = Object.keys(renderedSlots).length === 0 ? "" : await encryptString(key, JSON.stringify(renderedSlots));
|
||||
const hostId = await this.getHostId();
|
||||
const slash = this.result.base.endsWith("/") ? "" : "/";
|
||||
let serverIslandUrl = `${this.result.base}${slash}_server-islands/${componentId}${this.result.trailingSlash === "always" ? "/" : ""}`;
|
||||
const potentialSearchParams = createSearchParams(
|
||||
componentExportEncrypted,
|
||||
propsEncrypted,
|
||||
slotsEncrypted
|
||||
);
|
||||
const useGETRequest = isWithinURLLimit(serverIslandUrl, potentialSearchParams);
|
||||
if (useGETRequest) {
|
||||
serverIslandUrl += "?" + potentialSearchParams.toString();
|
||||
this.result._metadata.extraHead.push(
|
||||
markHTMLString(
|
||||
`<link rel="preload" as="fetch" href="${serverIslandUrl}" crossorigin="anonymous">`
|
||||
)
|
||||
);
|
||||
}
|
||||
const adapterHeaders = this.result.internalFetchHeaders || {};
|
||||
const headersJson = stringifyForScript(adapterHeaders);
|
||||
const method = useGETRequest ? (
|
||||
// GET request
|
||||
`const headers = new Headers(${headersJson});
|
||||
let response = await fetch('${serverIslandUrl}', { headers });`
|
||||
) : (
|
||||
// POST request
|
||||
`let data = {
|
||||
encryptedComponentExport: ${stringifyForScript(componentExportEncrypted)},
|
||||
encryptedProps: ${stringifyForScript(propsEncrypted)},
|
||||
encryptedSlots: ${stringifyForScript(slotsEncrypted)},
|
||||
};
|
||||
const headers = new Headers({ 'Content-Type': 'application/json', ...${headersJson} });
|
||||
let response = await fetch('${serverIslandUrl}', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
headers,
|
||||
});`
|
||||
);
|
||||
this.islandContent = `${method}replaceServerIsland('${hostId}', response);`;
|
||||
return this.islandContent;
|
||||
}
|
||||
}
|
||||
const renderServerIslandRuntime = () => {
|
||||
return `<script>${SERVER_ISLAND_REPLACER}</script>`;
|
||||
};
|
||||
const SERVER_ISLAND_REPLACER = markHTMLString(
|
||||
`async function replaceServerIsland(id, r) {
|
||||
let s = document.querySelector(\`script[data-island-id="\${id}"]\`);
|
||||
// If there's no matching script, or the request fails then return
|
||||
if (!s || r.status !== 200 || r.headers.get('content-type')?.split(';')[0].trim() !== 'text/html') return;
|
||||
// Load the HTML before modifying the DOM in case of errors
|
||||
let html = await r.text();
|
||||
// Remove any placeholder content before the island script
|
||||
while (s.previousSibling && s.previousSibling.nodeType !== 8 && s.previousSibling.data !== '[if astro]>server-island-start<![endif]')
|
||||
s.previousSibling.remove();
|
||||
s.previousSibling?.remove();
|
||||
// Insert the new HTML
|
||||
s.before(document.createRange().createContextualFragment(html));
|
||||
// Remove the script. Prior to v5.4.2, this was the trick to force rerun of scripts. Keeping it to minimize change to the existing behavior.
|
||||
s.remove();
|
||||
}`.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("//")).join(" ")
|
||||
);
|
||||
export {
|
||||
ServerIslandComponent,
|
||||
containsServerDirective,
|
||||
renderServerIslandRuntime
|
||||
};
|
||||
29
node_modules/astro/dist/runtime/server/render/slot.d.ts
generated
vendored
Normal file
29
node_modules/astro/dist/runtime/server/render/slot.d.ts
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { SSRResult } from '../../../types/public/internal.js';
|
||||
import { HTMLString } from '../escape.js';
|
||||
import { renderTemplate } from './astro/render-template.js';
|
||||
import { type RenderInstance } from './common.js';
|
||||
import type { RenderInstruction } from './instruction.js';
|
||||
type RenderTemplateResult = ReturnType<typeof renderTemplate>;
|
||||
export type ComponentSlots = Record<string, ComponentSlotValue>;
|
||||
export type ComponentSlotValue = (result: SSRResult) => RenderTemplateResult | Promise<RenderTemplateResult>;
|
||||
declare const slotString: unique symbol;
|
||||
export declare class SlotString extends HTMLString {
|
||||
instructions: null | RenderInstruction[];
|
||||
[slotString]: boolean;
|
||||
constructor(content: string, instructions: null | RenderInstruction[]);
|
||||
}
|
||||
export declare function isSlotString(str: string): str is any;
|
||||
/**
|
||||
* Collects instructions from a SlotString into the target array.
|
||||
* Returns the (possibly newly created) instructions array.
|
||||
*/
|
||||
export declare function mergeSlotInstructions(target: RenderInstruction[] | null, source: SlotString): RenderInstruction[] | null;
|
||||
export declare function renderSlot(result: SSRResult, slotted: ComponentSlotValue | RenderTemplateResult, fallback?: ComponentSlotValue | RenderTemplateResult): RenderInstance;
|
||||
export declare function renderSlotToString(result: SSRResult, slotted: ComponentSlotValue | RenderTemplateResult, fallback?: ComponentSlotValue | RenderTemplateResult): Promise<string>;
|
||||
interface RenderSlotsResult {
|
||||
slotInstructions: null | RenderInstruction[];
|
||||
children: Record<string, string>;
|
||||
}
|
||||
export declare function renderSlots(result: SSRResult, slots?: ComponentSlots): Promise<RenderSlotsResult>;
|
||||
export declare function createSlotValueFromString(content: string): ComponentSlotValue;
|
||||
export {};
|
||||
91
node_modules/astro/dist/runtime/server/render/slot.js
generated
vendored
Normal file
91
node_modules/astro/dist/runtime/server/render/slot.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
import { HTMLString, markHTMLString, unescapeHTML } from "../escape.js";
|
||||
import { renderChild } from "./any.js";
|
||||
import { renderTemplate } from "./astro/render-template.js";
|
||||
import { chunkToString } from "./common.js";
|
||||
const slotString = /* @__PURE__ */ Symbol.for("astro:slot-string");
|
||||
class SlotString extends HTMLString {
|
||||
instructions;
|
||||
[slotString];
|
||||
constructor(content, instructions) {
|
||||
super(content);
|
||||
this.instructions = instructions;
|
||||
this[slotString] = true;
|
||||
}
|
||||
}
|
||||
function isSlotString(str) {
|
||||
return !!str[slotString];
|
||||
}
|
||||
function mergeSlotInstructions(target, source) {
|
||||
if (source.instructions?.length) {
|
||||
target ??= [];
|
||||
target.push(...source.instructions);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
function renderSlot(result, slotted, fallback) {
|
||||
if (!slotted && fallback) {
|
||||
return renderSlot(result, fallback);
|
||||
}
|
||||
return {
|
||||
async render(destination) {
|
||||
await renderChild(destination, typeof slotted === "function" ? slotted(result) : slotted);
|
||||
}
|
||||
};
|
||||
}
|
||||
async function renderSlotToString(result, slotted, fallback) {
|
||||
let content = "";
|
||||
let instructions = null;
|
||||
const temporaryDestination = {
|
||||
write(chunk) {
|
||||
if (chunk instanceof SlotString) {
|
||||
content += chunk;
|
||||
instructions = mergeSlotInstructions(instructions, chunk);
|
||||
} else if (chunk instanceof Response) return;
|
||||
else if (typeof chunk === "object" && "type" in chunk && typeof chunk.type === "string") {
|
||||
if (instructions === null) {
|
||||
instructions = [];
|
||||
}
|
||||
instructions.push(chunk);
|
||||
} else {
|
||||
content += chunkToString(result, chunk);
|
||||
}
|
||||
}
|
||||
};
|
||||
const renderInstance = renderSlot(result, slotted, fallback);
|
||||
await renderInstance.render(temporaryDestination);
|
||||
return markHTMLString(new SlotString(content, instructions));
|
||||
}
|
||||
async function renderSlots(result, slots = {}) {
|
||||
let slotInstructions = null;
|
||||
let children = {};
|
||||
if (slots) {
|
||||
await Promise.all(
|
||||
Object.entries(slots).map(
|
||||
([key, value]) => renderSlotToString(result, value).then((output) => {
|
||||
if (output.instructions) {
|
||||
if (slotInstructions === null) {
|
||||
slotInstructions = [];
|
||||
}
|
||||
slotInstructions.push(...output.instructions);
|
||||
}
|
||||
children[key] = output;
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
return { slotInstructions, children };
|
||||
}
|
||||
function createSlotValueFromString(content) {
|
||||
return function() {
|
||||
return renderTemplate`${unescapeHTML(content)}`;
|
||||
};
|
||||
}
|
||||
export {
|
||||
SlotString,
|
||||
createSlotValueFromString,
|
||||
isSlotString,
|
||||
mergeSlotInstructions,
|
||||
renderSlot,
|
||||
renderSlotToString,
|
||||
renderSlots
|
||||
};
|
||||
4
node_modules/astro/dist/runtime/server/render/tags.d.ts
generated
vendored
Normal file
4
node_modules/astro/dist/runtime/server/render/tags.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { StylesheetAsset } from '../../../core/app/types.js';
|
||||
import type { SSRElement, SSRResult } from '../../../types/public/internal.js';
|
||||
export declare function renderScriptElement({ props, children }: SSRElement): string;
|
||||
export declare function renderUniqueStylesheet(result: SSRResult, sheet: StylesheetAsset): string | undefined;
|
||||
21
node_modules/astro/dist/runtime/server/render/tags.js
generated
vendored
Normal file
21
node_modules/astro/dist/runtime/server/render/tags.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import { renderElement } from "./util.js";
|
||||
function renderScriptElement({ props, children }) {
|
||||
return renderElement("script", {
|
||||
props,
|
||||
children
|
||||
});
|
||||
}
|
||||
function renderUniqueStylesheet(result, sheet) {
|
||||
if (sheet.type === "external") {
|
||||
if (Array.from(result.styles).some((s) => s.props.href === sheet.src)) return "";
|
||||
return renderElement("link", { props: { rel: "stylesheet", href: sheet.src }, children: "" });
|
||||
}
|
||||
if (sheet.type === "inline") {
|
||||
if (Array.from(result.styles).some((s) => s.children.includes(sheet.content))) return "";
|
||||
return renderElement("style", { props: {}, children: sheet.content });
|
||||
}
|
||||
}
|
||||
export {
|
||||
renderScriptElement,
|
||||
renderUniqueStylesheet
|
||||
};
|
||||
46
node_modules/astro/dist/runtime/server/render/util.d.ts
generated
vendored
Normal file
46
node_modules/astro/dist/runtime/server/render/util.d.ts
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { SSRElement } from '../../../types/public/internal.js';
|
||||
import type { RenderDestination, RenderFunction } from './common.js';
|
||||
export declare const voidElementNames: RegExp;
|
||||
export declare const toAttributeString: (value: any, shouldEscape?: boolean) => any;
|
||||
export declare const toStyleString: (obj: Record<string, any>) => string;
|
||||
export declare function defineScriptVars(vars: Record<any, any>): any;
|
||||
export declare function formatList(values: string[]): string;
|
||||
export declare function addAttribute(value: any, key: string, shouldEscape?: boolean, tagName?: string): any;
|
||||
export declare function internalSpreadAttributes(values: Record<any, any>, shouldEscape: boolean | undefined, tagName: string): any;
|
||||
export declare function renderElement(name: string, { props: _props, children }: SSRElement, shouldEscape?: boolean): string;
|
||||
/**
|
||||
* Executes the `bufferRenderFunction` to prerender it into a buffer destination, and return a promise
|
||||
* with an object containing the `flush` function to flush the buffer to the final
|
||||
* destination.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Render components in parallel ahead of time
|
||||
* const finalRenders = [ComponentA, ComponentB].map((comp) => {
|
||||
* return createBufferedRenderer(finalDestination, async (bufferDestination) => {
|
||||
* await renderComponentToDestination(bufferDestination);
|
||||
* });
|
||||
* });
|
||||
* // Render array of components serially
|
||||
* for (const finalRender of finalRenders) {
|
||||
* await finalRender.flush();
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export declare function createBufferedRenderer(destination: RenderDestination, renderFunction: RenderFunction): RendererFlusher;
|
||||
export interface RendererFlusher {
|
||||
/**
|
||||
* Flushes the current renderer to the underlying renderer.
|
||||
*
|
||||
* See example of `createBufferedRenderer` for usage.
|
||||
*/
|
||||
flush(): void | Promise<void>;
|
||||
}
|
||||
export declare const isNode: boolean;
|
||||
export declare const isDeno: boolean;
|
||||
export type PromiseWithResolvers<T> = {
|
||||
promise: Promise<T>;
|
||||
resolve: (value: T) => void;
|
||||
reject: (reason?: any) => void;
|
||||
};
|
||||
export declare function promiseWithResolvers<T = any>(): PromiseWithResolvers<T>;
|
||||
179
node_modules/astro/dist/runtime/server/render/util.js
generated
vendored
Normal file
179
node_modules/astro/dist/runtime/server/render/util.js
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
import { clsx } from "clsx";
|
||||
import { HTMLString, markHTMLString, stringifyForScript } from "../escape.js";
|
||||
import { isPromise } from "../util.js";
|
||||
const voidElementNames = /^(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/i;
|
||||
const htmlBooleanAttributes = /^(?:allowfullscreen|async|autofocus|autoplay|checked|controls|default|defer|disabled|disablepictureinpicture|disableremoteplayback|formnovalidate|inert|loop|muted|nomodule|novalidate|open|playsinline|readonly|required|reversed|scoped|seamless|selected|itemscope)$/i;
|
||||
const AMPERSAND_REGEX = /&/g;
|
||||
const DOUBLE_QUOTE_REGEX = /"/g;
|
||||
const STATIC_DIRECTIVES = /* @__PURE__ */ new Set(["set:html", "set:text"]);
|
||||
const toIdent = (k) => k.trim().replace(/(?!^)\b\w|\s+|\W+/g, (match, index) => {
|
||||
if (/\W/.test(match)) return "";
|
||||
return index === 0 ? match : match.toUpperCase();
|
||||
});
|
||||
const toAttributeString = (value, shouldEscape = true) => shouldEscape ? String(value).replace(AMPERSAND_REGEX, "&").replace(DOUBLE_QUOTE_REGEX, """) : value;
|
||||
const kebab = (k) => k.toLowerCase() === k ? k : k.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
||||
const toStyleString = (obj) => Object.entries(obj).filter(([_, v]) => typeof v === "string" && v.trim() || typeof v === "number").map(([k, v]) => {
|
||||
if (k[0] !== "-" && k[1] !== "-") return `${kebab(k)}:${v}`;
|
||||
return `${k}:${v}`;
|
||||
}).join(";");
|
||||
function defineScriptVars(vars) {
|
||||
let output = "";
|
||||
for (const [key, value] of Object.entries(vars)) {
|
||||
output += `const ${toIdent(key)} = ${stringifyForScript(value)};
|
||||
`;
|
||||
}
|
||||
return markHTMLString(output);
|
||||
}
|
||||
function formatList(values) {
|
||||
if (values.length === 1) {
|
||||
return values[0];
|
||||
}
|
||||
return `${values.slice(0, -1).join(", ")} or ${values[values.length - 1]}`;
|
||||
}
|
||||
function isCustomElement(tagName) {
|
||||
return tagName.includes("-");
|
||||
}
|
||||
function handleBooleanAttribute(key, value, shouldEscape, tagName) {
|
||||
if (tagName && isCustomElement(tagName)) {
|
||||
return markHTMLString(` ${key}="${toAttributeString(value, shouldEscape)}"`);
|
||||
}
|
||||
return markHTMLString(value ? ` ${key}` : "");
|
||||
}
|
||||
function addAttribute(value, key, shouldEscape = true, tagName = "") {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
if (STATIC_DIRECTIVES.has(key)) {
|
||||
console.warn(`[astro] The "${key}" directive cannot be applied dynamically at runtime. It will not be rendered as an attribute.
|
||||
|
||||
Make sure to use the static attribute syntax (\`${key}={value}\`) instead of the dynamic spread syntax (\`{...{ "${key}": value }}\`).`);
|
||||
return "";
|
||||
}
|
||||
if (key === "class:list") {
|
||||
const listValue = toAttributeString(clsx(value), shouldEscape);
|
||||
if (listValue === "") {
|
||||
return "";
|
||||
}
|
||||
return markHTMLString(` ${key.slice(0, -5)}="${listValue}"`);
|
||||
}
|
||||
if (key === "style" && !(value instanceof HTMLString)) {
|
||||
if (Array.isArray(value) && value.length === 2) {
|
||||
return markHTMLString(
|
||||
` ${key}="${toAttributeString(`${toStyleString(value[0])};${value[1]}`, shouldEscape)}"`
|
||||
);
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
return markHTMLString(` ${key}="${toAttributeString(toStyleString(value), shouldEscape)}"`);
|
||||
}
|
||||
}
|
||||
if (key === "className") {
|
||||
return markHTMLString(` class="${toAttributeString(value, shouldEscape)}"`);
|
||||
}
|
||||
if (htmlBooleanAttributes.test(key)) {
|
||||
return handleBooleanAttribute(key, value, shouldEscape, tagName);
|
||||
}
|
||||
if (value === "") {
|
||||
return markHTMLString(` ${key}`);
|
||||
}
|
||||
if (key === "popover" && typeof value === "boolean") {
|
||||
return handleBooleanAttribute(key, value, shouldEscape, tagName);
|
||||
}
|
||||
if (key === "download" && typeof value === "boolean") {
|
||||
return handleBooleanAttribute(key, value, shouldEscape, tagName);
|
||||
}
|
||||
if (key === "hidden" && typeof value === "boolean") {
|
||||
return handleBooleanAttribute(key, value, shouldEscape, tagName);
|
||||
}
|
||||
return markHTMLString(` ${key}="${toAttributeString(value, shouldEscape)}"`);
|
||||
}
|
||||
function internalSpreadAttributes(values, shouldEscape = true, tagName) {
|
||||
let output = "";
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
output += addAttribute(value, key, shouldEscape, tagName);
|
||||
}
|
||||
return markHTMLString(output);
|
||||
}
|
||||
function renderElement(name, { props: _props, children = "" }, shouldEscape = true) {
|
||||
const { lang: _, "data-astro-id": astroId, "define:vars": defineVars, ...props } = _props;
|
||||
if (defineVars) {
|
||||
if (name === "style") {
|
||||
delete props["is:global"];
|
||||
delete props["is:scoped"];
|
||||
}
|
||||
if (name === "script") {
|
||||
delete props.hoist;
|
||||
children = defineScriptVars(defineVars) + "\n" + children;
|
||||
}
|
||||
}
|
||||
if ((children == null || children === "") && voidElementNames.test(name)) {
|
||||
return `<${name}${internalSpreadAttributes(props, shouldEscape, name)}>`;
|
||||
}
|
||||
return `<${name}${internalSpreadAttributes(props, shouldEscape, name)}>${children}</${name}>`;
|
||||
}
|
||||
const noop = () => {
|
||||
};
|
||||
class BufferedRenderer {
|
||||
chunks = [];
|
||||
renderPromise;
|
||||
destination;
|
||||
/**
|
||||
* Determines whether buffer has been flushed
|
||||
* to the final destination.
|
||||
*/
|
||||
flushed = false;
|
||||
constructor(destination, renderFunction) {
|
||||
this.destination = destination;
|
||||
this.renderPromise = renderFunction(this);
|
||||
if (isPromise(this.renderPromise)) {
|
||||
Promise.resolve(this.renderPromise).catch(noop);
|
||||
}
|
||||
}
|
||||
write(chunk) {
|
||||
if (this.flushed) {
|
||||
this.destination.write(chunk);
|
||||
} else {
|
||||
this.chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
flush() {
|
||||
if (this.flushed) {
|
||||
throw new Error("The render buffer has already been flushed.");
|
||||
}
|
||||
this.flushed = true;
|
||||
for (const chunk of this.chunks) {
|
||||
this.destination.write(chunk);
|
||||
}
|
||||
return this.renderPromise;
|
||||
}
|
||||
}
|
||||
function createBufferedRenderer(destination, renderFunction) {
|
||||
return new BufferedRenderer(destination, renderFunction);
|
||||
}
|
||||
const isNode = typeof process !== "undefined" && Object.prototype.toString.call(process) === "[object process]";
|
||||
const isDeno = typeof Deno !== "undefined";
|
||||
function promiseWithResolvers() {
|
||||
let resolve, reject;
|
||||
const promise = new Promise((_resolve, _reject) => {
|
||||
resolve = _resolve;
|
||||
reject = _reject;
|
||||
});
|
||||
return {
|
||||
promise,
|
||||
resolve,
|
||||
reject
|
||||
};
|
||||
}
|
||||
export {
|
||||
addAttribute,
|
||||
createBufferedRenderer,
|
||||
defineScriptVars,
|
||||
formatList,
|
||||
internalSpreadAttributes,
|
||||
isDeno,
|
||||
isNode,
|
||||
promiseWithResolvers,
|
||||
renderElement,
|
||||
toAttributeString,
|
||||
toStyleString,
|
||||
voidElementNames
|
||||
};
|
||||
Reference in New Issue
Block a user