Angular2 AoT - 在组件中设置 module.id 时未定义 module.id

Angular2 AoT - module.id is not defined while setting module.id in component

我正面临 Angular2 AoT 的挑战,任何帮助对我来说都是一个很大的帮助,因为我被困住了。

我有一个简单的 hello world 应用程序,它有 main.js、home.module.ts、home.component.ts、home.component.html 和 home.service.ts。这段代码在没有 AoT 的情况下使用 Angular2 效果很好。

在我完全按照食谱中的 angular.io 步骤执行 AoT 和 Rollup 之后,我收到错误:"Uncaught ReferenceError: module is not defined" 我不知道为什么会这样。

我的Home.Component.ts是这样标记的:

@Component({
    selector: 'rf-home',
    moduleId: module.id,   // i m setting this module.id so that I can use relative template paths in my code. Helps in Dev env.
    templateUrl: 'Home.component.html',
    providers: [HomeService]
})

有人在,请帮忙!

更新: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;博士

我使用的修复方法是添加一个自定义提供程序,检查模块对象在浏览器中是否可用,如果找不到则将其添加到全局范围中。

  1. 创建以下内容class: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");
                }
            }
        }
    }
    
  2. 在您的 app.component.ts 中添加以下代码段。请注意,app.component.ts 应该是 app.module.ts 文件中 "bootstrap" 声明中的 class。

    import {RollupModuleProvider} from "./rollup-module.provider";
    
    @RollupModuleProvider({})
    

详情

为完整起见,下面是完整的 app.component.ts。请注意,我在此组件中内联模板以进一步简化构建。对于应用程序中的其他组件,'template' 可用于内联 html 或 'templateUrl' 可用于将 html 放入单独的文件中。对于除主要 app.component.ts 之外的所有组件,此选择可以基于 personal/project 偏好。

    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 构建的浏览器中,因为浏览器在全局范围内没有可用的 "module"(通常是 JavaScript window 对象)。在开发模式下,commonjs 设置了模块,所以没有问题。

由于 AoT 不需要 moduleId,修复方法是在 运行 处于 AoT 模式时在浏览器中简单地设置一个模块对象。除了被定义以防止抛出引用错误之外,模块对象不需要做任何事情。

设置全局作用域的代码来自 angular 2 代码库,只是为此用法稍作修改。

修复此错误的另一种方法:

  1. 移除 moduleId:module.id
  2. templateUrl: 'Home.component.html' 替换为 模板: 要求('to-string!./Home.component.html.html')

    @Component({
    选择器:'rf-home',
    模板:要求('to-string!./Home.component.html.html'),
    提供商:[家庭服务]
    })