与Angular 4 AoT一起用作useValue提供程序时,窗口未定义

Est*_*ask 5 javascript typescript angular-compiler-cli angular2-aot angular

提前编译Angular 4.0.2应用程序并将提供程序定义为 useValue

import { OpaqueToken, Provider } from '@angular/core';

export const windowToken = new OpaqueToken('window');
export const windowProvider = { provide: windowToken, useValue: window };
Run Code Online (Sandbox Code Playgroud)

并像

@NgModule({ providers: [windowProvider], ... })
export class AppModule {}
Run Code Online (Sandbox Code Playgroud)

它可以编译,但是当windowundefined注入时

constructor(@Inject(windowToken) window) {
   window.navigator...
}
Run Code Online (Sandbox Code Playgroud)

在引导时抛出错误:

TypeError:无法读取未定义的属性“ navigator”

仔细查看自动生成的app.module.ngfactory.js,看起来确实是这样undefined

...
import * as import39 from './window';
var AppModuleInjector = (function (_super) {
    ...
    AppModuleInjector.prototype.createInternal = function () {
        ...
        this._windowToken_26 = undefined;
        this._SomeService_27 = new import16.SomeService(this._windowToken_26);
    }
    AppModuleInjector.prototype.getInternal = function (token, notFoundResult) {
        ...
        if ((token === import39.windowToken)) {
            return this._windowToken_26;
        }
        ...
Run Code Online (Sandbox Code Playgroud)

当使用与相同的服务时useFactory,一切正常:

export function windowFactory() {
  return window;
}
export const windowProvider = { provide: windowToken, useFactory: windowFactory };
Run Code Online (Sandbox Code Playgroud)

在这里window用作useValue提供者到底有什么问题?这是一个已知的陷阱吗?此限制适用于所有全局变量还是所有useValue提供程序?

New*_*per 3

我也遇到了类似的问题,但问题出在 SignalrWindow 上。但概念和错误是相同的。

然后我在这里找到了这篇文章(https://blog.sstorie.com/integrating-angular-2-and-signalr-part-2-of-2/),文章底部的一些评论对我有所帮助我来解决问题。

基本上,它归结为在提供程序中使用工厂方法而不是 useValue 。我不确定为什么这是一个问题,但我确实知道这种方法解决了 aot 问题。

修复步骤:

创建一个导出的函数

export function windowFactory(): any {
    return window;
}
Run Code Online (Sandbox Code Playgroud)

然后在核心模块中的@NgModule提供程序中,您可以执行以下操作:

...
providers: [
    { provide: SignalrWindow, useFactory: windowFactory }
  ]
...
Run Code Online (Sandbox Code Playgroud)

基本上,您可以根据需要重命名这些方法(因此,在您的示例中,它是:)

export const windowProvider = { provide: windowToken, useFactory: windowFactory };
Run Code Online (Sandbox Code Playgroud)