angular - PlatformRef.bootstrapModule(...) 拋出一個錯誤,提示「未提供 ResourceLoader 實作。」
我正在嘗試創建一個 NgModuleRef<AppModule>,以便將我的一些組件渲染到非 HTML 格式中。
我能夠創建一個 PlatformRef 對象,但當我在這個對象上調用 bootstrapModule(AppModule) 時,我收到一個錯誤:
錯誤:未提供 ResourceLoader 實作。無法讀取 URL "app.component.html"
可能,我應該在不同於 extraProviders 的地方加入 ResourceLoader 的 DI 註冊,但我不知道確切位置…
程式碼:
import { ResourceLoader } from '@angular/compiler';
import { Compiler, CompilerFactory, Injectable, StaticProvider, Type } from '@angular/core';
import { platformDynamicServer } from '@angular/platform-server';
import { AppComponent } from './app/app.component';
import { AppModule } from './app/app.module';
export function createCompiler(compilerFactory: CompilerFactory) {
return compilerFactory.createCompiler();
}
async function generate<M>(moduleType: Type<M>) {
try {
const extraProviders: StaticProvider[] = [
{ provide: ResourceLoader, useClass: ResourceLoaderImpl, deps: [] },
{ provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] },
];
const platformRef = platformDynamicServer(extraProviders);
const moduleRef = await platformRef.bootstrapModule(moduleType); // <<< BREAKS HERE
const appComponent = moduleRef.injector.get(AppComponent);
console.info(appComponent.title.toString());
} catch (error) {
throw new Error(error.toString());
}
}
generate(AppModule)
.then(message => console.info({ message }))
.catch(error => console.error({ error }));
ResourceLoaderImpl 類的程式碼完全照抄自 @angular/platform-browser-dynamic (srcesource_loaderesource_loader_impl.ts):
@Injectable()
export class ResourceLoaderImpl extends ResourceLoader {
get(url: string): Promise<string> {
let resolve: (result: any) => void;
let reject: (error: any) => void;
const promise = new Promise<string>((res, rej) => {
resolve = res;
reject = rej;
});
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'text';
xhr.onload = function() {
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
// response/responseType properties were introduced in ResourceLoader Level2 spec (supported
// by IE10)
const response = xhr.response || xhr.responseText;
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
let status = xhr.status === 1223 ? 204 : xhr.status;
// fix status code when it is 0 (0 status is undocumented).
// Occurs when accessing file resources or on Android 4.1 stock browser
// while retrieving files from application cache.
if (status === 0) {
status = response ? 200 : 0;
}
if (200 <= status && status <= 300) {
resolve(response);
} else {
reject(`Failed to load ${url}`);
}
};
xhr.onerror = function() { reject(`Failed to load ${url}`); };
xhr.send();
return promise;
}
}
答案#1
ResourceLoader 是 CompilerOptions 的一部分,因此你應該提供它們。
這可以通過 platformRef.bootstrapModule 作為第二個 CompilerOptions 參數來完成:
platformRef.bootstrapModule(moduleType, {
providers: [
{
provide: ResourceLoader,
useClass: ResourceLoaderImpl, deps: []
}
]
});
或者你可以嘗試提供 COMPILER_OPTIONS 標記作為多提供者(這裡是來自源代碼的範例):
const extraProviders: StaticProvider[] = [
{
provide: COMPILER_OPTIONS,
useValue: {providers: [{provide: ResourceLoader, useClass: ResourceLoaderImpl, deps: []}]},
multi: true
},
{ provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] },
];
