fix: store hydration meta info in local variable

This commit is contained in:
Nate Moore 2023-08-17 14:16:07 -05:00
parent 9d48d35db0
commit 57a6f5b3b4
2 changed files with 29 additions and 20 deletions

View file

@ -10,14 +10,27 @@ declare const Astro: {
opts: Record<string, any>,
root: HTMLElement
) => void;
};
}
interface IslandMeta {
componentUrl: string;
rendererUrl: string;
beforeHydrationUrl?: string;
componentExport?: string;
props: Record<string, any>;
opts: Record<string, any>;
}
{
// @ts-ignore
(self.Astro || (self.Astro = {})).assign = (script,value) => {
Object.assign(script.parentElement,value);
// island meta info (for all islands) is stored here
var $meta: Record<string, IslandMeta> = {};
// Astro.assign is called in injected scripts
(self as any).Astro = Object.assign((self as any).Astro || {}, {
assign(script: HTMLElement, value: any) {
$meta[(script.parentElement as any).getAttribute('uid')] = value;
script.remove();
};
}
})
if (!customElements.get('astro-island')) {
customElements.define(
@ -25,16 +38,11 @@ declare const Astro: {
class extends HTMLElement {
public Component: any;
public hydrator: any;
// These props are injected by the Astro runtime via inline `<script>`
public opts: Record<string, any> = {};
public props: Record<string, any> = {};
public rendererUrl = '';
public componentUrl = '';
public componentExport = 'default';
public beforeHydrationUrl = '';
public uid: any;
static get observedAttributes() { return ['ssr'] }
get meta() { return $meta[this.uid]; }
connectedCallback() {
this.uid = this.getAttribute('uid')!;
if (!this.hasAttribute('await-children') || this.firstChild) {
this.childrenConnectedCallback();
} else {
@ -49,7 +57,7 @@ declare const Astro: {
}
}
async childrenConnectedCallback() {
let { beforeHydrationUrl } = this;
let { beforeHydrationUrl } = this.meta;
if (beforeHydrationUrl) {
await import(beforeHydrationUrl);
}
@ -57,7 +65,7 @@ declare const Astro: {
this.removeAttribute('await-children');
}
start() {
const { opts } = this;
const { opts = {} } = this.meta;
const client = this.getAttribute('client') as directiveAstroKeys;
if (Astro[client] === undefined) {
window.addEventListener(`astro:${client}`, () => this.start(), { once: true });
@ -65,7 +73,7 @@ declare const Astro: {
}
Astro[client]!(
async () => {
const { rendererUrl, componentUrl, componentExport = 'default' } = this;
const { rendererUrl, componentUrl, componentExport = 'default' } = this.meta;
const [componentModule, { default: hydrator }] = await Promise.all([
import(componentUrl),
rendererUrl ? import(rendererUrl) : () => () => {},
@ -117,7 +125,8 @@ declare const Astro: {
if (!closest?.isSameNode(this)) continue;
slots[slot.getAttribute('name') || 'default'] = slot.innerHTML;
}
await this.hydrator(this)(this.Component, this.props, slots, {
const { props = {} } = this.meta;
await this.hydrator(this)(this.Component, props, slots, {
client: this.getAttribute('client'),
});
this.removeAttribute('ssr');

View file

@ -186,7 +186,7 @@ export async function generateHydrateScript(
const serializedProps = serialize(scriptProps)
const script: SSRElement = {
children: `Astro.assign(document.currentScript,${serializedProps})`,
props: { async: '' }
props: {}
}
return [island, script];