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

标签 angular angular2-aot

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

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

在我按照 cookbook 中的 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;dr

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

  1. 创建以下类: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”声明中的类。

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

详情

为了完整起见,这是下面的完整 app.component.ts。请注意,我在此组件中内联模板以进一步简化构建。对于应用程序中的其他组件,"template"可用于内联 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 代码库,只是为此用途稍作修改。

关于Angular2 AoT - 在组件中设置 module.id 时未定义 module.id,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39662863/

相关文章:

android - 背景中带有 ionic 2 的 FCM 无法正常工作

javascript - Angular 4 - 使用元素的 Id 在 DOM 中显示/隐藏元素

javascript - 类具有或正在使用外部模块中的名称 'SafeUrl' 但无法命名

javascript - 通过单击 IFrame(内联框架)中的项目,我需要路由到特定的 URL

angular - 如何在 Angular 中检索组件的元数据

node.js - Angular universal 正在为每个页面在页面源中呈现主页 html

javascript - angular2 AoT错误不支持函数调用

angular - AOT 构建将组件模板留在最终包中

angular-cli - 令人困惑的 Angular-cli AOT 错误