How to Compile Angular Element Into Web Component w/ Webpack or Angular CLI?

后端 未结 4 1486
傲寒
傲寒 2021-02-13 04:06

I built a simple Web Component via Angular using Pascal Precht\'s tutorial, which you can see working HERE. It auto-magically compiles in the on Stackblitz in the link, but not

4条回答
  •  一向
    一向 (楼主)
    2021-02-13 04:30

    Current Angular version doesn’t provide an option to export component as single local file which can used in any non angular application. However it can be achieved by making changes in building and deployment steps. In my example I have created two angular elements a button and alert message. Both components are compiled and exported as single local file which I’m loading in a plain html file with javascript.

    Here are the steps follows: 1. Add ButtonComponent and AlertComponent in entryComponent list. In ngDoBootstrap and define them as custom elements. 
This is how my app.module looks:

    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. Here is my button component:
    import {
      Input,
      Component,
      ViewEncapsulation,
      EventEmitter,
      Output
    } from '@angular/core';
    
    @Component({
      selector: 'custom-button',
      template: ``,
      styles: [
        `
        button {
          border: solid 3px;
          padding: 8px 10px;
          background: #bada55;
          font-size: 20px;
        }
      `
      ],
      encapsulation: ViewEncapsulation.Native
    })
    export class ButtonComponent {
      @Input() label = 'default label';
      @Output() action = new EventEmitter();
      private clicksCt = 0;
    
      handleClick() {
        this.clicksCt++;
        this.action.emit(this.clicksCt);
      }
    }
    
    1. Here is my alert component:
    import { Component, Input, OnInit } from '@angular/core';
    @Component({
      selector: 'alert-message',
      template: '
    Alert Message: {{message}}
    ', styles: [ ` div { border: 1px solid #885800; background-color: #ffcd3f; padding: 10px; color: red; margin:10px; font-family: Arial; } `] }) export class AlertComponent { @Input () message: string; }
    1. Build configurations in 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/environments/environment.ts",
              "with": "src/environments/environment.prod.ts"
            }
          ],
          "optimization": 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"
      }
    }
    
    1. After build, I concatenate runtime, polyfills, script js files into single script file and export elements.js which contains the custom elements 
(optional: gzip those files)
serve it using 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",
      "lint": "ng lint",
      "e2e": "ng e2e"
    }
    
    1. Finally I include script.js and elements.js in index.html (in deploy directory) to tell the browser about the custom elements. 
Now my-button and my-alert can be included in index.html
. In this example, the button is shown on-load and Alert message is added dynamically (with counter number) on click of the button.
Here is the code:
        
        
    
        
          
          Custom Button Test Page
          
          
        
    
        
          
    
          

    Here is my link for my git repo

    Hope this will help!

    Thanks.

提交回复
热议问题