Question Comment compiler un élément angulaire dans un composant Web avec Webpack ou une CLI angulaire?


J'ai construit un composant Web simple via Angular en utilisant les outils de Pascal Precht Didacticiel, que vous pouvez voir travailler ICI. Il compile automatiquement dans le Stackblitz dans le lien, mais pas localement.

Mon objectif final est de disposer le code du composant Web résultant dans un fichier distinct. Finalement, je vais le télécharger quelque part et le retirer via un seul <script> tag, tout comme les composants Web normaux raw-html / javascript. Je pense que la question parle d'elle-même, mais vous pouvez lire les détails ci-dessous si vous souhaitez:


Détails:

Pour résumer mon code dans le lien ci-dessus, j'ai un composant très basique:

import { Component } from '@angular/core';

@Component({
  selector: 'hello-world',
  template: `<h1>Hello world</h1>`
})

export class HelloComponent  {}

et j'ai un module:

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);
  }
}

Voici une explication du module ci-dessus:

  1. Ajouter mon composant à la entryComponents Il n'est donc pas pris en charge par l'arborescence angulaire (car il n'est pas accessible sur l'application: entryComponents: [HelloComponent] 
  2. Exécuter mon composant à travers le createCustomElement fonction pour que je puisse l'utiliser comme un html régulier Web Component:

    const HelloElement = createCustomElement (HelloComponent, {   injecteur: this.injector })

  3. Enfin, je demande à Angular de compiler ce composant dans main.ts:

    platformBrowserDynamic().bootstrapModule(AppModule);


Voici ce que j'ai lu / regardé à fond (parmi des dizaines d'autres liens - dont la plupart sont datés, comme l'intro originale des éléments angulaires):

Composants Web de Scratch par Tomek Sułkowski (Il ne le compile jamais séparément)
Composants Web avec CLI (Même problème)
Composants Web par Academind (Encore une fois, ce gars les utilise également dans les applications Angular)

Merci pour toute aide.


11
2018-05-31 15:06


origine


Réponses:


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 { }

assurez-vous d'utiliser

npm install --save @angular/elements et ajouter "@webcomponents/custom-elements" : "^1.0.8" dans package.json. Après cette course npm install Et avec cela, vous devez annuler le commentaire ci-dessous des lignes de polyfills.ts

Cela ajoute un polyfill requis pour que les éléments personnalisés fonctionnent.

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 ne compile pas ce code ci-dessus, mais les éléments angulaires corrigent ce problème en permettant de prendre notre composant angulaire et de le placer dans un élément HTML auto-amorçable totalement encapsulé que vous pouvez transférer dans votre application angulaire de cette manière pour travail.

Dans le fichier 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);
   }
 }

Et à l'intérieur de votre 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() {
}
}

Maintenant, il est chargé en tant que composant Web natif. Reste uniquement utilisable dans les projets angulaires, mais déjà utilisable pour ce type de contenu.

J'espère que cela vous aidera à exécuter votre code localement


7
2018-06-11 07:26



D'après ce que j'ai lu, l'emballage spécifique aux composants Angular Elements pour une utilisation facile en dehors d'Angular sera fourni avec Angular 7.

Ce que vous pouvez faire maintenant est de créer une application angulaire avec le cli.

ng new YourAppName

Ajoutez la bibliothèque d'éléments angulaires avec:

ng add @angular/elements

Cela ajoute également tous les polyfills requis comme décrit dans le document officiel Documentation angulaire.

Ensuite, vous modifiez AppModule pour ne plus être un module bootstrap, mais simplement pour enregistrer les éléments personnalisés. Vous supprimez le bootstrap de NgModule et publiez les composants en tant que composants d'entrée. Puis enregistrez les composants en tant qu’éléments personnalisés dans le ngDoBootstrapcrochet. J'ai créé à la fois les éléments personnalisés AppComponent et HelloComponent par défaut. Voici à quoi ressemble mon module d'application:

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}));
  }
 }

Ensuite, vous pouvez utiliser les éléments du fichier index.html comme des éléments comme ceci:

<!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>

Si vous construisez cela avec ng build --prod Vous obtenez des packages minimisés que vous pouvez utiliser maintenant également dans d'autres pages HTML en incluant les scripts de package lorsqu'ils sont inclus par le compilateur dans le fichier index.html.

J'ai ajouté mon échantillon à GitHub. Dans l'histoire, vous pouvez voir ce que j'ai changé depuis l'application cli initiale.


1
2018-06-11 22:34



La version angulaire actuelle ne fournit pas d’option permettant d’exporter un composant en tant que fichier local unique pouvant être utilisé dans toute application non angulaire. Cependant, cela peut être réalisé en modifiant les étapes de construction et de déploiement. Dans mon exemple, j'ai créé deux éléments angulaires un bouton et un message d'alerte. Les deux composants sont compilés et exportés en tant que fichier local unique que je charge dans un fichier HTML simple avec javascript.

Voici les étapes suivantes: 1. Ajoutez ButtonComponent et AlertComponent dans la liste entryComponent. Dans ngDoBootstrap et définissez-les comme éléments personnalisés. Voici à quoi ressemble mon 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);
  }
}
  1. Voici mon composant bouton:

    importer {   Contribution,   Composant,   ViewEncapsulation,   EventEmitter,   Sortie } de '@ angular / core';

    @Composant({   sélecteur: 'bouton personnalisé',   modèle: <button (click)="handleClick()">{{label}}</button>,   modes: [      button { border: solid 3px; padding: 8px 10px; background: #bada55; font-size: 20px; }   ],   encapsulation: ViewEncapsulation.Native }) classe d'exportation ButtonComponent {   @Input () label = 'étiquette par défaut';   @Output () action = new EventEmitter ();   clicksCt privé = 0;

    handleClick () {     this.clicksCt ++;     this.action.emit (this.clicksCt);   } }

  2. Voici mon composant d'alerte:

    import {Composant, Entrée, OnInit} de '@ angular / core'; @Composant({   sélecteur: 'message d'alerte',   template: 'Message d'alerte: {{message}}',   modes: [     `     div {       bordure: 1px solide # 885800;       couleur d'arrière-plan: # ffcd3f;       rembourrage: 10px;       La couleur rouge;       marge: 10px;       famille de polices: Arial;

    }
    `]
    

    }) classe d'exportation AlertComponent {   @Input () message: chaîne; }

  3. Construire des configurations dans angular.json:

    "construire": {   "constructeur": "@ 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": [       {         "contribution":           "node_modules / document-register-element / build / document-register-element.js"       }     ]   },   "configurations": {     "production": {       "FileReplacements": [         {           "remplacer": "src / environnements / environment.ts",           "avec": "src / environnements / environment.prod.ts"         }       ],       "optimisation": vrai,       "outputHashing": "all",       "sourceMap": false,       "extractCss": true,       "namedChunks": false,       "aot": vrai,       "extractLicenses": true,       "vendorChunk": false,       "buildOptimizer": true     }   } }, "servir": {   "constructeur": "@ angular-devkit / build-angular: dev-server",   "options": {     "browserTarget": "angular6-elements: build"   },   "configurations": {     "production": {       "browserTarget": "angular6-elements: build: production"     }   } }, "extrait-i18n": {   "constructeur": "@ angular-devkit / build-angular: extract-i18n",   "options": {     "browserTarget": "angular6-elements: build"   } }

  4. Après la construction, je concatène runtime, polyfills, script js fichiers en fichier script unique et export elements.js qui contient les éléments personnalisés (optionnel: gzip ces fichiers) le sert en utilisant http-server deploy --gzip

    "scripts": {   "ng": "ng",   "start": "ng serve",   "build": "ng build --prod --output-hashing = none",   "package": "npm run 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",   "peluches": "peluches",   "e2e": "ng e2e" }

  5. Enfin j'inclus script.js et elements.js dans index.html (dans le répertoire deploy) pour informer le navigateur des éléments personnalisés. Maintenant, mon bouton et mon alerte peuvent être inclus dans index.html. Dans cet exemple, le bouton est affiché en charge et le message d'alerte est ajouté dynamiquement (avec le numéro du compteur) en cliquant sur le bouton. Voici le code:

         Page de test du bouton personnalisé      

        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", "Afficher le message d'alerte suivant!");       msgContainer.innerHTML + = <my-alert message="Here is a message #${event.detail} created dynamically using ng elements!!!"></my-alert>;     })

Voici mon lien pour mon repo git

J'espère que cela aidera!

Merci.


1
2018-06-12 16:22



Bonjour. 

Si je comprends bien, vous voulez générer un composant Web (Disons <my-component></my-component) et ensuite avec une simple balise de script pour obtenir le fichier .js pour initialiser ce composant et l'ajouter à n'importe quelle page HTML que vous souhaitez.

Dans mon Dépôt GitHub J'ai créé un composant simple Todo List. Ce composant suit les principes des éléments angulaires et, aussi, j'ai installé des bibliothèques de gestion de fichiers pour webpack afin d’emballer le JS dans un seul fichier JS.

Vous pouvez vérifier ce dépôt et voir si cela vous aide. Il suffit de le cloner puis d'exécuter npm installer suivi par npm run build: éléments N'hésitez pas à me contacter si quelque chose se passe au sud.

Vérifiez aussi ceci guider. Ce gars m'a beaucoup aidé.

Bonne chance


1
2018-06-13 14:20