aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/astro/src/@types/astro.ts4
-rw-r--r--packages/astro/src/runtime/server/astro-island.prebuilt.ts2
-rw-r--r--packages/astro/src/runtime/server/astro-island.ts124
-rw-r--r--packages/astro/src/runtime/server/hydration.ts23
-rw-r--r--packages/astro/src/runtime/server/index.ts19
-rw-r--r--packages/astro/src/runtime/server/serialize.ts12
-rw-r--r--scripts/cmd/prebuild.js6
7 files changed, 92 insertions, 98 deletions
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index 1c661343a..5c398566c 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -772,9 +772,7 @@ export interface MarkdownInstance<T extends Record<string, any>> {
}>;
}
-export type GetHydrateCallback = () => Promise<
- () => void | Promise<void>
->;
+export type GetHydrateCallback = () => Promise<() => void | Promise<void>>;
/**
* getStaticPaths() options
diff --git a/packages/astro/src/runtime/server/astro-island.prebuilt.ts b/packages/astro/src/runtime/server/astro-island.prebuilt.ts
index 0ac881edf..d7204bbe8 100644
--- a/packages/astro/src/runtime/server/astro-island.prebuilt.ts
+++ b/packages/astro/src/runtime/server/astro-island.prebuilt.ts
@@ -4,4 +4,4 @@
* to generate this file.
*/
-export default `var a;{const o={0:t=>t,1:t=>JSON.parse(t,n),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(JSON.parse(t,n)),5:t=>new Set(JSON.parse(t,n)),6:t=>BigInt(t),7:t=>new URL(t)},n=(t,e)=>{if(t===""||!Array.isArray(e))return e;const[r,s]=e;return r in o?o[r](s):void 0};customElements.get("astro-island")||customElements.define("astro-island",(a=class extends HTMLElement{constructor(){super(...arguments);this.hydrate=()=>{if(!this.hydrator||this.parentElement?.closest("astro-island[ssr]"))return;let e=null,r=this.querySelector("astro-fragment");if(r==null&&this.hasAttribute("tmpl")){let i=this.querySelector("template[data-astro-template]");i&&(e=i.innerHTML,i.remove())}else r&&(e=r.innerHTML);const s=this.hasAttribute("props")?JSON.parse(this.getAttribute("props"),n):{};this.hydrator(this)(this.Component,s,e,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),window.removeEventListener("astro:hydrate",this.hydrate),window.dispatchEvent(new CustomEvent("astro:hydrate"))}}async connectedCallback(){const[{default:e}]=await Promise.all([import(this.getAttribute("directive-url")),import(this.getAttribute("before-hydration-url"))]);window.addEventListener("astro:hydrate",this.hydrate);const r=JSON.parse(this.getAttribute("opts"));e(this,r,async()=>{const s=this.getAttribute("renderer-url"),[i,{default:l}]=await Promise.all([import(this.getAttribute("component-url")),s?import(s):()=>()=>{}]);return this.Component=i[this.getAttribute("component-export")||"default"],this.hydrator=l,this.hydrate})}attributeChangedCallback(){this.hydrator&&this.hydrate()}},a.observedAttributes=["props"],a))}`; \ No newline at end of file
+export default `var a;{const o={0:t=>t,1:t=>JSON.parse(t,n),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(JSON.parse(t,n)),5:t=>new Set(JSON.parse(t,n)),6:t=>BigInt(t),7:t=>new URL(t)},n=(t,e)=>{if(t===""||!Array.isArray(e))return e;const[r,s]=e;return r in o?o[r](s):void 0};customElements.get("astro-island")||customElements.define("astro-island",(a=class extends HTMLElement{constructor(){super(...arguments);this.hydrate=()=>{if(!this.hydrator||this.parentElement?.closest("astro-island[ssr]"))return;let e=null,r=this.querySelector("astro-fragment");if(r==null&&this.hasAttribute("tmpl")){let i=this.querySelector("template[data-astro-template]");i&&(e=i.innerHTML,i.remove())}else r&&(e=r.innerHTML);const s=this.hasAttribute("props")?JSON.parse(this.getAttribute("props"),n):{};this.hydrator(this)(this.Component,s,e,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),window.removeEventListener("astro:hydrate",this.hydrate),window.dispatchEvent(new CustomEvent("astro:hydrate"))}}async connectedCallback(){const[{default:e}]=await Promise.all([import(this.getAttribute("directive-url")),import(this.getAttribute("before-hydration-url"))]);window.addEventListener("astro:hydrate",this.hydrate);const r=JSON.parse(this.getAttribute("opts"));e(this,r,async()=>{const s=this.getAttribute("renderer-url"),[i,{default:l}]=await Promise.all([import(this.getAttribute("component-url")),s?import(s):()=>()=>{}]);return this.Component=i[this.getAttribute("component-export")||"default"],this.hydrator=l,this.hydrate})}attributeChangedCallback(){this.hydrator&&this.hydrate()}},a.observedAttributes=["props"],a))}`;
diff --git a/packages/astro/src/runtime/server/astro-island.ts b/packages/astro/src/runtime/server/astro-island.ts
index cd93854dc..365da6ae3 100644
--- a/packages/astro/src/runtime/server/astro-island.ts
+++ b/packages/astro/src/runtime/server/astro-island.ts
@@ -8,77 +8,79 @@
}
const propTypes: PropTypeSelector = {
- 0: value => value,
- 1: value => JSON.parse(value, reviver),
- 2: value => new RegExp(value),
- 3: value => new Date(value),
- 4: value => new Map(JSON.parse(value, reviver)),
- 5: value => new Set(JSON.parse(value, reviver)),
- 6: value => BigInt(value),
- 7: value => new URL(value),
+ 0: (value) => value,
+ 1: (value) => JSON.parse(value, reviver),
+ 2: (value) => new RegExp(value),
+ 3: (value) => new Date(value),
+ 4: (value) => new Map(JSON.parse(value, reviver)),
+ 5: (value) => new Set(JSON.parse(value, reviver)),
+ 6: (value) => BigInt(value),
+ 7: (value) => new URL(value),
};
const reviver = (propKey: string, raw: string): any => {
- if(propKey === '' || !Array.isArray(raw)) return raw;
+ if (propKey === '' || !Array.isArray(raw)) return raw;
const [type, value] = raw;
- return (type in propTypes) ? propTypes[type](value) : undefined;
+ return type in propTypes ? propTypes[type](value) : undefined;
};
- if(!customElements.get('astro-island')) {
- customElements.define('astro-island', class extends HTMLElement {
- public Component: any;
- public hydrator: any;
- static observedAttributes = ['props'];
- async connectedCallback(){
- const [ { default: setup } ] = await Promise.all([
- import(this.getAttribute('directive-url')!),
- import(this.getAttribute('before-hydration-url')!)
- ]);
- window.addEventListener('astro:hydrate', this.hydrate);
-
- const opts = JSON.parse(this.getAttribute('opts')!);
- setup(this, opts, async () => {
- const rendererUrl = this.getAttribute('renderer-url');
- const [
- componentModule,
- { default: hydrator }
- ] = await Promise.all([
- import(this.getAttribute('component-url')!),
- rendererUrl ? import(rendererUrl) : () => () => {}
+ if (!customElements.get('astro-island')) {
+ customElements.define(
+ 'astro-island',
+ class extends HTMLElement {
+ public Component: any;
+ public hydrator: any;
+ static observedAttributes = ['props'];
+ async connectedCallback() {
+ const [{ default: setup }] = await Promise.all([
+ import(this.getAttribute('directive-url')!),
+ import(this.getAttribute('before-hydration-url')!),
]);
- this.Component = componentModule[this.getAttribute('component-export') || 'default'];
- this.hydrator = hydrator;
- return this.hydrate;
- });
- }
- hydrate = () => {
- if(!this.hydrator || this.parentElement?.closest('astro-island[ssr]')) {
- return;
+ window.addEventListener('astro:hydrate', this.hydrate);
+
+ const opts = JSON.parse(this.getAttribute('opts')!);
+ setup(this, opts, async () => {
+ const rendererUrl = this.getAttribute('renderer-url');
+ const [componentModule, { default: hydrator }] = await Promise.all([
+ import(this.getAttribute('component-url')!),
+ rendererUrl ? import(rendererUrl) : () => () => {},
+ ]);
+ this.Component = componentModule[this.getAttribute('component-export') || 'default'];
+ this.hydrator = hydrator;
+ return this.hydrate;
+ });
}
- let innerHTML: string | null = null;
- let fragment = this.querySelector('astro-fragment');
- if (fragment == null && this.hasAttribute('tmpl')) {
- // If there is no child fragment, check to see if there is a template.
- // This happens if children were passed but the client component did not render any.
- let template = this.querySelector('template[data-astro-template]');
- if (template) {
- innerHTML = template.innerHTML;
- template.remove();
+ hydrate = () => {
+ if (!this.hydrator || this.parentElement?.closest('astro-island[ssr]')) {
+ return;
}
- } else if (fragment) {
- innerHTML = fragment.innerHTML;
+ let innerHTML: string | null = null;
+ let fragment = this.querySelector('astro-fragment');
+ if (fragment == null && this.hasAttribute('tmpl')) {
+ // If there is no child fragment, check to see if there is a template.
+ // This happens if children were passed but the client component did not render any.
+ let template = this.querySelector('template[data-astro-template]');
+ if (template) {
+ innerHTML = template.innerHTML;
+ template.remove();
+ }
+ } else if (fragment) {
+ innerHTML = fragment.innerHTML;
+ }
+ const props = this.hasAttribute('props')
+ ? JSON.parse(this.getAttribute('props')!, reviver)
+ : {};
+ this.hydrator(this)(this.Component, props, innerHTML, {
+ client: this.getAttribute('client'),
+ });
+ this.removeAttribute('ssr');
+ window.removeEventListener('astro:hydrate', this.hydrate);
+ window.dispatchEvent(new CustomEvent('astro:hydrate'));
+ };
+ attributeChangedCallback() {
+ if (this.hydrator) this.hydrate();
}
- const props = this.hasAttribute('props') ? JSON.parse(this.getAttribute('props')!, reviver) : {};
- this.hydrator(this)(this.Component, props, innerHTML, {
- client: this.getAttribute('client')
- });
- this.removeAttribute('ssr');
- window.removeEventListener('astro:hydrate', this.hydrate);
- window.dispatchEvent(new CustomEvent('astro:hydrate'));
- }
- attributeChangedCallback() {
- if(this.hydrator) this.hydrate();
}
- });
+ );
}
}
diff --git a/packages/astro/src/runtime/server/hydration.ts b/packages/astro/src/runtime/server/hydration.ts
index 90a9d7b7d..9f05152b8 100644
--- a/packages/astro/src/runtime/server/hydration.ts
+++ b/packages/astro/src/runtime/server/hydration.ts
@@ -5,8 +5,8 @@ import type {
SSRResult,
} from '../../@types/astro';
import { escapeHTML } from './escape.js';
-import { hydrationSpecifier, serializeListValue } from './util.js';
import { serializeProps } from './serialize.js';
+import { hydrationSpecifier, serializeListValue } from './util.js';
const HydrationDirectives = ['load', 'idle', 'media', 'visible', 'only'];
@@ -95,11 +95,6 @@ interface HydrateScriptOptions {
props: Record<string | number, any>;
}
-
-
-
-
-
/** For hydrated components, generate a <script type="module"> to load the component */
export async function generateHydrateScript(
scriptOptions: HydrateScriptOptions,
@@ -118,15 +113,15 @@ export async function generateHydrateScript(
children: '',
props: {
// This is for HMR, probably can avoid it in prod
- uid: astroId
- }
+ uid: astroId,
+ },
};
// Add component url
island.props['component-url'] = await result.resolve(componentUrl);
// Add renderer url
- if(renderer.clientEntrypoint) {
+ if (renderer.clientEntrypoint) {
island.props['component-export'] = componentExport.value;
island.props['renderer-url'] = await result.resolve(renderer.clientEntrypoint);
island.props['props'] = escapeHTML(serializeProps(props));
@@ -136,10 +131,12 @@ export async function generateHydrateScript(
island.props['client'] = hydrate;
island.props['directive-url'] = await result.resolve(hydrationSpecifier(hydrate));
island.props['before-hydration-url'] = await result.resolve('astro:scripts/before-hydration.js');
- island.props['opts'] = escapeHTML(JSON.stringify({
- name: metadata.displayName,
- value: metadata.hydrateArgs || ''
- }))
+ island.props['opts'] = escapeHTML(
+ JSON.stringify({
+ name: metadata.displayName,
+ value: metadata.hydrateArgs || '',
+ })
+ );
return island;
}
diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts
index e06b5fedf..7bd60aba4 100644
--- a/packages/astro/src/runtime/server/index.ts
+++ b/packages/astro/src/runtime/server/index.ts
@@ -8,12 +8,12 @@ import type {
SSRLoadedRenderer,
SSRResult,
} from '../../@types/astro';
+import islandScript from './astro-island.prebuilt.js';
import { escapeHTML, HTMLString, markHTMLString } from './escape.js';
import { extractDirectives, generateHydrateScript } from './hydration.js';
+import { serializeProps } from './serialize.js';
import { shorthash } from './shorthash.js';
import { serializeListValue } from './util.js';
-import islandScript from './astro-island.prebuilt.js';
-import { serializeProps } from './serialize.js';
export { markHTMLString, markHTMLString as unescapeHTML } from './escape.js';
export type { Metadata } from './metadata';
@@ -33,7 +33,7 @@ const svgEnumAttributes = /^(autoReverse|externalResourcesRequired|focusable|pre
const resultsWithHydrationScript = new WeakSet<SSRResult>();
function determineIfNeedsHydrationScript(result: SSRResult): boolean {
- if(resultsWithHydrationScript.has(result)) {
+ if (resultsWithHydrationScript.has(result)) {
return false;
}
resultsWithHydrationScript.add(result);
@@ -342,19 +342,17 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
const needsAstroTemplate = children && !/<\/?astro-fragment\>/.test(html);
const template = needsAstroTemplate ? `<template data-astro-template>${children}</template>` : '';
- if(needsAstroTemplate) {
+ if (needsAstroTemplate) {
island.props.tmpl = '';
}
- island.children = `${
- html ?? ''
- }${template}`;
+ island.children = `${html ?? ''}${template}`;
// Add the astro-island definition only once. Since the SSRResult object
// is scoped to a page renderer we can use it as a key to know if the script
// has been rendered or not.
let script = '';
- if(needsHydrationScript) {
+ if (needsHydrationScript) {
// Note that this is a class script, not a module script.
// This is so that it executes immediate, and when the browser encounters
// an astro-island element the callbacks will fire immediately, causing the JS
@@ -362,10 +360,7 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
script = `<script>${islandScript}</script>`;
}
- return markHTMLString(
- script +
- renderElement('astro-island', island, false)
- );
+ return markHTMLString(script + renderElement('astro-island', island, false));
}
/** Create the Astro.fetchContent() runtime function. */
diff --git a/packages/astro/src/runtime/server/serialize.ts b/packages/astro/src/runtime/server/serialize.ts
index d101e2f74..d15b22ea4 100644
--- a/packages/astro/src/runtime/server/serialize.ts
+++ b/packages/astro/src/runtime/server/serialize.ts
@@ -16,14 +16,16 @@ function serializeArray(value: any[]): any[] {
}
function serializeObject(value: Record<any, any>): Record<any, any> {
- return Object.fromEntries(Object.entries(value).map(([k, v]) => {
- return [k, convertToSerializedForm(v)];
- }));
+ return Object.fromEntries(
+ Object.entries(value).map(([k, v]) => {
+ return [k, convertToSerializedForm(v)];
+ })
+ );
}
function convertToSerializedForm(value: any): [ValueOf<typeof PROP_TYPE>, any] {
const tag = Object.prototype.toString.call(value);
- switch(tag) {
+ switch (tag) {
case '[object Date]': {
return [PROP_TYPE.Date, (value as Date).toISOString()];
}
@@ -46,7 +48,7 @@ function convertToSerializedForm(value: any): [ValueOf<typeof PROP_TYPE>, any] {
return [PROP_TYPE.JSON, JSON.stringify(serializeArray(value))];
}
default: {
- if(typeof value === 'object') {
+ if (typeof value === 'object') {
return [PROP_TYPE.Value, serializeObject(value)];
} else {
return [PROP_TYPE.Value, value];
diff --git a/scripts/cmd/prebuild.js b/scripts/cmd/prebuild.js
index 7f8733cfe..4a67babe2 100644
--- a/scripts/cmd/prebuild.js
+++ b/scripts/cmd/prebuild.js
@@ -7,7 +7,7 @@ import { pathToFileURL, fileURLToPath } from 'url';
export default async function prebuild(...args) {
let buildToString = args.indexOf('--to-string');
- if(buildToString !== -1) {
+ if (buildToString !== -1) {
args.splice(buildToString, 1);
buildToString = true;
}
@@ -33,10 +33,10 @@ export default async function prebuild(...args) {
const tscode = await fs.promises.readFile(filepath, 'utf-8');
const esbuildresult = await esbuild.transform(tscode, {
loader: 'ts',
- minify: true
+ minify: true,
});
const rootURL = new URL('../../', import.meta.url);
- const rel = path.relative(fileURLToPath(rootURL), filepath)
+ const rel = path.relative(fileURLToPath(rootURL), filepath);
const mod = `/**
* This file is prebuilt from ${rel}
* Do not edit this directly, but instead edit that file and rerun the prebuild