Frontmatter
| id | 8379 |
| title | Implement Lazy Loading Support for Main Thread Addons |
| state | Closed |
| labels | enhancementarchitectureperformancecore |
| assignees | tobiu |
| createdAt | Jan 7, 2026, 1:36 PM |
| updatedAt | Jan 7, 2026, 2:22 PM |
| githubUrl | https://github.com/neomjs/neo/issues/8379 |
| author | tobiu |
| commentsCount | 1 |
| parentIssue | null |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Jan 7, 2026, 2:21 PM |
Implement Lazy Loading Support for Main Thread Addons

Input from Gemini 3 Pro:
✦ ## Implementation Summary & Architectural Enhancements
This ticket evolved into a significant architectural update to support efficient, non-blocking addon initialization and robust configuration inheritance.
1. Lazy Loading for Main Thread Addons
We introduced a mechanism to defer the loading of external libraries (like Mermaid.js) until they are actually needed, significantly improving application startup time.
Neo.main.addon.Base: AddeduseLazyLoadingconfig.
- When
true, the addon'sconstructmethod leaves the#loadFilesPromisein a pending state.- This causes
initAsync()to pause after remote registration but before completion. Critically, this does not block the Main Thread (which only waits forremotesReady()), but it keeps the addon'sisReadystate asfalse.- Interception as Trigger: Since
isReadyis false,RemoteMethodAccessautomatically intercepts incoming remote calls (e.g.,render). The interception logic (cacheMethodCall) detects the pending promise and triggersloadFiles(). Once loaded, the promise resolves,initAsynccompletes,isReadybecomestrue, and the cached call executes.2. Core Enhancement:
deepArraysMerge StrategyTo support robust lazy loading, we needed to ensure the
loadFilesmethod (defined inNeo.main.addon.Base) remains accessible as a remote method even when subclasses (likeMermaid) define their ownremoteconfigs. Previously,Neo.merge(used bymerge: 'deep') replaced arrays, causing the baseloadFilesremote definition to be lost.
Neo.mjs: AddedNeo.mergeDeepArrays(target, source). This utility performs a deep merge on objects but concatenates and deduplicates arrays instead of replacing them.Neo.mergeConfig: Updated to support a new strategy string:'deepArrays'.Neo.core.Config: Documented the new strategy.3. Base Class Updates
Neo.core.Base: Updated theremote_config descriptor to usemerge: 'deepArrays'. This ensures thatremotedefinitions accumulate down the inheritance chain.Neo.main.addon.Base: AddedloadFilesto theremoteconfig. Thanks to the new merge strategy, this method is now automatically exposed for all addons, allowing for manual preloading from the App worker if desired.4. Pilot Implementation: Mermaid Addon
The
Neo.main.addon.Mermaidaddon was updated to utilizeuseLazyLoading: true.
- It no longer blocks startup.
- It automatically loads the Mermaid library upon the first
rendercall.- It inherits the
loadFilesremote endpoint correctly.These changes provide a scalable pattern for integrating heavy third-party libraries without compromising the initial load performance of Neo.mjs applications.
To optimize application startup time, we should allow Main Thread Addons to lazy-load their external dependencies (libraries) only when a remote method is actually called, rather than blocking initialization.
Proposed Changes:
src/worker/mixin/RemoteMethodAccess.mjsonRemoteMethodto check for ashouldInterceptRemote(methodName)method on the target instance.isReadyis true.src/main/addon/Base.mjsuseLazyLoadingconfig (default: false).constructandinitAsync: IfuseLazyLoadingis true,initAsyncshould not awaitloadFiles(), allowing the addon to become "ready" immediately.shouldInterceptRemote(methodName): Return true if the library files are not yet loaded (i.e., loading promise is pending) and the method is ininterceptRemotes.onInterceptRemotestriggers the file loading (viacacheMethodCall->executeLoadFiles).Outcome: Addons configured with
useLazyLoading: truewill not block the main thread initialization. Their libraries will be fetched and executed only when the first remote method (e.g.,render) is invoked.