4

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

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

在我按照说明书中的 angular.io 步骤精确执行 AoT 和汇总后,我收到错误:“未捕获的 ReferenceError:模块未定义”,我不知道为什么会发生这种情况。

我的 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]
})

有人在外面,请帮助!

4

2 回答 2

3

更新: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. 创建以下类: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。注意我在这个组件中内联模板以进一步简化构建。对于应用程序中的其他组件,可以使用“模板”来内联 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 代码库,只是针对这种用法稍作修改。

于 2016-09-28T01:52:11.480 回答
1

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

  1. 删除 moduleId:module.id
  2. templateUrl: 'Home.component.html'替换为 template: require('to-string!./Home.component.html.html')

    @Component({
    选择器:'rf-home',
    模板:require('to-string!./Home.component.html.html'),
    提供者:[HomeService]
    })

于 2016-11-26T12:27:30.587 回答