【问题标题】:various errors when attempting to integrate aframe into angular2 project esp. with unit tests尝试将 aframe 集成到 angular2 项目 esp 时出现各种错误。带有单元测试
【发布时间】:2018-03-09 21:35:33
【问题描述】:

我在让 aframe 0.7.0 在我的 angular 4.3.6 (angular-cli 1.0.0) 项目中正常工作时遇到问题。我收到的一些消息:

Chrome 61.0.3163 (Windows 10 0.0.0) LOG: '%cA-Frame:warn %cPut the A-Frame <script> tag in the <head> of the HTML *before* the scene to ensure everything for A-Frame is properly registered before they are used from HTML.%c ', 'color: orange', 'color: inherit', 'color: orange'

和: 'a-assets' is not a known element: 1. If 'a-assets' is an Angular component, then verify that it is part of this module. 2. If 'a-assets' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. (" lss-aframe-component tats #introScene> <!-- <ng-template appGameScene></ng-template> --> [ERROR ->]<a-assets>

aframe 与其他 JS 库不同的一大问题似乎是它需要从 &lt;head&gt; 元素而不是 &lt;body&gt; 元素加载。

我在 stackoverflow here herehere 上找到了一些部分解决方案,但所提供的解决方案都不能在我所有的“ng serve”和“ng test”环境中运行。特别是,我很难让单元测试在引用 AFRAME 命名空间的组件上工作。

将 aframe 集成到 Angular2 环境中需要做什么,包括单元测试?

【问题讨论】:

    标签: angular aframe


    【解决方案1】:

    为了将框架完全集成到 Angular 中,我必须这样做。我并不是说这一定是最好的方法,或者 必须做这一切。有些人似乎能够摆脱更简单的解决方案,如果这些解决方案对您有用(例如简单的adding the aframe lib into polyfill.ts),那么就去做吧。显然,解决方案可能会随着角度发布而有所不同,如果您没有运行单元测试,那么您不需要执行我在此处描述的所有操作。

    您需要关注的大文件有:

    .angular-cli.json
    karma.conf.js
    src/app/app.module.ts
    src/index.html
    all your .spec.ts files
    

    ng 服务环境

    1) 要让您的“ng serve”(网络)环境从头部加载 aframe.js,请将 aframe.js 库添加到“src/index.html”,如下所示:

    <!doctype html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>My app</title>
      <base href="/">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
      <script src="../node_modules/aframe/dist/aframe-master.js"></script>
      ...
    

    注意:你不需要为 three.js 添加脚本标签,因为 aframe 会预先请求它。

    注意 2:您也可以使用 'node_modules'/aframe/build/aframe.js'。 'aframe-master.js' 更像是一个'流血边缘不稳定'的构建,但它对我来说已经足够好了。

    注 3(更新为 '2018-01-10'):虽然我似乎能够使用 angular 4 的“../node_modules”,但使用 angular5 我必须复制 'aframe-master.js' 和 'aframe -master.js.map' 到 'assets' 的子目录中,例如'src/assets/libs'。简而言之,Angular 5 似乎要求从“/assets”(?)加载外部 js 库。

    通常,您应该在.angular.cli.jsonscripts 标记中包含javascript 库,但是如果您将它们放在那里,它们将不会从头部加载。我的scripts 标签目前是空的,但是你应该把任何其他的js库放在那里并且放在index.html中:

    cat .angular-cli.json
    {
      "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
      "project": {
        "name": "lss"
      },
      "apps": [
        {
          "root": "src",
          "outDir": "dist",
          "assets": [
            "assets",
            "favicon.ico"
          ],
          "index": "index.html",
          "main": "main.ts",
          "polyfills": "polyfills.ts",
          "test": "test.ts",
          "tsconfig": "tsconfig.app.json",
          "testTsconfig": "tsconfig.spec.json",
          "prefix": "app",
          "styles": [
            "styles.css"
          ],
          "scripts": [
          ],
          "environmentSource": "environments/environment.ts",
    

    注意脚本是空白的,并且 包含 aframe.js

    2) 将“CUSTOM_ELEMENTS_SCHEMA”添加到“src/app/app.module.ts”:

    import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
    ...
    entryComponents: [AppComponent, PlaneSceneComponent],
     bootstrap: [AppComponent],
     schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
    })
    export class AppModule { }
    

    注意:CUSTOM_ELEMENTS_SCHEMA 允许在您的 Angular html 中使用非角度标签(例如 &lt;a-scene&gt;)。

    如果您不运行单元测试,那就差不多了。业力测试环境完全独立于标准的基于 Web 的环境。如果您计划进行单元测试,请执行以下附加步骤来设置测试环境。

    ng 测试环境

    3) 更新 karma.conf.js 以了解 aframe 和 three.js 并指定自定义上下文文件:

    --> 2018-03-08 更新:从 angular cli 1.7.3 开始,“customContextFile”似乎不再受 angular 支持。它似乎也无法再从 node_modules 读取文件了——你必须将 aframe-master.lib 放在 'src/assets/' 下。我不得不像这样直接编辑'node_modules/@angular/cli/plugins/karma-context.html':

    <head>
      <title></title>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
      <!--user add -->
      <script type="text/javascript" src="/base/src/assets/libs/aframe-master.js" crossorigin="anonymous"></script>
      <!--user end -->
    </head>
    

    不幸的是,在我找到更正式的方法来实现此效果之前,必须在每个签出的 repo 上手动执行此 hack,因为大多数人不会签入 node_modules 目录。 以下在 ng-cli 1.7.3 之前有效:

    module.exports = function (config) {
      config.set({
        basePath: '',
        frameworks: ['jasmine', '@angular/cli'],
        plugins: [
          require('karma-jasmine'),
          require('karma-chrome-launcher'),
          require('karma-jasmine-html-reporter'),
          require('karma-coverage-istanbul-reporter'),
          require('@angular/cli/plugins/karma')
        ],
        //user add
        customContextFile: './src/environments/context_aframe_ut.html',
        //user end
        client:{
          clearContext: false // leave Jasmine Spec Runner output visible in browser
        },
        files: [
          { pattern: './src/test.ts', watched: false },
          //user add
          { pattern: 'node_modules/aframe/dist/aframe-master.js', included: false, served: true },
          { pattern: 'node_modules/three/build/three.js', included: false, served: true }
          //user end
        ],
        preprocessors: {
          './src/test.ts': ['@angular/cli']
        },
        mime: {
          'text/x-typescript': ['ts','tsx']
        },
        coverageIstanbulReporter: {
          reports: [ 'html', 'lcovonly' ],
          fixWebpackSourcePaths: true
        },
        angularCli: {
          environment: 'dev'
        },
        reporters: config.angularCli && config.angularCli.codeCoverage
                  ? ['progress', 'coverage-istanbul']
                  : ['progress', 'kjhtml'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        browsers: ['Chrome'],
        singleRun: false
      });
    };
    

    注意:被“//user add”和“//user end”块包围的代码段。第一个定义了一个新的“context.html”文件,我们将创建该文件将从&lt;head&gt; 标签加载aframe.js。第二个定义了 karma 的 aframe 和 three.js 库。

    4) 创建一个新的 karma 上下文 html 文件以从头部加载框架。

    --> 2018-03-08 更新:请注意 ang-cli 1.7.3,因为不再支持“customContextFile”,您不必执行此步骤。按照上一步中的说明编辑“node_modules/@angular/cli/plugins/karma-context.html”。

    将文件“node_modules/karma/static/context.html”复制到之前定义的“customContextFile”目录中,然后修改如下:

    <!DOCTYPE html>
    <!--
    This is the execution context.
    Loaded within the iframe.
    Reloaded before every execution run.
    vt was here 3.
    -->
    <html>
    <head>
      <title></title>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
      <!--user add -->
      <!-- <script src="aframe-master.js"></script> -->
      <script src="/base/node_modules/aframe/dist/aframe-master.js"></script>
      <!--user end -->
    </head>
    <body>
      <!-- The scripts need to be in the body DOM element, as some test running frameworks need the body
           to have already been created so they can insert their magic into it. For example, if loaded
           before body, Angular Scenario test framework fails to find the body and crashes and burns in
           an epic manner. -->
      <script src="context.js"></script>
      <script type="text/javascript">
        // Configure our Karma and set up bindings
        %CLIENT_CONFIG%
        window.__karma__.setupContext(window);
    
        // All served files with the latest timestamps
        %MAPPINGS%
      </script>
      <!-- Dynamically replaced with <script> tags -->
      %SCRIPTS%
      <script type="text/javascript">
        window.__karma__.loaded();
      </script>
    </body>
    </html>
    

    注意:“//用户添加”和“//用户端”部分再次出现。
    注意 2:您必须在 aframe 库前面加上 '/base' 才能让 karma 找到它。请注意我放弃了使无前缀版本工作的尝试。
    注 3:(可选)在开头注释中添加一些文本,例如'vt was here' 这样您就可以更轻松地验证 Karma 确实在加载您的自定义 context.html。

    5)(可选)验证更新后的 context.html。

    运行 'ng test' 并检查浏览器使用的 html。在节点 'iframe.#document.html.head' 下验证您是否拥有:

    &lt;script src="/base/node_modules/aframe/dist/aframe-master.js"&gt;&lt;/script&gt;

    这证实了业力正在从头部加载帧。

    6) 将“CUSTOM_ELEMENTS_SCHEMA”添加到每个使用 a-frame 的 spec.ts 文件中:

    import { async, ComponentFixture, TestBed } from '@angular/core/testing';
    import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core"; //<- add
    import { RouterTestingModule } from '@angular/router/testing';
    import { LoopySurfaceSurfersComponent } from './loopy-surface-surfers.component';
    import { AsteroidsGame } from '../inner-games/asteroids/asteroids-game';
    import { Ship } from '../inner-games/asteroids/ship';
    import { BaseService } from '../services/base.service';
    import { UtilsService } from '../services/utils.service';
    
    describe('LoopySurfaceSurfersComponent', () => {
      let component: LoopySurfaceSurfersComponent;
      let fixture: ComponentFixture<LoopySurfaceSurfersComponent>;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [ LoopySurfaceSurfersComponent ],
          imports: [RouterTestingModule],
          schemas: [ CUSTOM_ELEMENTS_SCHEMA ], // <- add
          providers: [AsteroidsGame, Ship, UtilsService, BaseService,
            THREE.Scene
          ]
        })
        .compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(LoopySurfaceSurfersComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });
    
      it('should create', () => {
        expect(component).toBeTruthy();
      });
    });
    

    7) 您可能需要循环“ng serve”和“ng test”才能了解更改。

    结论

    如您所见,这并非微不足道。问题的主要来源是从头部加载框架的要求。我希望这可以节省我将 aframe 完全集成到 angular2 环境中所必须付出的所有努力。

    我还应该声明,我非常喜欢 A 型框架,它与 angular 配合得非常好。将这两个框架一起运行是一个很好的组合,绝对值得付出努力,所以如果您遇到配置问题,请不要气馁。

    【讨论】:

    • 我很想执行第 3 步和第 4 步,但它不起作用,业力仍然显示如下错误:“对象不支持属性或方法‘发射’抛出”
    【解决方案2】:

    更新 @vt5491 解决 Angular 单元测试中问​​题的解决方案

    根据您在应用中使用 A-Frame 的方式,这对您来说可能是也可能不是问题。但是,一旦您的测试期望在 DOM 或 window 中定义 AFRAMETHREE,则在 index.html&lt;head&gt; 中导入 A-Frame 可能会中断并阻止您的单元测试运行。

    可以通过创建一个调用AFRAME 的基本脚本文件来重现此错误。您可能想要创建自己的 A-Frame 组件并将它们导入到 Angular 组件中:

    // foo.script.js
    AFRAME.registerComponent('foo', {
      schema: {},
      init: function () {},
      update: function () {},
      tick: function () {},
      remove: function () {},
      pause: function () {},
      play: function () {}
    });
    

    foo.script.js 被导入到要使用的 Angular 组件中:

    // foo.component.ts
    import 'src/script/foo.script.js';
    

    应用程序将在ng serve 下正常运行。这是因为index.html 包含 A-Frame。

    // index.html
    <head>
      <meta charset="utf-8">
      <title>Aframe</title>
      ...
      <script src="../node_modules/aframe/dist/aframe-master.js"></script>
    </head>
    

    您将在 A-Frame 正确启动的地方看到预期的 console.log:

    A-Frame 版本:0.9.2(日期 2019-05-06,提交 #f57a1fa)

    三个版本(https://github.com/supermedium/three.js):^0.102.2

    WebVR Polyfill 版本:^0.10.10

    但是,当我们运行 ng t 时,您会注意到控制台中缺少相同的提示。 A-Frame 不包括在这里。 Karma 在执行单元测试时不包括 A-Frame。相反,Karma 会中断,您的测试将无法完全运行。

    ./src/scripts/foo.script.js?:3 Uncaught ReferenceError: AFRAME is not defined

    因果报应的.html 文件位于:

    node_modules\@angular-devkit\build-angular\src\angular-cli-files\plugins\karma-context.html node_modules\@angular-devkit\build-angular\src\angular-cli-files\plugins\karma-debug.html

    一旦此处包含 A-Frame 的导入 (karma-context.html),那么您的单元测试将包含 A-Frame 并正常运行:

    // karma-context.html
    <head>
      <title></title>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
      <script src="https://aframe.io/releases/1.0.1/aframe.min.js"></script>
    </head>
    

    我们可以通过创建您自己的 karma-context.htmlkarma-debug.html 来自动执行此操作以供将来测试。在 scripts 目录下,为包含 A-Frame 导入的两个 html 文件分别创建一个副本。保持 karma-context.htmlkarma-debug.html 未修改在您的 node_modules 文件夹中。当您的项目被克隆时,内部的更改不会传播,因此我们的修改需要保存在其他地方。

    创建一个脚本,在 karma 运行时将修改后的 html 复制到 node_module 中:

    // scripts/karma-copy.test.js
    const fs = require('fs');
    
    // Modify karma-context.html
    fs.copyFile(
      'src/scripts/karma-context.html',
      'node_modules/@angular-devkit/build-angular/src/angular-cli-files/plugins/karma-context.html',
      (err) => {
        if (err) throw err;
      }
    );
    
    // Modify karma-debug.html
    fs.copyFile(
      'src/scripts/karma-debug.html',
      'node_modules/@angular-devkit/build-angular/src/angular-cli-files/plugins/karma-debug.html',
      (err) => {
        if (err) throw err;
      }
    );
    

    将脚本包含在karma.config.js:

    plugins: [
      require('../src/scripts/karma-copy.test.js'),
      ...
    ],
    

    现在,当您关闭项目时,ng t 将在 &lt;head&gt; 中包含 A-Frame。

    【讨论】:

      猜你喜欢
      • 2020-11-11
      • 2013-01-01
      • 2015-11-02
      • 2023-03-27
      • 2020-04-10
      • 1970-01-01
      • 1970-01-01
      • 2012-01-01
      • 2021-01-25
      相关资源
      最近更新 更多