Angular Custom Elements
Setup
- @angular/cli: 9.1.6
- Angular 9.1.7
- Typescript: 3.8.3
1. Preparando o ambiente:
$ ng new <nome_do_projeto>
2. Entre no diretório:
$ cd <nome_do_projeto>
3. Adicionaremos a feature elements do pacote @angular
$ ng add @angular/elements
em caso de sucesso, a mensagem de retorno deverá ser:
Installing packages for tooling via npm.
Installed packages for tooling via npm.
Added "document-register-element" as a dependency.
Added "document-register-element" to polyfills.
UPDATE package.json (1329 bytes)
UPDATE src/polyfills.ts (2871 bytes)
✔ Packages installed successfully.
4. Criaremos um componente que será nosso elemento customizado
Nome do componente sugerido: boilerplate
$ ng generate component boilerplate
boilerplate.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-boilerplate',
templateUrl: './boilerplate.component.html',
styleUrls: ['./boilerplate.component.scss']
})
export class BoilerplateComponent {
@Input() public title = 'default';
public value: number = 0;
public increment(): void {
this.value++;
}
}
boilerplate.component.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="custom-container">
<div class="first-box">
<span>{{ title }}</span>
</div>
<div class="second-box">
<div>
{{ value }}
</div>
<div>
<button (click)="increment()">Incrementar</button>
</div>
</div>
</div>
5. Hora de definir nosso componente como um custom element
app.module.ts
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
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BoilerplateComponent } from './boilerplate/boilerplate.component';
@NgModule({
declarations: [
AppComponent,
BoilerplateComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
entryComponents: [
BoilerplateComponent
],
})
export class AppModule {
constructor(private injector: Injector) {
const custom = createCustomElement(BoilerplateComponent, { injector });
customElements.define('app-hello-world', custom);
}
ngDoBootstrap() {}
}
6. Realizamos o build
$ npm run build
7. Geramos os arquivos de build de forma modular, vamos concatenar os essesnciais para consumi-los!
Nessa etapa, temos algumas opções para realizar a mesma tarefa, seguem algumas:
Independente da opção escolhida, vamos adicionar dentro da tag scripts do arquivo package.json
1
2
3
4
"scripts": {
...
"build": "ng build --prod --output-hashing=none"
}
1.cat - linux/mac
1
2
3
4
5
"scripts": {
...
"dist:concat": "cat ./dist/angular-custom-elements/{runtime,polyfills,main}-es5.js > build.js",
"build:cat": "npm run build && npm run dist:concat"
}
2.jscat - windows
$ npm i jscat -g
$ npm i jscat --save-dev
1
2
3
4
"scripts": {
...
"build:jscat": "npm run build && jscat ./dist/angular-custom-elements/runtime.js ./dist/angular-custom-elements/polyfills.js ./dist/angular-custom-elements/scripts.js ./dist/angular-custom-elements/main.js >../elements.js"
}
*obs: outros exemplos desse processo, podem ser realizados com gulp ou concat.
8. Sucesso! Temos nosso arquivo de distribuição unificado!
Se tudo ocorreu bem, teremos nosso arquivo dentro da pasta dist, este você utilizará dentro das futuras aplicações
Extra: testando custom element em cenário simples
- Fora do seu projeto angular, crie um diretório contendo:
- index.html
- build.js [ nosso arquivo recém gerado ]
- Seu arquivo index.html deve estar semelhante a este, se precisar substitua os nomes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<base href="/">
<title>Document</title>
</head>
<body>
<boilerplate-selector title="title"></boilerplate-selector>
<script src="<caminho_absoluto>/build.js"></script>
</body>
</html>
Pronto! Agora abra o arquivo index.html no browser!
Comentáriuos pertinentes:
Zone.js
O zone.js é fundamental para o funcionamento do custom-element, nesse caso de teste, ele aproveita o build do próprio angular. Em outros cenários, onde queremos usar nosso seletor em um projeto que o zone.js já é utilizado, temos de tomar cuidado para que não haja conflito.
Projeto
https://github.com/heijimrt/angular-custom-elements
Comentários