angularweb-componentangular-elementsangular18

Web Components and Angular 18


What are the Changes form Angular 17 to 18 for Web Components (Standalone Elements)? I've tried some Angular 17 related Guides / couldn't find any (usefull) information about the changes for 18 so far.

My Setup

main.ts:

import {createApplication} from '@angular/platform-browser';
import {createCustomElement} from "@angular/elements";
import {GridWidgetComponent} from "./app/grid-widget/grid-widget.component";

(async () => {
    const app = await createApplication({
        providers: []
    });

    const gridElement = createCustomElement(GridWidgetComponent, {
        injector: app.injector,
    });

    customElements.define("grid-widget", gridElement);
})();

PHP Storm informs me in my main.ts that: "Expression statement is not assignment or call"

index-test.html:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

<grid-widget></grid-widget>
<script src="component-lib.js" type="module"></script>

</body>
</html>

script linked as type=module because there was a message for Syntax Error: Uncaught SyntaxError: Unexpected token 'export' (at component-lib.js:3:144) but changed nothing

src/app/grid-widget/grid-widget.component.ts:

import { Component } from '@angular/core';
import {CommonModule} from "@angular/common";

@Component({
  selector: 'grid-widget',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './grid-widget.component.html',
  styleUrl: './grid-widget.component.scss'
})
export class GridWidgetComponent {
  constructor() {
  }
}

angular.json:

...
"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser-esbuild",
          "options": {
            "outputPath": "dist/webcomponent-example",
            "index": "src/index.html",
            "main": "src/main.ts",
...

package.json:

...
 "build": "ng build --output-hashing=none --configuration production",
 "package" : "npm run build && cat dist/webcomponent-example/{polyfills,main}.js > dist/component-lib.js",
...
"dependencies":{
...
"@angular/elements": "^18.2.1",
...
"@angular/platform-browser": "^18.1.0",
...
}

The result is an error in the console that "Nt" already has been declared: "Uncaught SyntaxError: Identifier 'Nt' has already been declared" when using type=module without type=module I've got a Syntax Error about the Export: "Uncaught SyntaxError: Unexpected token 'export'"

One of the tutorials I've used was https://www.youtube.com/watch?v=sDf4PFC_Vok&t=508s In the docs I've only found https://angular.dev/guide/elements but it does not show how to build it correctly.

Target is to have a Web Component (obviously for a grid and later others too) which can be embedded into a PHP site. Because there could be multiple instances on the same page I tough WebComponents / Elements would be a working solution.

Did anyone got a good reference on how to create Web Components with Angular 18?


Solution

  • Ok I've found the issue - The problem relied on the bundler Script which should combine polyfills.js and main.js into one "bundle.js" file:

    ...
    "package": "npm run build && cat dist/widgets/browser/{polyfills,main}.js > dist/widgets/browser/bundle.js",
    ...
    

    When using polyfills.js and main.js there is no issue and everything works like a charm.