【问题标题】:Angular2 AoT - module.id is not defined while setting module.id in componentAngular2 AoT - 在组件中设置 module.id 时未定义 module.id
【发布时间】:2017-02-01 10:30:09
【问题描述】:

我正面临 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]
})

有人在那里,请帮忙!

【问题讨论】:

    标签: angular angular2-aot


    【解决方案1】:

    更新: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 中添加以下 sn-p。请注意,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 代码库,只是针对此用法稍作修改。

    【讨论】:

    • 嗨,Brian,感谢您的意见,抱歉回复晚了。我已经添加了一个假人。
    • @Brian :我尝试了您的方法,但仍然失败。一个问题。我应该将@RollupModuleProvider({}) 添加到所有组件中还是仅添加到 AppComponent 中?
    • Abhijith,请参阅我在 10 月 22 日更新的评论的最顶部。Angular 团队更新了 Angular 文档,为该问题提供了更简单的解决方法。
    【解决方案2】:

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

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

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

    【讨论】:

    • 是的,组件装饰器中的moduleId 是一个丑陋的黑客。注意如果使用 SystemJS,这看起来像 import template from './home.component.html'; @Component({template, providers[...],...})
    • 我的印象是使用 AOT 编译时不能使用“require()”调用。这样做会导致这个错误:“调用函数'require',不支持函数调用”
    猜你喜欢
    • 1970-01-01
    • 2016-09-07
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多