From 0e5abca84acbd8acf38b5e2bb046db4dea2f4670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Sun, 22 Dec 2024 03:32:00 +0100 Subject: [PATCH] Unlock controller loading & logDebugActivity log `controller#lazy:loading` & `controller#lazy:loaded` --- src/StimulusBundle/assets/dist/loader.js | 55 ++++++++++++++-------- src/StimulusBundle/assets/src/loader.ts | 58 ++++++++++++++++-------- 2 files changed, 75 insertions(+), 38 deletions(-) diff --git a/src/StimulusBundle/assets/dist/loader.js b/src/StimulusBundle/assets/dist/loader.js index 1d1ce80d04a..3f70fed3f99 100644 --- a/src/StimulusBundle/assets/dist/loader.js +++ b/src/StimulusBundle/assets/dist/loader.js @@ -25,30 +25,50 @@ class StimulusLazyControllerHandler { this.lazyLoadNewControllers(document.documentElement); } lazyLoadExistingControllers(element) { - this.queryControllerNamesWithin(element).forEach((controllerName) => this.loadLazyController(controllerName)); + Array.from(element.querySelectorAll(`[${controllerAttribute}]`)) + .flatMap(extractControllerNamesFrom) + .forEach((controllerName) => this.loadLazyController(controllerName)); } - async loadLazyController(name) { - if (canRegisterController(name, this.application)) { - if (this.lazyControllers[name] === undefined) { - return; - } - const controllerModule = await this.lazyControllers[name](); - registerController(name, controllerModule.default, this.application); + loadLazyController(name) { + if (!this.lazyControllers[name]) { + return; + } + const controllerLoader = this.lazyControllers[name]; + delete this.lazyControllers[name]; + if (!canRegisterController(name, this.application)) { + return; } + this.application.logDebugActivity(name, 'lazy:loading'); + controllerLoader() + .then((controllerModule) => { + this.application.logDebugActivity(name, 'lazy:loaded'); + registerController(name, controllerModule.default, this.application); + }) + .catch((error) => { + console.error(`Error loading controller "${name}":`, error); + }); } lazyLoadNewControllers(element) { + if (Object.keys(this.lazyControllers).length === 0) { + return; + } new MutationObserver((mutationsList) => { - for (const { attributeName, target, type } of mutationsList) { - switch (type) { - case 'attributes': { - if (attributeName === controllerAttribute && - target.getAttribute(controllerAttribute)) { - extractControllerNamesFrom(target).forEach((controllerName) => this.loadLazyController(controllerName)); + for (const mutation of mutationsList) { + switch (mutation.type) { + case 'childList': { + for (const node of mutation.addedNodes) { + if (node instanceof Element) { + extractControllerNamesFrom(node).forEach((controllerName) => { + this.loadLazyController(controllerName); + }); + } } break; } - case 'childList': { - this.lazyLoadExistingControllers(target); + case 'attributes': { + if (mutation.attributeName === controllerAttribute) { + extractControllerNamesFrom(mutation.target).forEach((controllerName) => this.loadLazyController(controllerName)); + } } } } @@ -58,9 +78,6 @@ class StimulusLazyControllerHandler { childList: true, }); } - queryControllerNamesWithin(element) { - return Array.from(element.querySelectorAll(`[${controllerAttribute}]`)).flatMap(extractControllerNamesFrom); - } } function registerController(name, controller, application) { if (canRegisterController(name, application)) { diff --git a/src/StimulusBundle/assets/src/loader.ts b/src/StimulusBundle/assets/src/loader.ts index d6c7ad19433..393ded69f19 100644 --- a/src/StimulusBundle/assets/src/loader.ts +++ b/src/StimulusBundle/assets/src/loader.ts @@ -64,38 +64,58 @@ class StimulusLazyControllerHandler { } private lazyLoadExistingControllers(element: Element) { - Array.from(element.querySelectorAll(`[${controllerAttribute}]`)).flatMap(extractControllerNamesFrom).forEach( - (controllerName) => this.loadLazyController(controllerName) - ); + Array.from(element.querySelectorAll(`[${controllerAttribute}]`)) + .flatMap(extractControllerNamesFrom) + .forEach((controllerName) => this.loadLazyController(controllerName)); } - private async loadLazyController(name: string) { - if (canRegisterController(name, this.application)) { - if (this.lazyControllers[name] === undefined) { - return; - } + private loadLazyController(name: string) { + if (!this.lazyControllers[name]) { + return; + } - const controllerModule = await this.lazyControllers[name](); + // Delete the loader to avoid loading it twice + const controllerLoader = this.lazyControllers[name]; + delete this.lazyControllers[name]; - registerController(name, controllerModule.default, this.application); + if (!canRegisterController(name, this.application)) { + return; } + + this.application.logDebugActivity(name, 'lazy:loading'); + + controllerLoader() + .then((controllerModule) => { + this.application.logDebugActivity(name, 'lazy:loaded'); + registerController(name, controllerModule.default, this.application); + }) + .catch((error) => { + console.error(`Error loading controller "${name}":`, error); + }); } private lazyLoadNewControllers(element: Element) { + if (Object.keys(this.lazyControllers).length === 0) { + return; + } new MutationObserver((mutationsList) => { - for (const { attributeName, target, type } of mutationsList) { - switch (type) { + for (const mutation of mutationsList) { + switch (mutation.type) { case 'childList': { - this.lazyLoadExistingControllers(target as Element); + // @ts-ignore + for (const node of mutation.addedNodes) { + if (node instanceof Element) { + extractControllerNamesFrom(node).forEach((controllerName) => { + this.loadLazyController(controllerName); + }); + } + } break; } - + case 'attributes': { - if ( - attributeName === controllerAttribute && - (target as Element).getAttribute(controllerAttribute) - ) { - extractControllerNamesFrom(target as Element).forEach((controllerName) => + if (mutation.attributeName === controllerAttribute) { + extractControllerNamesFrom(mutation.target as Element).forEach((controllerName) => this.loadLazyController(controllerName) ); }