diff options
Diffstat (limited to 'packages/integrations/lit')
-rw-r--r-- | packages/integrations/lit/package.json | 1 | ||||
-rw-r--r-- | packages/integrations/lit/server.js | 14 | ||||
-rw-r--r-- | packages/integrations/lit/src/client.ts | 25 | ||||
-rw-r--r-- | packages/integrations/lit/src/index.ts | 2 |
4 files changed, 39 insertions, 3 deletions
diff --git a/packages/integrations/lit/package.json b/packages/integrations/lit/package.json index ac0a8608c..1136570ee 100644 --- a/packages/integrations/lit/package.json +++ b/packages/integrations/lit/package.json @@ -23,6 +23,7 @@ ".": "./dist/index.js", "./server.js": "./server.js", "./client-shim.js": "./client-shim.js", + "./dist/client.js": "./dist/client.js", "./hydration-support.js": "./hydration-support.js", "./package.json": "./package.json" }, diff --git a/packages/integrations/lit/server.js b/packages/integrations/lit/server.js index 83737c183..48a3c646f 100644 --- a/packages/integrations/lit/server.js +++ b/packages/integrations/lit/server.js @@ -36,10 +36,18 @@ function* render(Component, attrs, slots) { // LitElementRenderer creates a new element instance, so copy over. const Ctr = getCustomElementConstructor(tagName); + let shouldDeferHydration = false; + if (attrs) { for (let [name, value] of Object.entries(attrs)) { - // check if this is a reactive property - if (name in Ctr.prototype) { + const isReactiveProperty = name in Ctr.prototype; + const isReflectedReactiveProperty = Ctr.elementProperties.get(name)?.reflect; + + // Only defer hydration if we are setting a reactive property that cannot + // be reflected / serialized as a property. + shouldDeferHydration ||= isReactiveProperty && !isReflectedReactiveProperty; + + if (isReactiveProperty) { instance.setProperty(name, value); } else { instance.setAttribute(name, value); @@ -49,7 +57,7 @@ function* render(Component, attrs, slots) { instance.connectedCallback(); - yield `<${tagName}`; + yield `<${tagName}${shouldDeferHydration ? ' defer-hydration' : ''}`; yield* instance.renderAttributes(); yield `>`; const shadowContents = instance.renderShadow({}); diff --git a/packages/integrations/lit/src/client.ts b/packages/integrations/lit/src/client.ts new file mode 100644 index 000000000..00f126e34 --- /dev/null +++ b/packages/integrations/lit/src/client.ts @@ -0,0 +1,25 @@ +export default (element: HTMLElement) => + async ( + Component: any, + props: Record<string, any>, + ) => { + // Get the LitElement element instance (may or may not be upgraded). + const component = element.children[0] as HTMLElement; + + // If there is no deferral of hydration, then all reactive properties are + // already serialzied as reflected attributes, or no reactive props were set + if (!component || !component.hasAttribute('defer-hydration')) { + return; + } + + // Set properties on the LitElement instance for resuming hydration. + for (let [name, value] of Object.entries(props)) { + // Check if reactive property or class property. + if (name in Component.prototype) { + (component as any)[name] = value; + } + } + + // Tell LitElement to resume hydration. + component.removeAttribute('defer-hydration'); + }; diff --git a/packages/integrations/lit/src/index.ts b/packages/integrations/lit/src/index.ts index 5b428ef8d..de6d5b0f9 100644 --- a/packages/integrations/lit/src/index.ts +++ b/packages/integrations/lit/src/index.ts @@ -5,6 +5,7 @@ function getViteConfiguration() { return { optimizeDeps: { include: [ + '@astrojs/lit/dist/client.js', '@astrojs/lit/client-shim.js', '@astrojs/lit/hydration-support.js', '@webcomponents/template-shadowroot/template-shadowroot.js', @@ -34,6 +35,7 @@ export default function (): AstroIntegration { addRenderer({ name: '@astrojs/lit', serverEntrypoint: '@astrojs/lit/server.js', + clientEntrypoint: '@astrojs/lit/dist/client.js', }); // Update the vite configuration. updateConfig({ |