Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten in custom element
我使用角度自定义元素功能(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"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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); } } |
1 2 3 4 5 6 7 8 9 | angular (parent app) index.html <!doctype html> <html lang="en"> <body> </app-root> <script src="./assets/elements.js"> </body> </html> |
1 2 3 4 5 6 7 | 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; |
1 2 | app.component.html <test-card [data]="{id:"foo"}"></test-card> |
错误Zone.js检测到ZoneAwarePromise
为了避免麻烦,建议在使用Angular Elements时删除Zone并自己进行更改检测。
1 2 3 | platformBrowserDynamic() .bootstrapModule(MainModule, { ngZone: 'noop'}) .catch(err => console.error(err)); |
然后确保将其从PolyFills中删除。
我们不能多次加载zonejs。原因是一旦
话虽这么说,在另一个Angular应用程序内部也有100%的可能包含角度元素。我们需要照顾的只是在父/ shell /主机应用程序中仅将区域js加载一次,并在所有Web组件(Angular Elements)中共享它。
在引导多个元素时,我们可以添加不加载/修补zonejs的逻辑(如果已经加载的话),如下所示:
从polyfill.ts中删除所有Angular Elements的zonejs polyfill
在main.ts级别中创建一个文件。假设bootstraper.ts:
从polyfill.ts中删除所有Angular Elements的zonejs polyfill
创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 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 = 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 { 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); }); } } |
在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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中使用。
注意其他选项是从
谢谢