我使用角度自定义元素功能(element.js)创建了一个小型应用程序,将该element.js文件导入到index.html中的另一个angular(parent)应用程序中,在开发服务器(ng serve)元素功能中效果很好,但是在生产模式下(ng build --prod)在element.js文件中得到此错误。
@ angular / core“:”〜8.1.3“, @ angular / elements“:” ^ 8.1.3“
element (angular custom element code)
polyfills.ts
import 'zone.js/dist/zone'; // Included with Angular CLI.
import "@webcomponents/custom-elements/src/native-shim";
import "@webcomponents/custom-elements/custom-elements.min";
app.module.ts
export class AppModule {
constructor(private injector: Injector) { }
ngDoBootstrap() {
const el = createCustomElement(NotificationElementComponent, {
injector: this.injector
});
// using built in the browser to create your own custome element name
customElements.define('test-card', el);
}
}
angular (parent app)
index.html
<!doctype html>
<html lang="en">
<body>
<app-root></app-root>
<script src="./assets/elements.js"></script>
</body>
</html>
polyfills.ts
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone'; // Included with Angular CLI.
(window as any).global = window;
app.component.html
<test-card [data]="{id:"foo"}"></test-card>
错误Zone.js检测到ZoneAwarePromise (window|global).Promise
已被覆盖。最可能的原因是在Zone.js之后加载了Promise polyfill(加载zone.js时不需要填充Promise api。如果必须加载,则在加载zone.js之前。)
答案 0 :(得分:1)
为避免让您头疼,建议您在使用Angular Elements时删除Zone并自己进行更改检测。
platformBrowserDynamic()
.bootstrapModule(MainModule, { ngZone: 'noop'})
.catch(err => console.error(err));
然后确保将其从PolyFills中删除。
答案 1 :(得分:0)
我们不能多次加载zonejs。原因是一旦zone
被加载,它就会在不同的窗口函数上进行修补。异常基本上表示相同。
话虽如此,在另一个Angular应用程序内部包含角度元素的可能性为100%。我们需要照顾的是在父/ shell /主机应用程序中仅将区域js加载一次,并在所有Web组件(Angular Elements)中共享它。
在引导多个元素时,我们可以添加不加载/修补zonejs的逻辑(如果已按如下所示加载):
从polyfill.ts中删除所有Angular Elements的zonejs polyfill
在main.ts级别中创建一个文件。假设bootstraper.ts:
从polyfill.ts中删除所有Angular Elements的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
中,我们可以将引导程序逻辑更改为以下内容:
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 Elements(Web组件)并在Angular Shell SPA中使用。
注意 ,其他选项是从zonejs
弹出,但是那样一来,您将不得不手动处理ChangeDetetction。
谢谢