window 用作具有 Angular 4 AoT 的 useValue 提供程序时未定义
window is undefined when used as useValue provider with Angular 4 AoT
当Angular 4.0.2 应用程序提前编译时,提供程序定义为useValue
import { OpaqueToken, Provider } from '@angular/core';
export const windowToken = new OpaqueToken('window');
export const windowProvider = { provide: windowToken, useValue: window };
并像
一样使用
@NgModule({ providers: [windowProvider], ... })
export class AppModule {}
它编译正常,但在注入时 window
为 undefined
constructor(@Inject(windowToken) window) {
window.navigator...
}
引导时抛出错误:
TypeError: Cannot read property 'navigator' of undefined
仔细查看自动生成的 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;
}
...
当使用与useFactory
相同的服务时,一切正常:
export function windowFactory() {
return window;
}
export const windowProvider = { provide: windowToken, useFactory: windowFactory };
这里使用 window
作为 useValue
提供商到底有什么问题?这是一个已知的陷阱吗?此限制是否适用于所有全局变量或所有 useValue
提供程序?
我遇到了类似的问题,但它与 SignalrWindow 有关。尽管概念和错误是相同的。
然后我在这里找到这篇文章(https://blog.sstorie.com/integrating-angular-2-and-signalr-part-2-of-2/),文章底部有一些评论帮助我解决了问题。
基本上,它归结为在提供者中使用工厂方法而不是 useValue。我不确定为什么会出现问题,但我知道这种方法可以解决 aot 问题。
修复步骤:
创建导出的函数
export function windowFactory(): any {
return window;
}
然后在核心模块中,在 @NgModule
提供程序中你可以这样做:
...
providers: [
{ provide: SignalrWindow, useFactory: windowFactory }
]
...
基本上,您可以根据自己的喜好重命名这些方法(因此,在您的示例中它将是:)
export const windowProvider = { provide: windowToken, useFactory: windowFactory };
在 AoT 编译期间,angular CLI 静态分析代码也会生成 ngmodule.factory 文件。它看到 "useValue" 并检查静态值是否可用并将其放入 ngmodule.factory。在编译期间,这个值不可用,所以它保留了那个提供者值,因此,当注入构造函数时,它被 returned 为 "undefined"。
但是,提供 "useFactory" 的目的完全相同,在 运行 之前您不知道自己的价值。
因此,useValue 在您的方案中不起作用,但 "useFactory" 会起作用。
底线:当 AOT 编译时,只有当你有常量字符串或数字等静态值时才使用 "useValue"。否则使用 "useFactory" 到 return 运行-时间计算 object/values。
当Angular 4.0.2 应用程序提前编译时,提供程序定义为useValue
import { OpaqueToken, Provider } from '@angular/core';
export const windowToken = new OpaqueToken('window');
export const windowProvider = { provide: windowToken, useValue: window };
并像
一样使用@NgModule({ providers: [windowProvider], ... })
export class AppModule {}
它编译正常,但在注入时 window
为 undefined
constructor(@Inject(windowToken) window) {
window.navigator...
}
引导时抛出错误:
TypeError: Cannot read property 'navigator' of undefined
仔细查看自动生成的 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;
}
...
当使用与useFactory
相同的服务时,一切正常:
export function windowFactory() {
return window;
}
export const windowProvider = { provide: windowToken, useFactory: windowFactory };
这里使用 window
作为 useValue
提供商到底有什么问题?这是一个已知的陷阱吗?此限制是否适用于所有全局变量或所有 useValue
提供程序?
我遇到了类似的问题,但它与 SignalrWindow 有关。尽管概念和错误是相同的。
然后我在这里找到这篇文章(https://blog.sstorie.com/integrating-angular-2-and-signalr-part-2-of-2/),文章底部有一些评论帮助我解决了问题。
基本上,它归结为在提供者中使用工厂方法而不是 useValue。我不确定为什么会出现问题,但我知道这种方法可以解决 aot 问题。
修复步骤:
创建导出的函数
export function windowFactory(): any {
return window;
}
然后在核心模块中,在 @NgModule
提供程序中你可以这样做:
...
providers: [
{ provide: SignalrWindow, useFactory: windowFactory }
]
...
基本上,您可以根据自己的喜好重命名这些方法(因此,在您的示例中它将是:)
export const windowProvider = { provide: windowToken, useFactory: windowFactory };
在 AoT 编译期间,angular CLI 静态分析代码也会生成 ngmodule.factory 文件。它看到 "useValue" 并检查静态值是否可用并将其放入 ngmodule.factory。在编译期间,这个值不可用,所以它保留了那个提供者值,因此,当注入构造函数时,它被 returned 为 "undefined"。
但是,提供 "useFactory" 的目的完全相同,在 运行 之前您不知道自己的价值。
因此,useValue 在您的方案中不起作用,但 "useFactory" 会起作用。
底线:当 AOT 编译时,只有当你有常量字符串或数字等静态值时才使用 "useValue"。否则使用 "useFactory" 到 return 运行-时间计算 object/values。