AOT and JIT with build-optimizer

2019-07-11 18:38发布

I am following the solution here of using the JitCompilerFactory to load the runtime compiler and custom decorators to preserve the component and module metadata. But with the angular-cli --build-optimizer flag I get:

ERROR Error: Cannot resolve all parameters for 'Parser'(?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'Parser' is decorated with Injectable.

Here is my minimal reproduction, run ng serve --aot --build-optimizer. As a control ng serve --aot works.

1条回答
Anthone
2楼-- · 2019-07-11 18:45

If you use option --build-optimizer then @angular-devkit/build-optimizer/webpack-loader loader is added to webpack loaders list.

@angular-devkit/build-optimizer/webpack-loader removes ctorParameters definitions from types that is not part of platformWhitelist (source):

const platformWhitelist = [
  'PlatformRef_',
  'TestabilityRegistry',
  'Console',
  'BrowserPlatformLocation',
];

I think that's correct behavior.

To work around it you could initialize ctorParameters manually before JitCompilerFactory is created:

import { 
  Compiler, ɵConsole as Console,
  Optional, Inject, Injector, 
  PACKAGE_ROOT_URL 
} from '@angular/core';

import {
  JitCompilerFactory,
  TemplateParser, CompilerConfig, CompileReflector,
  ElementSchemaRegistry, I18NHtmlParser, TEMPLATE_TRANSFORMS, DirectiveNormalizer,
  ResourceLoader, UrlResolver, HtmlParser, CompileMetadataResolver, NgModuleResolver,
  DirectiveResolver, SummaryResolver, PipeResolver, StaticSymbolCache, 
  ERROR_COLLECTOR_TOKEN,
  StyleCompiler, ViewCompiler, NgModuleCompiler, JitCompiler
} from '@angular/compiler';

import * as compiler from '@angular/compiler';

export function compilerFactory() {
  restoreDecorators();

  return new JitCompilerFactory([{ useDebug: false, useJit: true }]).createCompiler();
}

function restoreDecorators() {
  (compiler.Parser as any).parameters = [compiler.Lexer];
  (TemplateParser as any).parameters = [
    CompilerConfig, CompileReflector, compiler.Parser, ElementSchemaRegistry,
    I18NHtmlParser, Console, [new Optional(), new Inject(TEMPLATE_TRANSFORMS)]
  ];
  (DirectiveNormalizer as any).parameters = [
    ResourceLoader, UrlResolver,
    HtmlParser, CompilerConfig
  ];
  (CompileMetadataResolver as any).parameters = [
    CompilerConfig, NgModuleResolver, DirectiveResolver, PipeResolver, SummaryResolver,
    ElementSchemaRegistry,
    DirectiveNormalizer, Console,
    [new Optional(), StaticSymbolCache],
    CompileReflector,
    [new Optional(), new Inject(ERROR_COLLECTOR_TOKEN)]
  ];
  (StyleCompiler as any).parameters = [UrlResolver];
  (ViewCompiler as any).parameters = [CompileReflector];
  (NgModuleCompiler as any).parameters = [CompileReflector];
  (NgModuleResolver as any).parameters = [CompileReflector];
  (DirectiveResolver as any).parameters = [CompileReflector];
  (PipeResolver as any).parameters = [CompileReflector];

  (JitCompiler as any).parameters = [
    Injector,
    CompileMetadataResolver,
    TemplateParser,
    StyleCompiler,
    ViewCompiler,
    NgModuleCompiler,
    SummaryResolver,
    CompilerConfig,
    Console
  ];
  (UrlResolver as any).parameters = [[new Inject(PACKAGE_ROOT_URL)]];
}

And it seems to be risky as compiler is subject to internal changes. It works for @angular/compiler@4.4.5 but may not work for other releases.

查看更多
登录 后发表回答