From e6a5b7fee2c9dabfb827ab1e87c4352ccb166d2b Mon Sep 17 00:00:00 2001 From: Paul Derscheid Date: Fri, 13 Sep 2024 11:32:26 +0000 Subject: [PATCH] Bug 37911: (follow-up) Scan for requested components in caller and lazy load This should ensure that we only load what's requested. Maybe we can also find a way to call the exported hydrate function on demand. To test: 1) Apply the patch 2) Run yarn js:watch and wait for the first build if necessary 3) Load mainpage.pl and note that only hello-islands.ts is imported. 4) Uncomment in intranet-main.tt 5) Reload the page 6) Note that now both component chunks are imported on demand 7) Discuss --- .../prog/en/modules/intranet-main.tt | 10 +++- .../prog/js/vue/components/HelloWorld.vue | 18 ++++++++ .../prog/js/vue/modules/islands.ts | 46 +++++++++++++++---- 3 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/HelloWorld.vue diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt index d1c83f7e18..d5ac78f8da 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt @@ -11,7 +11,6 @@ [% t("Koha staff interface") | html %] [% END %] [% Asset.css("css/mainpage.css") | $raw %] -[% Asset.js("js/vue/dist/islands.js", "defer" => 1, async => "1") | $raw %] [% INCLUDE 'doc-head-close.inc' %] @@ -307,8 +306,17 @@ +
+

+ Uncomment me in intranet-main.tt 👇
+ -<!-- <hello-world></hello-world> -->
+ +<hello-world></hello-world> +

+ +
[% MACRO jsinclude BLOCK %] + [% Asset.js("js/vue/dist/islands.js", "type" => "module") | $raw %] + + diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts index 9f0798ecb6..e5e8ae76b9 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/islands.ts @@ -16,16 +16,46 @@ export const componentRegistry: Map Promise> = new Map( return module.default; }, ], + [ + "hello-world", + async () => { + const module = await import( + /* webpackChunkName: "hello-world" */ "../components/HelloWorld.vue" + ); + return module.default; + }, + ], ] ); -// Register and define custom elements -window.requestIdleCallback(async () => { - componentRegistry.forEach(async (importFn, name) => { - const component = await importFn(); - customElements.define( - name, - defineCustomElement(component as any, { shadowRoot: false }) +/** + * Hydrates custom elements by scanning the document and loading only necessary components. + * @returns {void} + */ +export function hydrate(): void { + window.requestIdleCallback(async () => { + const islandTagNames = Array.from(componentRegistry.keys()).join(", "); + const requestedIslands = new Set( + Array.from(document.querySelectorAll(islandTagNames)).map(element => + element.tagName.toLowerCase() + ) ); + + requestedIslands.forEach(async name => { + const importFn = componentRegistry.get(name); + if (!importFn) { + return; + } + + const component = await importFn(); + customElements.define( + name, + defineCustomElement(component as any, { + shadowRoot: false, + }) + ); + }); }); -}); +} + +hydrate(); -- 2.46.0