更新:2016 年 10 月 22 日
从 Angular 2.1 开始,文档的 AOT 部分(https://angular.io/docs/ts/latest/cookbook/aot-compiler.html)有一个更简单的方法。
<script>window.module = 'aot';</script>
此行位于 aot 构建的 index.html 文件中。
tl;博士
我正在使用的修复是添加一个自定义提供程序,该提供程序检查模块对象在浏览器中是否可用,如果找不到,则将其添加到全局范围中。
创建以下类:rollup-module.provider.ts
export function RollupModuleProvider(params: any) {
return function (target: any) {
// Setup the 'module' variable globally. The rollup javascript has its own module system, but there is still a
// reference to the Commonjs module.id in the code, so setup a module object to allow that code to execute
// without throwing an exception
try {
// In dev mode with commonjs the following line will execute without a problem
// In AoT mode with rollup the following line will trigger an exception that will be
// caught and handled to allow the AoT build to run without issue
let testIfRunningWithCommonJSandModuleIsAvailable = module.id;
} catch (e) {
// Declare Module for rollup based production builds.
// When running dev builds CommonJS automatically provides the module definition
console.log("Defining Module");
var globalScope: any;
if (typeof window === 'undefined') {
globalScope = global;
}
else {
globalScope = window;
}
globalScope.module = "test";
try {
let moduleShouldBeAvailable = module;
}
catch (e) {
// Our attempt to register module failed so we are not in an unrecoverable error state.
console.error("Module not defined");
}
}
}
}
在您的 app.component.ts 中添加以下代码段。请注意,app.component.ts 应该是 app.module.ts 文件中“bootstrap”声明中的类。
import {RollupModuleProvider} from "./rollup-module.provider";
@RollupModuleProvider({})
细节
为了完整起见,这是下面的完整 app.component.ts。注意我在这个组件中内联模板以进一步简化构建。对于应用程序中的其他组件,可以使用“模板”来内联 html,或者可以使用“templateUrl”将 html 放入单独的文件中。对于除主 app.component.ts 之外的所有组件,此选择可以基于个人/项目偏好。
import { Component } from '@angular/core';
import './rxjs-operators';
import {ModalService} from "./shared/modal.service";
import {RollupModuleProvider} from "./rollup-module.provider";
@RollupModuleProvider({})
@Component({
selector: 'myapp',
/* For only the top level component inline the template which simplifies the build process. By in-lining the
* template we don't need to setup the "module: module.id" on the Component decorator. We use the RollupModuleProvider
* to setup the module variable when running in a ngc/rollup build. In a dev build the CommonJs module system is used
* so module.id is available. In a ngc/rollup build the module does not need to be set on the component so it can be
* set to a valid value and then is essentially ignored.
*/
template:
`<div [class.modalDisplayed]="modalService.isModalDisplayed()"></div>
<nav-header></nav-header>
<div class="container-fluid">
<router-outlet> </router-outlet>
</div>`
})
export class AppComponent {
constructor (public modalService: ModalService) {
}
}
这是完整的 app.module.ts。
import {NgModule} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { routing } from './app.routing';
import { Logger } from './logger.service';
import { HttpClient } from './http.client.service';
import {WindowSize} from './window-size.service';
import {ModalService} from "./shared/modal.service";
import {SharedModule} from "./shared/shared.module";
@NgModule({
imports: [BrowserModule, HttpModule, routing, SharedModule],
declarations: [AppComponent],
providers: [ Logger, HttpClient, WindowSize, ModalService ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
详细解释
作为解决方案的一部分,我希望能够在代码中保留 moduleId 定义,以便我可以继续运行 tsc 并使用 commonjs 进行开发。AoT 不需要 moduleId 即可运行。UncaughtReferenceError 发生在具有 AoT 构建的浏览器中,因为浏览器在全局范围(通常是 JavaScript 窗口对象)中没有可用的“模块”。在开发模式下,commonjs 设置了模块,所以没有问题。
由于 AoT 不需要 moduleId,因此修复方法是在 AoT 模式下运行时在浏览器中简单地设置一个模块对象。除了定义模块对象以防止引发引用错误之外,模块对象不需要做任何事情。
设置全局范围的代码来自 angular 2 代码库,只是针对这种用法稍作修改。