Как скомпилировать угловой элемент в веб-компонент с Webpack или угловым CLI?
Я создал простой Web-компонент через Angular, используя учебник Pascal Precht, который вы можете увидеть ЗДЕСЬ. Он автоматически волшебно компилируется в Stackblitz в ссылке, но не локально.
Моя конечная цель состоит в том, чтобы локально получить код для результирующего веб-компонента в отдельном файле. В конце концов, я буду загружать его куда-нибудь и вытягивать через один <script>
тег, как и обычные веб-компоненты raw-html/javascript. Я думаю, что вопрос говорит сам за себя, но вы можете прочитать подробности ниже, если хотите:
Детали:
Чтобы подвести итог моего кода по ссылке выше, у меня есть очень простой компонент:
import { Component } from '@angular/core';
@Component({
selector: 'hello-world',
template: `<h1>Hello world</h1>`
})
export class HelloComponent {}
и у меня есть модуль:
import { NgModule, Injector } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { createCustomElement } from '@angular/elements'
import { HelloComponent } from './hello.component';
@NgModule({
imports: [BrowserModule],
declarations: [HelloComponent],
entryComponents: [HelloComponent]
})
export class AppModule {
constructor(private injector: Injector) {}
ngDoBootstrap() {
const HelloElement = createCustomElement(HelloComponent, {
injector: this.injector
});
customElements.define('hello-world', HelloElement);
}
}
Вот объяснение модуля выше:
- Добавить мой компонент в
entryComponents
массив, поэтому он не удаляется угловым шейкером (так как он недоступен при загрузке приложения:entryComponents: [HelloComponent]
Запустите мой компонент через
createCustomElement
функция, так что я могу использовать его как обычный HTMLWeb Component
:const HelloElement = createCustomElement (HelloComponent, {injector: this.injector});
Наконец, я прошу Angular скомпилировать этот компонент в
main.ts
:platformBrowserDynamic().bootstrapModule(AppModule);
Вот материал, который я прочитал / посмотрел полностью (среди десятков других ссылок - большинство из которых датированы, как и оригинальное введение в Angular Elements):
Веб-компоненты с нуля Томека Сулковски (он никогда не компилирует его отдельно)
Веб-компоненты с CLI (та же проблема)
Веб-компоненты от Academind (опять же, этот парень также использует их в приложениях Angular)
Спасибо за любую помощь.
4 ответа
import { NgModule} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HelloComponent } from './hello.component';
import { AppComponent } from './app.component';
@NgModule({
imports: [BrowserModule],
declarations: [AppComponent, HelloComponent],
entryComponents: [HelloComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
убедитесь, что вы используете
npm install --save @angular/elements
и добавить "@webcomponents/custom-elements" : "^1.0.8"
в package.json. После этого запуска npm install
И наряду с этим вам нужно удалить комментарий ниже строк из polyfills.ts
Это добавляет polyfill, который требуется для пользовательских элементов для работы.
import '@webcomponents/custom-elements/custom-elements.min';
import '@webcomponents/custom-elements/src/native-shim';
<my-tag message="This is rendered dynamically">stack Overflow</my-tag>
Angular не компилирует этот код выше, но угловые элементы решают эту проблему, позволяя взять наш угловой компонент и поместить его в полностью инкапсулированный самозагрузочный HTML-элемент, который вы можете, например, выгрузить в свое угловое приложение следующим образом, и который все еще будет Работа.
В файле AppComponent.ts
import { Component, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements'
import { DomSanitizer } from '@angular/platform-browser';
import { HelloComponent } from './hello.component';
@Component({
selector: 'app-root',
template: '<div [innerHtml]="title"></div>',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = null;
constructor(injector: Injector, domsanitizer: DomSanitizer){
const customElement = createCustomElement(HelloComponent, {injector:
injector});
//this feature is not provided by angular it is provided by javascript
//this allows us to register custom web component
customElements.define('my-tag', customElement);
//instead of 'hello-world' i've used 'my-tag'
setTimeout(() => {
//security mechanism is used to avoid cross site attacks
this.title = domsanitizer.bypassSecurityTrustHtml('<my-tag message="This
is rendered dynamically">stack Overflow</my-tag>');
}, 1000);
}
}
И внутри вашего HelloComponent
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'hello-world',
template: `<div> hello component -- {{ message }}</div>`,
styles: [`
div {
border: 1px solid black;
background-color: red;
padding: 1%;
}
`]
})
export class HelloComponent implements OnInit {
@Input() message : string;
constructor() { }
ngOnInit() {
}
}
Теперь он загружается как собственный веб-компонент. Он по-прежнему может использоваться только в угловых проектах, но уже может использоваться для контента типа dyanamic, подобного этому.
Я надеюсь, что это поможет вам запустить ваш код локально
Текущая версия Angular не предоставляет возможность экспортировать компонент как отдельный локальный файл, который можно использовать в любом неугловом приложении. Однако это может быть достигнуто путем внесения изменений в этапы построения и развертывания. В моем примере я создал два угловых элемента - кнопку и предупреждающее сообщение. Оба компонента скомпилированы и экспортированы как один локальный файл, который я загружаю в простой HTML-файл с JavaScript.
Вот следующие шаги: 1. Добавьте ButtonComponent и AlertComponent в список entryComponent. В ngDoBootstrap и определите их как пользовательские элементы. Вот так выглядит мой app.module:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { AppComponent } from './app.component';
import { ButtonComponent } from './button/button.component';
import { AlertComponent } from './alert/alert.component';
@NgModule({
declarations: [AppComponent, ButtonComponent, AlertComponent],
imports: [BrowserModule],
entryComponents: [ButtonComponent, AlertComponent]
})
export class AppModule {
constructor(private injector: Injector) {
}
ngDoBootstrap() {
const customButton = createCustomElement(ButtonComponent, { injector: this.injector });
customElements.define('my-button', customButton);
const alertElement = createCustomElement(AlertComponent, { injector: this.injector});
customElements.define('my-alert', alertElement);
}
}
Вот мой компонент кнопки:
import {Input, Component, ViewEncapsulation, EventEmitter, Output} из '@ angular / core';
@Component ({селектор: "настраиваемая кнопка", шаблон:
<button (click)="handleClick()">{{label}}</button>
, стили: [button { border: solid 3px; padding: 8px 10px; background: #bada55; font-size: 20px; }
], encapsulation: ViewEncapsulation.Native}) класс экспорта ButtonComponent { @Input() label = 'метка по умолчанию'; @Output() action = new EventEmitter(); приватные клики Ct = 0;handleClick () {this.clicksCt ++; this.action.emit (this.clicksCt); }}
Вот мой компонент оповещения:
import {Component, Input, OnInit} из '@angular/core'; @Component({селектор: 'alert-message', шаблон: 'Alert Message: {{message}}', стили: [ ` div { border: 1px solid #885800; background-color: #ffcd3f; отступы: 10px; цвет: красный; поле: 10px; семейство шрифтов: Arial;
} `]
}) класс экспорта AlertComponent { @Input () message: string; }
Построить конфигурации в angular.json:
"build": {"builder": "@ angular-devkit / build-angular: browser", "options": {"outputPath": "dist", "index": "src / index.html", "main": "src / main.ts", "polyfills": "src / polyfills.ts", "tsConfig": "src / tsconfig.app.json", "assets": ["src / favicon.ico", "src / assets "]," styles ": [" src / styles.css "]," scripts ": [{" input ":" node_modules / document-register-element / build / document-register-element.js "}] }, "configurations": {"production": {"fileReplacements": [{"replace": "src / environment /environment.ts", "with": "src/environment /environment.prod.ts" } ], "оптимизация": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true } } }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "angular6-elements:build" }, "configurations": { "production": { "browserTarget": "angular6-elements:build:production" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "angular6-elements:build" } }
После сборки я объединяю
runtime, polyfills, script
JS файлы в один файл сценария и экспортelements.js
который содержит пользовательские элементы (необязательно: gzip эти файлы), обслуживает его с помощью http-сервера deploy --gzip"scripts": {"ng": "ng", "start": "ng serve", "build": "ng build --prod --output-hashing = none", "package": "npm run package package-base && npm run package-elements", "package-base": "cat dist/{runtime,polyfills,scripts}.js | gzip > deploy/script.js.gz", "package-elements": "cat dist/main.js | gzip > deploy/elements.js.gz", "serve": "http-server deploy --gzip", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }
Наконец включаю
script.js
а такжеelements.js
в index.html (в каталоге deploy), чтобы сообщить браузеру о пользовательских элементах. Теперь my-button и my-alert могут быть включены в index.html . В этом примере кнопка отображается при загрузке, а оповещение добавляется динамически (с номером счетчика) при нажатии кнопки. Вот код:Пользовательская кнопка Тестовая страница
const button = document.querySelector ('my-button'); const msgContainer = document.querySelector ('# message-container'); button.addEventListener ('action', (event) => {console.log (
"action" emitted: ${event.detail}
); button.setAttribute ("label", "Show Next Alert Message!"); msgContainer.innerHTML + =<my-alert message="Here is a message #${event.detail} created dynamically using ng elements!!!"></my-alert>
; });
Вот моя ссылка на мой репозиторий
Надеюсь, это поможет!
Благодарю.
Привет.
Если я правильно понимаю, вы хотите создать веб-компонент (скажем, <my-component></my-component
) и затем с помощью простого тега script, чтобы получить файл.js для инициализации этого компонента и добавления его на любую html-страницу, которую вы хотите.
В моем GitHub-репозитории я создал простой компонент Todo List. Этот компонент следует принципам угловых элементов, а также я установил несколько библиотек управления файлами для веб-пакета, чтобы также упаковать JS в один файл JS.
Вы можете проверить этот репозиторий и посмотреть, поможет ли это вам. Просто клонируйте его, а затем запустите npm install, а затем npm run build:elements Не стесняйтесь обращаться ко мне, если что-нибудь пойдет на юг.
Также проверьте это руководство. Этот парень мне очень помог.
Удачи
Из того, что я читал, упаковка, специфичная для компонентов Angular Elements для удобства использования вне Angular, будет идти с Angular 7.
Что вы можете сделать сейчас, это создать и угловое приложение с кли.
ng new YourAppName
Добавьте библиотеку угловых элементов:
ng add @angular/elements
Это также добавляет все необходимые полифилы, как описано в официальной угловой документации.
Затем вы изменяете AppModule, чтобы он не был модулем начальной загрузки, а просто регистрировал пользовательские элементы. Вы удаляете начальную загрузку из NgModule и рекламируете компоненты как входные компоненты. Затем зарегистрируйте компоненты в качестве пользовательских элементов в ngDoBootstrap
крюк. Я сделал пользовательские элементы AppComponent и HelloComponent по умолчанию. Вот так выглядит мой модуль приложения:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { AppComponent } from './app.component';
import { HelloComponent } from '../hello/hello.component';
@NgModule({
declarations: [
AppComponent,
HelloComponent
],
imports: [
BrowserModule
],
providers: [],
entryComponents: [AppComponent, HelloComponent]
})
export class AppModule {
constructor(private injector: Injector) {
}
ngDoBootstrap() {
customElements.define('app-root', createCustomElement(AppComponent, {injector: this.injector}));
customElements.define('hello-world', createCustomElement(HelloComponent, {injector: this.injector}));
}
}
Затем вы можете использовать элементы в index.html как элементы, например, так:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ElementsTest</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>
<div>
<app-root></app-root>
</div>
<div>
<hello-world></hello-world>
</div>
</body>
</html>
Если вы построите это с ng build --prod
вы получаете свернутые пакеты, которые теперь можно использовать и на других html-страницах, включив сценарии пакетов по мере их включения компилятором в файл index.html.
Я добавил свой образец в GitHub. В истории вы можете увидеть, что я изменил по сравнению с первоначальным приложением.