Blog>
Snippets

Dynamic Plugin Loading with Angular

Use Angular's dynamic import to load plugins lazily and register them with the Dependency Injection system without needing to list them statically.
import { Injectable, Injector, Compiler } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class PluginLoaderService {
  constructor(private injector: Injector, private compiler: Compiler) {}

  async loadPlugin(pluginName: string) {
    // Dynamic import to lazily load the plugin module
    const module = await import(
      `./plugins/${pluginName}/${pluginName}.module`
    ).then(m => m[`${pluginName}Module`]);

    // Compile the module and resolve the module instance
    const moduleFactory = await this.compiler.compileModuleAsync(module);
    const moduleRef = moduleFactory.create(this.injector);

    // Assume the plugin provides a static '.forRoot()' method to register its services
    if (module.forRoot) {
      this.injector = module.forRoot(moduleRef.injector);
    }
  }
}
This service provides functionality to dynamically load and compile a plugin module by its name. The `loadPlugin()` method uses the dynamic imports feature from the ES2020 specification, allowing Angular to load only the necessary code for a plugin, without the need to list it in the main application bundle. After dynamically importing, it compiles the module and uses its `.forRoot()` method to register any services with Angular's dependency injection system.