AngularJS + Angular 8无法一起使用[混合应用程序]

时间:2019-10-01 15:11:35

标签: angularjs angular typescript angular-cli ng-upgrade

我有一个迁移大型的angularjs应用程序的用例,我想首先在一个小型应用程序中进行此过程。因此,出于这个原因,我参观了angularjs webapp英雄,并开始向其中添加angular(通过使用angular-cli创建一个新项目),然后添加NgUpgrade模块。

我现在遇到的问题是,angularjs Web应用程序在angular 8应用程序中运行得很好,但是属于angular 8的组件却未呈现。

我的印象是,由于我手动启动了angularjs,所以我的角度组件没有被引导,但是我不确定...当我在@NgModules中显式添加bootstrap属性时,它仅适用于角度组件,但不起作用对于angularjs(这是有道理的)。所以我在想也许我必须升级angularjs组件或降级最新的angular组件,但我不这么认为。

Here,您将找到带有代码的git存储库。以下是与我的项目有关的更多信息:

  • 角度版本:8.2.8
  • angularJS版本:1.6.10
  • angular-cli:8.3.6

项目结构

enter image description here

index.html

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Common</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>

<body>
  <app-root></app-root>
  <hero-list></hero-list>
</body>

</html>

index.ts(angularjs根模块)

// initialize root module and make it exportable to be able to bootstrap it
// inside angular
export const heroAppModule = angular.module('heroApp', [
    'ngMaterial',
    'perfect_scrollbar',
    'ngJsTree',
    'ngTagsInput',
    'ui.router',
    'heroApp.underscore'
]).config(['$stateProvider', function ($stateProvider) {
    var heroState = {
        name: 'hero',
        url: '/hero',
        template: '<hero-list></hero-list>'
    };
    $stateProvider.state(heroState);
}]);

/** start: REQUIRE ZONE for angularjs
 * Add angularjs files since they aren't yet fully ES6 modules
 * we use requirejs as module loader
 */
require('./editable-field/editable-field');
require('./hero-detail/hero-detail');
require('./hero-list/hero-list');
require('./underscore/underscore.module');
require('./underscore/underscore.service');
/**
 * end: REQUIRE ZONE for angularjs
 */

app.module.ts(使用NgUpgrade引导angularjs)

import * as angular from 'angular';
import { UpgradeModule, setAngularJSGlobal } from '@angular/upgrade/static';

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { heroAppModule } from './../ngjs/index';
import { HelloworldComponent } from './helloworld/helloworld.component';

@NgModule({
  declarations: [ HelloworldComponent ],
  imports: [
    BrowserModule,
    UpgradeModule
  ] // ,
   // bootstrap: [HelloworldComponent]
})


export class AppModule {
  constructor(private upgrade: UpgradeModule) { }
  ngDoBootstrap() {
      setAngularJSGlobal(angular);
      this.upgrade.bootstrap(document.body, [heroAppModule.name], { strictDi: true });
  }
 }

main.ts

import 'zone.js/dist/zone';  // Included with Angular CLI.
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/ngx/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

英雄列表组件(angularjs)

declare var angular: angular.IAngularStatic;

(function () {
    'use strict';
    angular.module('heroApp').component('heroList', {
        template: require('html-loader!./hero-list.html'),
        controller: HeroListController,
        controllerAs: 'vm'
    });

    HeroListController.$inject = ['$scope', '$element', '$attrs'];

    function HeroListController($scope, $element, $attrs) {
        var vm = this;

        vm.list = [
            {
                name: 'Superman',
                location: 'The sky'
            },
            {
                name: 'Batman',
                location: 'Baticueva'
            }
        ];

        vm.updateHero = function (hero, prop, value) {
            hero[prop] = value;
        };

        vm.deleteHero = function (hero) {
            var idx = vm.list.indexOf(hero);
            if (idx >= 0) {
                vm.list.splice(idx, 1);
            }
        };
    }
})();

应用程序根组件(文件名:helloworld.component)

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './helloworld.component.html',
  styleUrls: ['./helloworld.component.scss']
})
export class HelloworldComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

应用程序根模板

<p>helloworld works!</p>

angular.json(angular-cli文件)  

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "common": {
      "projectType": "application",
      "schematics": {
        "@schematics/angular:component": {
          "style": "scss"
        }
      },
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/common",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": false,
            "assets": [
              "src/favicon.ico",
              "src/assets"            ],
            "styles": [
              "bower_components/jstree/dist/themes/default/style.min.css",
              "bower_components/ng-tags-input/ng-tags-input.bootstrap.min.css",
              "bower_components/utatti-perfect-scrollbar/css/perfect-scrollbar.css",
              "bower_components/angular-material/angular-material.css",
              "src/styles.scss"
            ],
            "scripts": [
              "bower_components/jquery/dist/jquery.js",
              "bower_components/angular/angular.js",
              "bower_components/angular-material/angular-material.js",
              "bower_components/angular-animate/angular-animate.js",
              "bower_components/angular-aria/angular-aria.js",
              "bower_components/jstree/dist/jstree.js",
              "bower_components/ng-js-tree/dist/ngJsTree.js",
              "bower_components/ng-tags-input/ng-tags-input.js",
              "bower_components/utatti-perfect-scrollbar/dist/perfect-scrollbar.js",
              "bower_components/angular-perfect-scrollbar/src/angular-perfect-scrollbar.js",
              "node_modules/@uirouter/angularjs/release/angular-ui-router.min.js",
              "node_modules/underscore/underscore.js"
            ]
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "common:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "common:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "common:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.scss"
            ],
            "scripts": []
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "tsconfig.app.json",
              "tsconfig.spec.json",
              "e2e/tsconfig.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        },
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "common:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "common:serve:production"
            }
          }
        }
      }
    }},
  "defaultProject": "common"
}

结果...

Result

3 个答案:

答案 0 :(得分:0)

隔离Angular 1代码和Angular 8代码

<body>
  <app-root></app-root>
<div ng-controller="MyController">
  <hero-list></hero-list>
</div>
</body>

答案 1 :(得分:0)

最后,我发现我需要的解决方案永远不会在应用程序的根部同时使用每个框架的两个组件。取而代之的是,我使用了以下模式作为有角度的documentation

  

一旦运行混合应用程序,就可以开始逐步升级代码的过程。执行此操作的更常见模式之一是在AngularJS上下文中使用Angular组件。这可能是一个全新的组件,也可能是以前的AngularJS但已为Angular重写的组件。

因此,由于我的旧应用程序是用angularjs编写的,因此该框架将始终包含我的根应用程序,并且还将成为我将来所有功能的包装。因此,如果有一天我决定在Angular 8中编写一个新组件,则该组件将存在于angularjs中,并且将其降级以使其能够正常工作。

答案 2 :(得分:0)

即使在index.html中,我也遇到了类似的问题:

<body>
  <app-root></app-root>
</body>

我发现通过设置Angular docs for ngUpgrade,顶级组件需要是来自Angular.js的组件,而不是来自Angular的组件:

<body>
  <hero-list></hero-list>
</body>