TL; DR : я пытаюсь использовать Angular Elements в качестве плагинов для Angular приложения. Если я создаю элемент с --prod
, он работает с ng serve
в моем приложении (настройка разработки), но переходит в бесконечную перезагрузку, когда я использую его с ng serve --prod
в моем приложении или после ng build --prod
моего приложения ( настройка производства).
Хотя, если я создаю элемент с добавлением --optimization=false
, он работает с моим продуктивным приложением, но не с настройками разработки.
Дело в том, что я ожидал, что построение Углового элемента с --prod
будет хорошо для обоих случаев.
Вопрос : Есть ли способ решить эту проблему?
Теперь длинное чтение.
На работе мы пытаемся использовать настраиваемые плагины на нашем Angular сайте, где именно сервер сообщает, какой плагин активен или нет.
Мы пытались загружать Angular модули динамически, но это совершенно другая головная боль, которую мы отодвинули на следующий день.
Итак, следующее, что мы хотели попробовать, это Angular Elements , и это вроде как работает, если мы не построим все так, как должно.
Во-первых, я начал следовать этому уроку https://scotch.io/tutorials/build-a-reusable-component-with-angular-elements/amp и игнорировал все, что касается okta
, потому что моя функциональность отличается
Создание:
Я создал свое основное приложение с помощью следующей команды, это будет приложение, в котором размещаются плагины:
ng new core --routing --skip-git --style scss --skip-tests --minimal
Затем я создал плагин / angular-element с помощью этой команды:
ng new plugin --skip-git --style scss --skip-tests --minimal
Plugin:
После всего создания я зашел в свой плагин и прокомментировал эту строку в polyfills.ts
, где-то на этом сайте я прочитал, что это решает проблему уже загруженного NgZone
, и это было правдой:
// import 'zone.js/dist/zone'; // Included with Angular CLI.
В tsconfig.json
я изменил "target": "es5"
на "target": "es2015"
, чтобы исправить проблему с тем, как Angular создает элементы. Не совсем уверен, как это работает, но stackoverflow предложил это, и он добился цели.
Я отредактировал app.module.ts
во что-то вроде следующих идей из учебника и некоторых других, на которые я потерял ссылку:
import { BrowserModule } from '@angular/platform-browser';
import { CUSTOM_ELEMENTS_SCHEMA, Injector, NgModule } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
],
providers: [
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA,
],
entryComponents: [
AppComponent,
],
})
export class AppModule {
constructor(private injector: Injector) {
const elem = createCustomElement(AppComponent, { injector: this.injector });
customElements.define('my-plugin', elem);
}
ngDoBootstrap() {
}
}
Примечание : я добавил CUSTOM_ELEMENTS_SCHEMA
, потому что я где-то нашел его, но он не решил (также я не уверен, что он делает).
В app.component.ts
я сделал это, чтобы иметь некоторое свойство для отображения в шаблоне:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
public content: any = {
a: 10,
b: '20',
}
}
И app.component.html
выглядит так:
Some content:
{{content | json}}
В файле package.json
у меня есть три сценария для сборки всех:
{
"scripts": {
"build": "npm run build:opt && npm run build:noopt",
"build:opt": "ng build --prod --output-hashing none && node build-elements.js",
"build:noopt": "ng build --prod --output-hashing none --optimization=false && node build-elements.noopt.js"
}
}
Файл build-elements.js
выглядит следующим образом (build-elements.noopt.js
совпадает с другим именем назначения):
'use strict';
const concat = require('concat');
const fs = require('fs-extra');
const path = require('path');
(async function build() {
const files = [
'./dist/plugin/runtime.js',
'./dist/plugin/polyfills.js',
'./dist/plugin/scripts.js',
'./dist/plugin/main.js',
];
const destinationDir = path.join(__dirname, '../core/src/assets');
await fs.ensureDir(destinationDir);
await concat(files, path.join(destinationDir, 'my-plugin.js'));
})();
Core:
Для хост-приложения я добавил компонент с именем embedded
и к нему идет маршрут по умолчанию.
Затем я изменил embedded.component.html
на что-то вроде этого, используя несколько Bootstrap классов:
Loading...
Наконец, embedded.component.ts
закончилось так, чтобы показать действительный механизм загрузки:
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { environment } from '../../environments/environment';
@Component({
selector: 'app-embedded',
templateUrl: './embedded.component.html',
})
export class EmbeddedComponent implements OnInit {
@ViewChild('container') public container: ElementRef;
constructor(protected activatedRoute: ActivatedRoute) {
}
ngOnInit() {
this.activatedRoute.queryParams.subscribe((params: Params) => {
const script = document.createElement('script');
if (params['how-it-should-be'] !== undefined) {
script.src = environment.production ? '/assets/my-plugin.js' : '/assets/my-plugin-no-optimization.js';
} else {
script.src = environment.production ? '/assets/my-plugin-no-optimization.js' : '/assets/my-plugin.js';
}
document.body.appendChild(script);
const div = document.createElement('div');
div.innerHTML = '<my-plugin></my-plugin>';
this.container.nativeElement.innerHTML = '';
this.container.nativeElement.appendChild(div);
});
}
}
Запуск:
Если я запускаю ng serve
и просматриваю http://localhost:4200
, страница загружается без проблем, вставляет плагин, добавляет новый элемент в DOM и отображает сообщение от моего плагина.
И если вы отладите приложение, вы увидите, что оно загружает /assets/my-plugin.js
, созданное для производства. Это не будет проблемой, разве что для отладки.
Затем, если я запускаю ng serve --prod
(или собираю его для производства), он также работает нормально, но загружает /assets/my-plugin-no-optimization.js
, тот, который создан для "отладки".
Это решение, которое я использовал в нашем реальном приложении, но, как вы видите, я не использую оптимизированный код в своем плагине для производства, и это нехорошо ... вообще.
Чтобы доказать мою точку зрения, если я перейду к http://localhost:4200/?how-it-should-be
, он попытается загрузить оптимизированный плагин для ng serve --prod
и отладочный плагин для ng serve
. Имейте в виду, что это приведет к бесконечной перезагрузке, откройте инструменты разработчика браузера, чтобы увидеть его.
Конечный продукт, который мы используем, гораздо сложнее, но в этих примерах есть базовая логика, которая на самом деле не работает.
Я также создал репозиторий GitHub, где вы можете увидеть эти коды и сами попробовать решить проблему, или использовать в качестве примера для своих собственных идей.
Если вам интересно, как я узнал, что с помощью --optimization=false
вроде как исправил, ну, я пытался отладить эту проблему (которая оказалась невозможной), и вдруг она загрузилась.
Я посмотрел на время и опоздал на два часа для производственного развертывания, поэтому добавил этот ужасный механизм для загрузки разных сборок в зависимости от среды.
Он работает как в разработке, так и в производстве, но я не горжусь этим.
Извините, если мой английский плохой ... нет нет нет, мой английский плохой, извините ^ __ ^