我试图在 Angular 14 中动态导入模块,其中模块路径是在运行时设置的,但出现以下错误:
Error: Cannot find module 'src/app/plugin1/plugin1.module'
Github 重现 https://github.com/baltzarmattsson/lazyapprepro
当我手动输入导入路径时它起作用:
let module = await import("src/app/plugin1/plugin1.module").then(m => (m as any)[Object.keys(m)[0]]);
但不适用于动态值:
@Input() path: string;
...
let module = await import(this.path).then(m => (m as any)[Object.keys(m)[0]]);
插件模块包含在 tsconfig 中,tsconfig.app.json:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": [],
"module": "esnext"
},
"files": [
"src/main.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.d.ts",
"src/**/*.ts",
"src/app/plugin1/plugin1.module"
],
"exclude": [
"src/**/*.spec.ts",
"src/test.ts",
"src/environments/*"
]
}
tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2020",
"module": "es2020",
"lib": [
"es2020",
"dom"
]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
我正在努力实现我们之前使用的目标@herodevs/英雄装载机 https://www.npmjs.com/package/@herodevs/hero-loaderfor,它不适用于 ng14。
Update
创造了这个怪物并使其发挥作用。由于必须显式输入字符串,因此无法通过 for 循环加载它们。条目是not添加到任何 tsconfig 文件中。
任何其他解决方案仍然值得赞赏。
@Injectable({ providedIn: "root" })
export class ModuleLoaderService {
preloadedModulesByPath: { [path: string]: any };
isModulesPreLoaded = false;
async preloadLazyModules() {
let map = {};
map["path/to/module1.module"] = await import("path/to/module1.module");
map["path/to/module2.module"] = await import("path/to/module2.module");
map["path/to/module3.module"] = await import("path/to/module3.module");
map["path/to/module4.module"] = await import("path/to/module4.module");
this.preloadedModulesByPath = map;
this.isModulesPreLoaded = true;
}
}
import { Component, ComponentRef, createNgModule, Injector, Input, ViewContainerRef } from "@angular/core";
import { ModuleLoaderService } from "../services/module-loader.service";
@Component({
selector: 'hero-loader',
template: "",
})
export class HeroLoaderTempComponent {
// In format path/to/feature.module#FeatureModule
@Input() moduleName: string;
_componentRef: ComponentRef<unknown>;
constructor(
private _injector: Injector,
private _viewRef: ViewContainerRef,
private moduleLoader: ModuleLoaderService
) { }
async ngOnInit() {
if (!this.moduleName) {
return;
}
let path = this.moduleName.split("#")[0];
let moduleName = this.moduleName.split("#")[1];
let module = this.moduleLoader.preloadedModulesByPath[path];
module = module[Object.keys(module)[0]];
try {
let moduleRef = createNgModule(module, this._injector);
const component = (moduleRef as any)._bootstrapComponents[0];
this._componentRef = this._viewRef.createComponent(component, { injector: this._injector, ngModuleRef: moduleRef })
} catch (e) {
console.error("Err when loading dynamic module: " + moduleName, e);
}
}
}