是否可以使用由不同版本的 Angular 构建的不同 angular 元素

Is it possible to use different angular elements built with different versions of Angular

我想知道是否可以使用由不同版本的 Angular 构建的不同 angular 元素(自定义元素)。 我听说 zone.js 污染了全局范围。

感谢您的回答。

是的,你没有听错。如果从特定版本创建的每个 angular 元素都试图加载 zonejs,我们不能使用多个 angular 元素。

话虽如此,在一个页面上有多个 angular 个不同版本的元素是 100% 可能的。我们需要注意的是只加载一次 zone js 并在所有 web 组件(Angular 元素)之间共享它。

虽然 bootstrapping 多个元素我们可以添加 not loading/patching zonejs 的逻辑,如果已经加载如下:

从 polyfill.ts 中删除所有 Angular 元素的 zonejs polyfill

main.ts 级别创建一个文件。假设 bootstraper.ts :

export class Bootstrapper {
  constructor(
    private bootstrapFunction: (bootstrapper: Bootstrapper) => void
  ) {}

  /**
   * Before bootstrapping the app, we need to determine if Zone has already
   * been loaded and if not, load it before bootstrapping the application.
   */
  startup(): void {
    console.log('NG: Bootstrapping app...');

    if (!window['Zone']) {
      // we need to load zone.js
      console.group('Zone: has not been loaded. Loading now...');
      // This is the minified version of zone
      const zoneFile = `/some/shared/location/zone.min.js`;

      const filesToLoad = [zoneFile];

      const req = window['require'];
      if (typeof req !== 'undefined') {
        req(filesToLoad, () => {
          this.bootstrapFunction(this);
          console.groupEnd();
        });
      } else {
        let sequence: Promise<any> = Promise.resolve();
        filesToLoad.forEach((file: string) => {
          sequence = sequence.then(() => {
            return this.loadScript(file);
          });
        });

        sequence.then(
          () => {
            this.bootstrapFunction(this);
            console.groupEnd();
          },
          (error: any) => {
            console.error('Error occurred loading necessary files', error);
            console.groupEnd();
          }
        );
      }
    } else {
      // zone already exists
      this.bootstrapFunction(this);
    }
  }

  /**
   * Loads a script and adds it to the head.
   * @param fileName
   * @returns a Promise that will resolve with the file name
   */
  loadScript(fileName: string): Promise<any> {
    return new Promise(resolve => {
      console.log('Zone: Loading file... ' + fileName);
      const script = document.createElement('script');
      script.src = fileName;
      script.type = 'text/javascript';
      script.onload = () => {
        console.log('\tDone');
        resolve(fileName);
      };
      document.getElementsByTagName('head')[0].appendChild(script);
    });
  }
}

并且在 main.ts 中我们可以将 bootstrap 逻辑更改为以下逻辑:

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { Bootstrapper } from './bootstraper';
const bootstrapApp = function(): void {
  platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .then(() => {})
    .catch(err => console.error(err));
};

const bootstrapper = new Bootstrapper(bootstrapApp);
bootstrapper.startup();

这样我们绝对可以创建多个 Angular 元素(Web 组件)并在 SPA 中使用。

谢谢