PlatformRef.bootstrapModule (...) выдает ошибку, которая говорит: «Реализация ResourceLoader не была предоставлена». - PullRequest
0 голосов
/ 26 августа 2018

Я пытаюсь создать NgModuleRef<AppModule>, чтобы преобразовать некоторые из моих компонентов в форматы, отличные от HTML.

Мне удалось создать объект PlatformRef, однако, когда я звоню bootstrapModule(AppModule) на этом объекте я получаю сообщение об ошибке:

"Ошибка: не предоставлена ​​реализация ResourceLoader. Не удается прочитать URL" app.component.html ""

Возможно, мне следует добавить регистрацию DI ResourceLoader в месте, отличном от extraProviders, но я не знаю, где именно ...

Код:

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 (src\resource_loader\resource_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 Ответ

0 голосов
/ 29 августа 2018

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] },
];
...