如何使用Webpack或Angular CLI将角元素编译为Web组件?

VSO*_*VSO 14 webpack angular-cli angular angular-elements

我使用Pascal Precht的教程通过Angular构建了一个简单的Web组件,您可以在这里看到它.它自动神奇地编译链接中的Stackblitz,但不是本地.

我的最终目标是将生成的Web组件的代码放在本地的单独文件中.最终,我会将其上传到某处并通过单个<script>标签将其拉入,就像普通的raw-html/javascript Web Components一样.我认为问题不言自明,但如果您愿意,可以阅读以下详细信息:


细节:

要在上面的链接中总结我的代码,我有一个非常基本的组件:

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

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

export class HelloComponent  {}
Run Code Online (Sandbox Code Playgroud)

我有一个模块:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

以下是上述模块的说明:

  1. 将我的组件添加到entryComponents数组中,因此它不会被角度树振荡器取出(因为它在应用程序启动时无法访问: entryComponents: [HelloComponent]
  2. 通过该createCustomElement函数运行我的组件,以便我可以将其用作常规html Web Component:

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

  3. 最后,我请Angular编译这个组件main.ts:

    platformBrowserDynamic().bootstrapModule(AppModule);


这是我完全阅读/观看的内容(在其他几十个链接中 - 大多数都是过时的,就像原始的Angular Elements简介一样):

来自TomekSułkowski的Scratch的Web组件(他从未单独编译)
带有CLI的Web组件(相同问题)
Academind的Web组件(再一次,这个人也在Angular应用程序中使用它们)

感谢您的任何帮助.

Pra*_*sne 8

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 { }
Run Code Online (Sandbox Code Playgroud)

确保你使用

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);
   }
 }
Run Code Online (Sandbox Code Playgroud)

在你的内心 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() {
}
}
Run Code Online (Sandbox Code Playgroud)

现在,它作为本机Web组件加载.仅在角度项目中可用,但已经可用于像这样的动态内容.

我希望这可以帮助您在本地运行代码


小智 5

当前的 Angular 版本不提供将组件导出为可用于任何非 Angular 应用程序的单个本地文件的选项。但是,它可以通过更改构建和部署步骤来实现。在我的示例中,我创建了两个角度元素,一个按钮和一个警报消息。这两个组件都被编译并导出为单个本地文件,我正在使用 javascript 将其加载到一个纯 html 文件中。

步骤如下: 1. 在 entryComponent 列表中添加 ButtonComponent 和 AlertComponent。在 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);
  }
}

Run Code Online (Sandbox Code Playgroud)
  1. 这是我的按钮组件:
import {
  Input,
  Component,
  ViewEncapsulation,
  EventEmitter,
  Output
} from '@angular/core';

@Component({
  selector: 'custom-button',
  template: `<button (click)="handleClick()">{{label}}</button>`,
  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<number>();
  private clicksCt = 0;

  handleClick() {
    this.clicksCt++;
    this.action.emit(this.clicksCt);
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 这是我的警报组件:
import { Component, Input, OnInit } from '@angular/core';
@Component({
  selector: 'alert-message',
  template: '<div>Alert Message: {{message}}</div>',
  styles: [
    `
    div {
      border: 1px solid #885800;
      background-color: #ffcd3f;
      padding: 10px;
      color: red;
      margin:10px;
      font-family: Arial;

    }
    `]
})
export class AlertComponent {
  @Input () message: string;
}
Run Code Online (Sandbox Code Playgroud)
  1. 在 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"
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 构建后,我将runtime, polyfills, scriptjs 文件连接到单个脚本文件中并导出elements.js其中包含自定义元素?(可选:gzip 这些文件)?使用 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"
}
Run Code Online (Sandbox Code Playgroud)
  1. 最后,我在 index.html(部署目录中)中包含script.jselements.js以告诉浏览器有关自定义元素的信息。?现在 my-button 和 my-alert 可以包含在 index.html 中?。在这个例子中,按钮在加载时显示,并且在单击按钮时动态添加警报消息(带有计数器编号)。这是代码:
"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"
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 git repo 的链接

希望这会有所帮助!

谢谢。