@useavalon/avalon 0.1.64 → 0.1.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/build/island-client-bundler.d.ts +2 -2
- package/dist/src/build/island-client-bundler.js +3 -3
- package/dist/src/client/adapters/lit-adapter.js +1 -1
- package/dist/src/client/hmr-coordinator.js +1 -1
- package/dist/src/client/main-slim.js +1 -1
- package/dist/src/client/strategies.js +1 -1
- package/dist/src/islands/per-island-script.js +1 -1
- package/dist/src/post-build/inline-islands.d.ts +7 -4
- package/dist/src/post-build/inline-islands.js +2 -2
- package/dist/src/post-build/isolated-island-builder.d.ts +37 -0
- package/dist/src/post-build/isolated-island-builder.js +4 -0
- package/package.json +1 -1
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* include all CSS files from the client build output.
|
|
11
11
|
*/
|
|
12
12
|
import type { Plugin } from "vite";
|
|
13
|
-
import type { ResolvedAvalonConfig } from "../vite-plugin/types.ts";
|
|
14
13
|
import type { AvalonNitroConfig } from "../nitro/config.ts";
|
|
14
|
+
import type { ResolvedAvalonConfig } from "../vite-plugin/types.ts";
|
|
15
15
|
/**
|
|
16
16
|
* Creates a Vite plugin that emits island components as separate client chunks.
|
|
17
17
|
*/
|
|
18
|
-
export declare function islandClientBundlerPlugin(config: ResolvedAvalonConfig,
|
|
18
|
+
export declare function islandClientBundlerPlugin(config: ResolvedAvalonConfig, _nitroConfig?: AvalonNitroConfig): Plugin;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{existsSync as e,readdirSync as t,readFileSync as n,statSync as r}from"node:fs";import{dirname as i,relative as a,resolve as o}from"node:path";export function islandClientBundlerPlugin(e,t){let n=process.cwd(),r=new Map,i=!1,a=c(e,n);for(let e of a)d(e,n,r);let o=`\0avalon-island-entry:`,s=!1,l=[],u={},f=`dist`;return{name:`avalon:island-client-bundler`,enforce:`pre`,configResolved(e){s=e.command===`serve`,i=e.command===`build`,l=e.resolve?.alias??[],u=e.define??{},f=e.build?.outDir??`dist`},resolveId(e){return e.startsWith(o)?e:null},load(e){if(!e.startsWith(o))return null;let t=e.slice(21),n=JSON.stringify(t);if(t.includes(`.qwik.`))return i?[`export * from ${n};`,`export { _hW } from "@builder.io/qwik";`].join(`
|
|
2
2
|
`):[`export * from ${n};`,`export { _hW } from "@builder.io/qwik";`,`import __C from ${n};`,`export default __C;`,`if(typeof globalThis<"u")globalThis.__avalonIsland=__C;`].join(`
|
|
3
|
-
`);let r=t.includes(`.lit.`),a=[];
|
|
4
|
-
`)},async buildStart(){if(s)return;let t=this.environment;if(!(t&&t.name!==`client`)&&r.size>0){for(let[,e]of r)this.emitFile({type:`chunk`,id:o+e.filePath,fileName:`islands/${e.bundleKey}.js`,preserveSignature:`exports-only`});e.verbose&&console.log(`🏝️ Emitting ${r.size} island client bundles`)}}}}function c(
|
|
3
|
+
`);let r=t.includes(`.lit.`),a=t.includes(`.solid.`),s=t.includes(`.preact.`),c=t.includes(`.react.`),l=t.includes(`.vue.`),u=t.includes(`.svelte.`),d=[];if(r&&i&&d.push(`import "@useavalon/lit/client";`),d.push(`import __C from ${n};`,`var Component = __C;`,`export { Component as default, Component };`,`if(typeof globalThis<"u")globalThis.__avalonIsland=Component;`),i){let e={solid:`@useavalon/solid/client`,preact:`@useavalon/preact/client`,react:`@useavalon/react/client`,vue:`@useavalon/vue/client`,svelte:`@useavalon/svelte/client`,lit:`@useavalon/lit/client`},t=a?`solid`:s?`preact`:c?`react`:l?`vue`:u?`svelte`:r?`lit`:null;t&&e[t]?d.push(`export { hydrate as __hydrateIsland } from ${JSON.stringify(e[t])};`):d.push(`export { loadIntegrationModule } from "virtual:avalon/integration-loader";`)}return d.join(`
|
|
4
|
+
`)},async buildStart(){if(s)return;let t=this.environment;if(!(t&&t.name!==`client`)&&r.size>0){for(let[,e]of r)this.emitFile({type:`chunk`,id:o+e.filePath,fileName:`islands/${e.bundleKey}.js`,preserveSignature:`exports-only`});e.verbose&&console.log(`🏝️ Emitting ${r.size} island client bundles`)}},async closeBundle(){if(s||!i||r.size===0||globalThis.__avalonIslandsRebuilt)return;globalThis.__avalonIslandsRebuilt=!0;let{buildIsolatedIslands:e}=await import(`../post-build/isolated-island-builder.js`),t=new Map;for(let[e,n]of r){let r=n.filePath.includes(`.solid.`)?`solid`:n.filePath.includes(`.preact.`)?`preact`:n.filePath.includes(`.react.`)?`react`:n.filePath.includes(`.vue.`)||n.filePath.endsWith(`.vue`)?`vue`:n.filePath.includes(`.svelte.`)||n.filePath.endsWith(`.svelte`)?`svelte`:n.filePath.includes(`.lit.`)?`lit`:n.filePath.includes(`.qwik.`)?`qwik`:`preact`;t.set(e,{...n,framework:r})}await e(n,f,t,l,u)}}}function c(n,r){let i=[];if(n.pagesDir){let t=o(r,n.pagesDir);e(t)&&i.push(t)}if(n.layoutsDir){let t=o(r,n.layoutsDir);e(t)&&i.push(t)}if(n.modules){let a=o(r,n.modules.dir);if(e(a))try{for(let n of t(a,{withFileTypes:!0}))if(n.isDirectory())for(let t of[`pages`,`layouts`,`components`]){let r=o(a,n.name,t);e(r)&&i.push(r)}}catch{}}return i}const l=[`.qwik.`];function u(e){return l.some(t=>e.includes(t))}function d(e,r,i){let a;try{a=t(e,{withFileTypes:!0})}catch{return}for(let t of a){let a=o(e,t.name);if(t.isDirectory()){d(a,r,i);continue}if(/\.(tsx?|jsx?|mdx?)$/.test(t.name))try{let e=n(a,`utf-8`),t=e.includes(`island=`)||e.includes(`island `),o=/import\s+\w+\s+from\s+['"][^'"]*\.qwik\.[^'"]*['"]/m.test(e);if(!t&&!o)continue;f(e,a,r,i)}catch{}}}function f(e,t,n,r){let i=/<([A-Z]\w*)\s+[^>]*\bisland\b/g,o=new Set,s=null;for(s=i.exec(e);s!==null;s=i.exec(e))o.add(s[1]);let c=/import\s+(\w+)\s+from\s+['"]([^'"]+)['"]/g,l=new Set,d=[];for(s=c.exec(e);s!==null;s=c.exec(e))d.push([s[1],s[2]]),u(s[2])&&RegExp(`<${s[1]}[\\s/>]`).test(e)&&l.add(s[1]);if(!(o.size===0&&l.size===0))for(let[e,i]of d){if(!o.has(e)&&!l.has(e))continue;let s=p(i,t,n);if(!s)continue;let c=a(n,s).replaceAll(`\\`,`/`).replace(/\.(tsx?|jsx?)$/,``);r.has(s)||r.set(s,{filePath:s,bundleKey:c})}}function p(t,n,a){let s;if(t.startsWith(`@shared/`))s=o(a,`app/shared`,t.slice(8));else if(t.startsWith(`@modules/`))s=o(a,`app/modules`,t.slice(9));else if(t.startsWith(`@/`))s=o(a,`app`,t.slice(2));else if(t.startsWith(`.`))s=o(i(n),t);else return null;if(e(s)&&r(s).isFile())return s;for(let t of[`.tsx`,`.ts`,`.jsx`,`.js`,`.vue`,`.svelte`])if(e(s+t))return s+t;return null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BaseFrameworkAdapter as e}from"../framework-adapter.js";export class LitHMRAdapter extends e{name=`lit`;elementConstructors=new WeakMap;tagNames=new WeakMap;canHandle(e){if(!e)return!1;if(typeof e==`function`){let t=e;if(t.__litElement)return!0;try{let t=e.prototype;if(t){if(`render`in t&&`requestUpdate`in t&&`updateComplete`in t)return!0;let e=t;for(;e&&e!==Object.prototype;){let t=e.constructor;if(t&&t.name===`LitElement`)return!0;e=Object.getPrototypeOf(e)}}}catch{}if(t.elementName||t.tagName)return!0;try{let t=e.toString();if(t.includes(`LitElement`)||t.includes(`customElement`)||t.includes("html`")||t.includes("css`")||t.includes(`render()`)||t.includes(`requestUpdate`))return!0}catch{}}if(typeof e!=`object`)return!1;let t=e;return t.default&&typeof t.default==`function`?this.canHandle(t.default):!!t.__litElement}preserveState(e){try{let t=super.preserveState(e);if(!t)return null;let n=e.getAttribute(`data-props`),r=n?JSON.parse(n):{},i=e.getAttribute(`data-src`)||``,a=this.extractComponentName(i),o=e.getAttribute(`data-tag-name`)||this.tagNames.get(e),s=o?e.querySelector(o):e.querySelector(`[data-lit-element]`),c={},l={};if(s){for(let e in s)if(
|
|
1
|
+
import{BaseFrameworkAdapter as e}from"../framework-adapter.js";export class LitHMRAdapter extends e{name=`lit`;elementConstructors=new WeakMap;tagNames=new WeakMap;canHandle(e){if(!e)return!1;if(typeof e==`function`){let t=e;if(t.__litElement)return!0;try{let t=e.prototype;if(t){if(`render`in t&&`requestUpdate`in t&&`updateComplete`in t)return!0;let e=t;for(;e&&e!==Object.prototype;){let t=e.constructor;if(t&&t.name===`LitElement`)return!0;e=Object.getPrototypeOf(e)}}}catch{}if(t.elementName||t.tagName)return!0;try{let t=e.toString();if(t.includes(`LitElement`)||t.includes(`customElement`)||t.includes("html`")||t.includes("css`")||t.includes(`render()`)||t.includes(`requestUpdate`))return!0}catch{}}if(typeof e!=`object`)return!1;let t=e;return t.default&&typeof t.default==`function`?this.canHandle(t.default):!!t.__litElement}preserveState(e){try{let t=super.preserveState(e);if(!t)return null;let n=e.getAttribute(`data-props`),r=n?JSON.parse(n):{},i=e.getAttribute(`data-src`)||``,a=this.extractComponentName(i),o=e.getAttribute(`data-tag-name`)||this.tagNames.get(e),s=o?e.querySelector(o):e.querySelector(`[data-lit-element]`),c={},l={};if(s){for(let e in s)if(Object.hasOwn(s,e)&&!e.startsWith(`_`))try{let t=s[e];t!=null&&typeof t!=`function`&&typeof t!=`symbol`&&(c[e]=t)}catch{}for(let e=0;e<s.attributes.length;e++){let t=s.attributes[e];l[t.name]=t.value}}return{...t,framework:`lit`,data:{componentName:a,tagName:o||void 0,capturedProps:r,elementProperties:c,elementAttributes:l}}}catch(e){return console.warn(`Failed to preserve Lit state:`,e),null}}async update(e,t,n){if(!this.canHandle(t))throw Error(`Component is not a valid Lit component`);let r;if(typeof t==`object`&&t){let e=t;if(e.default&&typeof e.default==`function`)r=e.default;else throw Error(`Lit component object must have a default export`)}else if(typeof t==`function`)r=t;else throw Error(`Invalid Lit component type`);try{let t=e.getAttribute(`data-tag-name`);if(t||=r.elementName,t||=r.name.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),!t||!t.includes(`-`))throw Error(`Invalid custom element tag name: `+t);this.tagNames.set(e,t),e.setAttribute(`data-tag-name`,t);let i=Array.from(e.querySelectorAll(t));if(i.length===0){let i=customElements.get(t);i?i!==r&&await this.reregisterCustomElement(t,r):customElements.define(t,r);let a=document.createElement(t);Object.entries(n).forEach(([e,t])=>{try{a[e]=t}catch(t){console.warn(`Failed to set property ${e} on Lit element:`,t)}}),e.appendChild(a),this.elementConstructors.set(e,r),e.setAttribute(`data-hydrated`,`true`),e.setAttribute(`data-hydration-status`,`success`);return}let a=customElements.get(t);if(a&&a!==r){await this.reregisterCustomElement(t,r);for(let e of i){let n={},r={};for(let t in e)if(Object.hasOwn(e,t)&&!t.startsWith(`_`))try{let r=e[t];r!=null&&typeof r!=`function`&&typeof r!=`symbol`&&(n[t]=r)}catch{}for(let t=0;t<e.attributes.length;t++){let n=e.attributes[t];r[n.name]=n.value}let i=document.createElement(t);Object.entries(r).forEach(([e,t])=>{i.setAttribute(e,t)}),Object.entries(n).forEach(([e,t])=>{try{i[e]=t}catch(t){console.warn(`Failed to restore property ${e}:`,t)}}),e.parentNode?.replaceChild(i,e)}}else if(a)for(let e of i)Object.entries(n).forEach(([t,n])=>{try{e[t]=n}catch(e){console.warn(`Failed to update property ${t}:`,e)}}),e.requestUpdate&&e.requestUpdate();else{customElements.define(t,r);for(let e of i)e.requestUpdate&&e.requestUpdate()}this.elementConstructors.set(e,r),e.setAttribute(`data-hydrated`,`true`),e.setAttribute(`data-hydration-status`,`success`)}catch(t){throw console.error(`Lit HMR update failed:`,t),e.setAttribute(`data-hydration-status`,`error`),t}}async reregisterCustomElement(e,t){console.warn(`Custom element ${e} is already defined. Replacing all instances with new definition.`)}restoreState(e,t){try{super.restoreState(e,t);let n=t,r=n.data.tagName;if(r){let t=e.querySelector(r);t&&(n.data.elementProperties&&Object.entries(n.data.elementProperties).forEach(([e,n])=>{try{t[e]=n}catch(t){console.warn(`Failed to restore property ${e}:`,t)}}),n.data.elementAttributes&&Object.entries(n.data.elementAttributes).forEach(([e,n])=>{try{t.setAttribute(e,n)}catch(t){console.warn(`Failed to restore attribute ${e}:`,t)}}),t.requestUpdate&&t.requestUpdate())}}catch(e){console.warn(`Failed to restore Lit state:`,e)}}handleError(e,t){console.error(`Lit HMR error:`,t),super.handleError(e,t);let n=e.querySelector(`.hmr-error-indicator`);if(n){let e=t.message,r=``;e.includes(`custom element`)||e.includes(`define`)?r=` (Hint: Check that your element has a valid tag name with a hyphen)`:e.includes(`tag name`)?r=` (Hint: Custom element tag names must contain a hyphen)`:e.includes(`property`)||e.includes(`attribute`)?r=` (Hint: Check @property decorators and attribute names)`:e.includes(`render`)?r=` (Hint: Check the render() method for errors)`:e.includes(`shadow`)&&(r=` (Hint: Check Shadow DOM usage and styles)`),n.textContent=`Lit HMR Error: ${e}${r}`}}extractComponentName(e){let t=e.split(`/`);return t[t.length-1].replace(/\.lit\.(ts|js)$/,``).replace(/\.(ts|js)$/,``)}unmount(e){try{let t=this.tagNames.get(e);t&&(e.querySelectorAll(t).forEach(e=>{e.remove()}),this.tagNames.delete(e)),this.elementConstructors.delete(e)}catch(e){console.warn(`Failed to unmount Lit element:`,e)}}}export const litAdapter=new LitHMRAdapter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{getCSSHMRHandler as e}from"./css-hmr-handler.js";import{AdapterRegistry as t}from"./framework-adapter.js";export class HMRCoordinator{registry=new t;stateSnapshots=new Map;updateQueue=new Set;isProcessing=!1;initialize(){import.meta.hot&&(import.meta.hot.accept(),import.meta.hot.on(`vite:beforeUpdate`,e=>{this.handleUpdate(e)}),import.meta.hot.on(`vite:beforeFullReload`,()=>{this.handleBeforeFullReload()}),import.meta.hot.on(`vite:error`,e=>{console.error(`[HMR] error:`,e),this.handleError(e)}),document.addEventListener(`hmr-update-required`,e=>{let{src:t,reason:n}=e.detail;n===`css-module-update`&&(this.updateQueue.add(this.normalizePath(t)),this.isProcessing||this.processUpdateQueue().catch(e=>{console.error(`[HMR] Failed to process CSS module update:`,e)}))}))}registerAdapter(e,t){this.registry.register(e,t)}getRegistry(){return this.registry}async handleUpdate(e){if(e.type!==`update`||!e.updates)return;let t=[],n=[];for(let r of e.updates)r.type===`css-update`?t.push(r):n.push(r);this.processCSSUpdates(t),this.queueJSUpdates(n),!this.isProcessing&&this.updateQueue.size>0&&await this.processUpdateQueue()}processCSSUpdates(t){if(t.length===0)return;let n=e();for(let e of t)try{n.handleCSSUpdate(e)}catch(e){console.error(`[HMR] CSS update failed:`,e)}}queueJSUpdates(e){for(let t of e){let e=this.normalizePath(t.path||t.acceptedPath);this.isIslandModule(e)&&this.updateQueue.add(e)}}async processUpdateQueue(){if(this.updateQueue.size!==0){this.isProcessing=!0;try{let e=Array.from(this.updateQueue);this.updateQueue.clear();for(let t of e){let e=this.findAffectedIslands(t);for(let t of e)try{await this.updateIsland(t)}catch(e){console.error(`[HMR] Failed to update island:`,e)}}}finally{this.isProcessing=!1}}}findAffectedIslands(e){let t=[],n=this.normalizePath(e),r=document.querySelectorAll(`[data-src]`);for(let e of r){let r=e.dataset.src;if(!r)continue;let i=this.normalizePath(r);(i===n||i.endsWith(n)||n.endsWith(i)||i.split(`/`).pop()===n.split(`/`).pop())&&t.push(e)}return t}async updateIsland(e){let t=e.dataset.framework,n=e.dataset.src,r=e.dataset.props;if(!t||!n){console.warn(`[HMR] Island missing framework or src attribute`,e);return}let i=this.registry.get(t.toLowerCase());if(!i){console.warn(`[HMR] No adapter registered for framework: ${t}`);return}try{let a=r?JSON.parse(r):{},o=i.preserveState(e);o&&this.stateSnapshots.set(this.getIslandId(e),o),delete e.dataset.hydrated,delete e.dataset.hydrationStatus,e.querySelector(`.hydration-error-indicator, .hmr-error-indicator`)?.remove();let s=Date.now(),c=await import(n.includes(`?`)?`${n}&t=${s}`:`${n}?t=${s}`),l=this.resolveComponent(c,n);await i.update(e,l,a),o&&(i.restoreState(e,o),this.stateSnapshots.delete(this.getIslandId(e))),e.dataset.hydrated=`true`,e.dispatchEvent(new CustomEvent(`hmr-update`,{detail:{framework:t,src:n,timestamp:Date.now(),success:!0},bubbles:!0}))}catch(r){throw console.error(`[HMR] Failed to update ${t} island ${n}:`,r),i.handleError(e,r),e.dispatchEvent(new CustomEvent(`hmr-error`,{detail:{framework:t,src:n,error:r.message,timestamp:Date.now()},bubbles:!0})),r}}resolveComponent(e,t){if(e.default)return e.default;for(let t of Object.keys(e)){if(t===`default`)continue;let n=e[t];if(typeof n==`function`&&n.prototype)return n}throw Error(`Component ${t} has no default export`)}handleBeforeFullReload(){let e=document.querySelectorAll(`[data-hydrated="true"]`),t={};for(let n of e){let e=n.dataset.framework,r=n.dataset.src;if(!e||!r)continue;let i=this.registry.get(e.toLowerCase());if(!i)continue;let a=i.preserveState(n);a&&(t[r]=a)}try{sessionStorage.setItem(`__avalon_hmr_states__`,JSON.stringify(t))}catch(e){console.warn(`[HMR] Failed to save states:`,e)}}handleError(e){let t=Error(e.err.message);t.stack=e.err.stack,console.error(`[HMR] Error:`,t),globalThis.window!==void 0&&import(`./hmr-error-overlay.js`).then(({showHMRErrorOverlay:n})=>{n({framework:`unknown`,src:`unknown`,error:t,filePath:e.err.id||e.err.loc?.file||`unknown`,line:e.err.loc?.line,column:e.err.loc?.column})}).catch(()=>{console.error(`[HMR] Failed to show error overlay`)})}normalizePath(e){return e.replaceAll(`\\`,`/`).replace(/^\//,``).replace(/\?.*$/,``).replace(/#.*$/,``).replace(/^src\//,``)}isIslandModule(e){return e.includes(`/islands/`)||e.includes(`\\islands\\`)}getIslandId(e){let t=e.dataset.src??``;return`${e.dataset.framework??``}:${t}:${Array.from(document.querySelectorAll(`[data-src="${t}"]`)).indexOf(e)}`}}let r=null;export function getHMRCoordinator(){return r??=new HMRCoordinator,r}export function initializeHMR(){import.meta.hot&&getHMRCoordinator().initialize()}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(
|
|
1
|
+
(()=>{var e=document.querySelectorAll(`[data-framework]`);if(!e.length)return;var t=!1;e.forEach(e=>{var r=e.dataset.framework,i=e.dataset.condition||`on:client`;e.dataset.renderStrategy!==`ssr-only`&&(i===`on:client`?(window.requestIdleCallback||requestAnimationFrame)(()=>{n(e,r)}):t=!0)}),t&&import(`./strategies.js`).then(t=>{e.forEach(e=>{var r=e.dataset.condition||`on:client`;r!==`on:client`&&e.dataset.renderStrategy!==`ssr-only`&&!e.dataset.hydrated&&t.setup(e,e.dataset.framework,r,n)})});async function n(e,t){if(!e.dataset.hydrated){var n=e.dataset.src;if(n)try{var r=e.dataset.props?JSON.parse(e.dataset.props):{},i=await import(`virtual:avalon/integration-loader`);t===`lit`&&await i.preLitHydration();var a=await import(n),o=a.default||Object.values(a).find(e=>typeof e==`function`&&e.prototype)||a,s=await i.loadIntegrationModule(t);s.hydrate&&await s.hydrate(e,o,r),e.dataset.hydrated=`true`}catch(e){console.error(`Hydration error for `+t+` island `+n+`:`,e)}}}})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function setup(e,t,n,r){if(n===`on:visible`)try{var i=new IntersectionObserver(
|
|
1
|
+
export function setup(e,t,n,r){if(n===`on:visible`)try{var i=new IntersectionObserver(n=>{n[0].isIntersecting&&(r(e,t),i.disconnect())},{rootMargin:`50px`,threshold:0});i.observe(e)}catch{r(e,t)}else if(n===`on:interaction`){var a=[`click`,`touchstart`,`mouseenter`,`focusin`],o=!1,s=()=>{o||(o=!0,a.forEach(t=>{e.removeEventListener(t,s)}),r(e,t))};a.forEach(t=>{e.addEventListener(t,s,{once:!0,passive:!0})})}else if(n===`on:idle`){var c=()=>{r(e,t)};`requestIdleCallback`in globalThis?globalThis.requestIdleCallback(c,{timeout:5e3}):document.readyState===`complete`?setTimeout(c,200):globalThis.addEventListener(`load`,()=>{setTimeout(c,200)},{once:!0})}else if(n.startsWith(`media:`)){var l=n.slice(6);try{var u=globalThis.matchMedia(l);u.matches?r(e,t):u.addEventListener(`change`,function n(i){i.matches&&(r(e,t),u.removeEventListener(`change`,n))})}catch{r(e,t)}}else e.dataset.customDirective?import(`./custom-directives.js`).then(i=>{i.hasClientDirective&&i.hasClientDirective(n)?i.executeCustomDirective(e,n,()=>{r(e,t)}):r(e,t)}).catch(()=>{r(e,t)}):r(e,t)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function generatePerIslandScript(e){let{islandId:r,componentSrc:i,framework:a,condition:o,conditionArg:s,propsJson:c,isCustomDirective:l,directiveScript:u}=e;return`<script type="module">${n(r,o,t(r,i,a,c),s,l,u)}<\/script>`}function t(e,t,n,r){return[`async function h(){`,`var e=document.getElementById(${JSON.stringify(e)});`,`if(!e||e.dataset.hydrated)return;`,`try{`,`var p=${r};`,`var m=await import(${JSON.stringify(t)});`,`var C=m.default||Object.values(m).find(function(v){return typeof v==="function"&&v.prototype})||m;`,`var i=await m.loadIntegrationModule(${JSON.stringify(n)})
|
|
1
|
+
export function generatePerIslandScript(e){let{islandId:r,componentSrc:i,framework:a,condition:o,conditionArg:s,propsJson:c,isCustomDirective:l,directiveScript:u}=e;return`<script type="module">${n(r,o,t(r,i,a,c),s,l,u)}<\/script>`}function t(e,t,n,r){return[`async function h(){`,`var e=document.getElementById(${JSON.stringify(e)});`,`if(!e||e.dataset.hydrated)return;`,`try{`,`var p=${r};`,`var m=await import(${JSON.stringify(t)});`,`var C=m.default||Object.values(m).find(function(v){return typeof v==="function"&&v.prototype})||m;`,`if(m.__hydrateIsland){await m.__hydrateIsland(e,C,p)}`,`else if(m.loadIntegrationModule){var i=await m.loadIntegrationModule(${JSON.stringify(n)});if(i.hydrate)await i.hydrate(e,C,p)}`,`e.dataset.hydrated="true";`,`}catch(err){console.error("Hydration error:",err)}`,`}`].join(``)}function n(e,t,n,r,i,a){if(t===`on:client`)return`${n}(window.requestIdleCallback||requestAnimationFrame)(function(){h()});`;if(t===`on:visible`)return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){try{var o=new IntersectionObserver(function(n){`,`if(n[0].isIntersecting){h();o.disconnect()}`,`},{rootMargin:"50px",threshold:0});o.observe(e)}catch(_){h()}}`].join(``);if(t===`on:idle`)return[n,`if("requestIdleCallback" in globalThis){`,`globalThis.requestIdleCallback(function(){h()},{timeout:5000})`,`}else if(document.readyState==="complete"){`,`setTimeout(function(){h()},200)`,`}else{globalThis.addEventListener("load",function(){setTimeout(function(){h()},200)},{once:true})}`].join(``);if(t===`on:interaction`)return[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){var d=false;var ev=["click","touchstart","mouseenter","focusin"];`,`var fn=function(){if(d)return;d=true;ev.forEach(function(n){e.removeEventListener(n,fn)});h()};`,`ev.forEach(function(n){e.addEventListener(n,fn,{once:true,passive:true})})}`].join(``);if(t.startsWith(`media:`)){let e=t.slice(6);return[n,`try{var mq=globalThis.matchMedia(${JSON.stringify(e)});`,`if(mq.matches){h()}else{mq.addEventListener("change",function x(ev){`,`if(ev.matches){h();mq.removeEventListener("change",x)}},{once:true})}}catch(_){h()}`].join(``)}return i&&a?[n,`var e=document.getElementById(${JSON.stringify(e)});`,`if(e){var dir=(${a});`,`dir(e,function(){h()}${r?`,${JSON.stringify(r)}`:``})}`].join(``):`${n}h();`}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Post-build Island Inlining
|
|
3
3
|
*
|
|
4
|
-
* Re-bundles
|
|
4
|
+
* Re-bundles island chunks with esbuild to inline shared dependencies
|
|
5
5
|
* (framework runtimes) into a single self-contained file per island.
|
|
6
|
-
* This eliminates the separate shared chunks, matching Astro's approach.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Safe for all frameworks because each island wrapper exports __hydrateIsland
|
|
8
|
+
* directly from the framework adapter — the component and hydrate function
|
|
9
|
+
* share the same module graph, so no duplicate framework singletons are created.
|
|
10
|
+
*
|
|
11
|
+
* Runs AFTER the main Vite build, operating on compiled JS output.
|
|
10
12
|
*/
|
|
11
13
|
interface InlineResult {
|
|
12
14
|
island: string;
|
|
13
15
|
beforeSize: number;
|
|
14
16
|
afterSize: number;
|
|
15
17
|
success: boolean;
|
|
18
|
+
skipped?: boolean;
|
|
16
19
|
error?: string;
|
|
17
20
|
}
|
|
18
21
|
/**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readdir as e,readFile as t}from"node:fs/promises";import{
|
|
2
|
-
`))}else await
|
|
1
|
+
import{readdir as e,readFile as t}from"node:fs/promises";import{join as n,resolve as r}from"node:path";export async function inlineIslandChunks(e,n={}){let{verbose:i=!1}=n,o=await a(r(e,`islands`));if(o.length===0)return i&&console.log(`🏝️ No island files found, skipping inlining`),[];let s=null,c;if(globalThis.Bun!==void 0)s=`bun`;else try{c=await import(`esbuild`),s=`esbuild`}catch{}if(!s)return console.warn(`🏝️ No bundler available (Bun or esbuild), skipping island inlining`),[];console.log(`🏝️ Inlining shared chunks into ${o.length} islands...`);let l=[];for(let n of o){let a=n.replace(`${e}/`,``);if(a.includes(`.qwik.`)){l.push({island:a,beforeSize:0,afterSize:0,success:!0,skipped:!0});continue}try{let e=await t(n,`utf-8`),o=Buffer.byteLength(e,`utf-8`);if(!e.includes(`from"../`)&&!e.includes(`from'../`)){l.push({island:a,beforeSize:o,afterSize:o,success:!0});continue}if(s===`bun`){let e={entrypoints:[n],outdir:r(n,`..`),naming:`[name].[ext]`,minify:!0,target:`browser`,format:`esm`,treeshaking:!0,external:[`*integration-loader*`]},t=await Bun.build(e);if(!t.success)throw Error(t.logs.map(e=>e.message).join(`
|
|
2
|
+
`))}else await c.build({entryPoints:[n],outfile:n,bundle:!0,format:`esm`,minify:!0,treeShaking:!0,target:`es2020`,allowOverwrite:!0,plugins:[{name:`externalize-integration-loader`,setup(e){e.onResolve({filter:/integration-loader|rolldown-runtime/},e=>({path:e.path,external:!0}))}}]});let u=await t(n,`utf-8`),d=Buffer.byteLength(u,`utf-8`);if(l.push({island:a,beforeSize:o,afterSize:d,success:!0}),i){let e=(o/1024).toFixed(1),t=(d/1024).toFixed(1);console.log(` ✅ ${a}: ${e} KiB → ${t} KiB`)}}catch(e){let t=e instanceof Error?e.message:String(e);console.error(` ❌ ${a}: ${t}`),l.push({island:a,beforeSize:0,afterSize:0,success:!1,error:t})}}let u=l.filter(e=>e.success).length,d=l.filter(e=>!e.success).length;return console.log(`🏝️ Done: ${u} inlined${d?`, ${d} failed`:``}`),l}async function a(t,r=[]){try{let i=await e(t,{withFileTypes:!0});for(let e of i){let i=n(t,e.name);e.isDirectory()?await a(i,r):e.name.endsWith(`.js`)&&!e.name.endsWith(`.map`)&&r.push(i)}}catch{}return r}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Isolated Island Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds each island as a separate Vite build with fresh framework plugins.
|
|
5
|
+
* This produces self-contained island files with the framework runtime inlined
|
|
6
|
+
* and tree-shaken — matching Astro's approach.
|
|
7
|
+
*
|
|
8
|
+
* Each build:
|
|
9
|
+
* 1. Loads framework plugins fresh (vite-plugin-solid, @vitejs/plugin-vue, etc.)
|
|
10
|
+
* 2. Compiles from source (.tsx/.vue/.svelte)
|
|
11
|
+
* 3. Outputs a single file with codeSplitting: false
|
|
12
|
+
* 4. Tree-shakes aggressively — only used runtime functions remain
|
|
13
|
+
*
|
|
14
|
+
* Runs as a post-build step after the main Vite build.
|
|
15
|
+
*/
|
|
16
|
+
interface IslandBuildResult {
|
|
17
|
+
island: string;
|
|
18
|
+
success: boolean;
|
|
19
|
+
size?: number;
|
|
20
|
+
error?: string;
|
|
21
|
+
}
|
|
22
|
+
interface IslandSource {
|
|
23
|
+
filePath: string;
|
|
24
|
+
bundleKey: string;
|
|
25
|
+
framework: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build all islands in isolation.
|
|
29
|
+
*
|
|
30
|
+
* @param cwd - Project root directory
|
|
31
|
+
* @param distDir - Build output directory (e.g., "dist")
|
|
32
|
+
* @param islands - Map of discovered islands (filePath → bundleKey)
|
|
33
|
+
* @param resolveAliases - Resolve aliases from the main Vite config
|
|
34
|
+
* @param defineValues - Define replacements from the main Vite config
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildIsolatedIslands(cwd: string, distDir: string, islands: Map<string, IslandSource>, resolveAliases: any[], defineValues: Record<string, unknown>): Promise<IslandBuildResult[]>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{existsSync as e,statSync as t}from"node:fs";import{resolve as n}from"node:path";function r(e,t){let n=JSON.stringify(e);if(t===`qwik`)return[`export * from ${n};`,`export { _hW } from "@builder.io/qwik";`].join(`
|
|
2
|
+
`);let r=[];t===`lit`&&r.push(`import "@useavalon/lit/client";`),r.push(`import __C from ${n};`,`var Component = __C;`,`export { Component as default, Component };`,`if(typeof globalThis<"u")globalThis.__avalonIsland=Component;`);let i={solid:`@useavalon/solid/client`,preact:`@useavalon/preact/client`,react:`@useavalon/react/client`,vue:`@useavalon/vue/client`,svelte:`@useavalon/svelte/client`,lit:`@useavalon/lit/client`};return i[t]&&r.push(`export { hydrate as __hydrateIsland } from ${JSON.stringify(i[t])};`),r.join(`
|
|
3
|
+
`)}async function i(e,t){let n=[],{resolve:r}=await import(`node:path`),{existsSync:i}=await import(`node:fs`),{pathToFileURL:a}=await import(`node:url`),o={solid:{pkg:`vite-plugin-solid`,esmEntry:`dist/esm/index.mjs`},vue:{pkg:`@vitejs/plugin-vue`,esmEntry:`dist/index.mjs`},svelte:{pkg:`@sveltejs/vite-plugin-svelte`,esmEntry:`src/index.js`}}[e];if(!o)return n;try{let s=null,c=t;for(let e=0;e<8;e++){let e=r(c,`node_modules`,o.pkg,o.esmEntry);if(i(e)){s=e;break}for(let e of[`solid`,`vue`,`svelte`,`preact`,`react`,`lit`]){let t=r(c,`packages`,`integrations`,e,`node_modules`,o.pkg,o.esmEntry);if(i(t)){s=t;break}}if(s)break;c=r(c,`..`)}if(!s)throw Error(`Cannot find package '${o.pkg}'`);let l=await import(a(s).href);switch(e){case`solid`:{let e=l.default??l;n.push(e({ssr:!1,hot:!1}));break}case`vue`:{let e=l.default??l;n.push(e());break}case`svelte`:{let e=l.svelte??l.default;n.push(e({compilerOptions:{hydratable:!0}}));break}}}catch(t){console.warn(` ⚠ Could not load ${e} plugin: ${t instanceof Error?t.message:t}`)}return n}function a(e){let t={solid:`@useavalon/solid/client`,preact:`@useavalon/preact/client`,react:`@useavalon/react/client`,vue:`@useavalon/vue/client`,svelte:`@useavalon/svelte/client`,lit:`@useavalon/lit/client`}[e];return t?[`import { hydrate } from ${JSON.stringify(t)};`,`export async function loadIntegrationModule() { return { hydrate }; }`].join(`
|
|
4
|
+
`):`export async function loadIntegrationModule() { return {}; }`}async function o(e){let{createRequire:t}=await import(`node:module`),n=t(`${e}/package.json`),r=e=>{try{return n.resolve(e).replace(/\.js$/,`.mjs`)}catch{return null}},i={preact:r(`preact`),"preact/hooks":r(`preact/hooks`),"preact/compat":r(`preact/compat`),"preact/compat/client":r(`preact/compat/client`),"preact/compat/server":r(`preact/compat/server`),"preact/jsx-runtime":r(`preact/jsx-runtime`),react:r(`preact/compat`),"react/jsx-runtime":r(`preact/jsx-runtime`),"react/jsx-dev-runtime":r(`preact/jsx-runtime`),"react-dom":r(`preact/compat`),"react-dom/client":r(`preact/compat/client`),"react-dom/server":r(`preact/compat/server`)};return{name:`avalon:isolated-preact-compat`,enforce:`pre`,resolveId(e){return i[e]||null}}}export async function buildIsolatedIslands(s,c,l,u,d){if(l.size===0)return[];let{build:f}=await import(`vite`);console.log(`🏝️ Building ${l.size} islands in isolation...`);let p=performance.now(),m=[];for(let[,p]of l){let{filePath:l,bundleKey:h,framework:g}=p,_=`islands/${h}.js`;if(g===`qwik`||g===`lit`){m.push({island:_,success:!0});continue}let v=r(l,g),y=`\0isolated-island-entry`,b=`\0virtual:avalon/integration-loader`;try{let r=await i(g,s);await f({configFile:!1,root:s,logLevel:`silent`,plugins:[{name:`avalon:isolated-island-virtual`,resolveId(e){return e===y?e:e===`virtual:avalon/integration-loader`||e===b?b:null},load(e){return e===y?v:e===b?a(g):null}},await o(s),...r],build:{write:!0,outDir:n(s,c),emptyOutDir:!1,minify:`oxc`,target:`es2020`,rollupOptions:{input:y,output:{format:`es`,entryFileNames:_},preserveEntrySignatures:`exports-only`}},resolve:{alias:u},define:{...d,__DEV__:`false`,__PROD__:`true`,"process.env.NODE_ENV":`"production"`}});let l=n(s,c,_),p=e(l)?t(l).size:0;m.push({island:_,success:!0,size:p}),console.log(` ✅ ${h} (${g}): ${(p/1024).toFixed(1)} KiB`)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(` ❌ ${h} (${g}): ${t}`),m.push({island:_,success:!1,error:t})}}let h=((performance.now()-p)/1e3).toFixed(1),g=m.filter(e=>e.success).length,_=m.filter(e=>!e.success).length;return console.log(`🏝️ Done in ${h}s: ${g} built${_?`, ${_} failed`:``}`),m}
|