angularangular-cliangular-elementsangular18angularbuild

Angular elements: ng build in Angular 18 with --optimization=true emits broken artifacts


when I try to build the module with the flag --optimization equal to false, then everything works just fine. The compilation finishes without any issues and I can use my web-component as well. Once I do all the same, but with the flag --optimization equal to true, then the build finishes without errors, but the application which uses the output files crashes.

// main.ts file
import { createApplication } from '@angular/platform-browser';
import { createCustomElement } from '@angular/elements';
import { LinkComponent } from './app/temp/components/link/link.component';

createApplication()
 .then((app) => {
   const Link = createCustomElement(LinkComponent, {
    injector: app.injector,
   });
   customElements.define('app-link', Link);
})
.catch((err) => console.error(err));

// link.componen.ts file
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { NgIf } from '@angular/common';

enum LinkType {
  ACTIVE = 'active',
  INACTIVE = 'inactive',
}

@Component({
  selector: 'app-link',
  template: `
    <a [class.active]="type === LinkType.ACTIVE" [href]="href">{{ label }}</a>

    <strong>{{ value }}</strong>

    <strong *ngIf="value > 0.5"> Greater than 0.5! </strong>

    <button (click)="handleButtonClick()">Generate</button>
  `,
  styles: `
    :host {
      display: inline-block;
    }
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: true,
  imports: [NgIf],
})
export class LinkComponent {
  @Input() public href = '';
  @Input() public label = '';
  @Input() public type: LinkType = LinkType.INACTIVE;

  LinkType = LinkType;
  value = 0;

  handleButtonClick() {
    this.value = Math.random();
  }
}

// Package.json file contents
"dependencies": {
    "@angular/animations": "^18.2.13",
    "@angular/cdk": "^18.2.14",
    "@angular/common": "^18.2.13",
    "@angular/compiler": "^18.2.13",
    "@angular/core": "^18.2.13",
    "@angular/elements": "^18.2.13",
    "@angular/forms": "^18.2.13",
    "@angular/material": "^18.2.14",
    "@angular/material-date-fns-adapter": "^18.2.14",
    "@angular/platform-browser": "^18.2.13",
    "@angular/platform-browser-dynamic": "^18.2.13",
    "@angular/router": "^18.2.13",
    "date-fns": "^3.6.0",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.14.2"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^18.2.15",
    "@angular/cli": "^18.2.12",
    "@angular/compiler-cli": "^18.2.13",
    "@types/jasmine": "~5.1.0",
    "jasmine-core": "~5.5.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "typescript": "~5.4.0"
  }

// tsconfig.json file contents
{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "baseUrl": "./",
    "paths": {
      "@pm/shared/*": ["src/app/shared/*"]
    },
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "skipLibCheck": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "moduleResolution": "bundler",
    "importHelpers": true,
    "target": "ES2022",
    "module": "ES2022"
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

Solution

  • You are defining the script tag without the type attribute set as module, that is causing the error.

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
        <title>Document</title>
    
      </head>
      <body>
        <app-link label="Test"></app-link>
        <script src="./dist/demo/browser/polyfills.js" type="module"></script> <!-- notice! -->
        <script src="./dist/demo/browser/main.js" type="module"></script> <!-- notice! -->
      </body>
    </html>
    

    HTML from dist:

    <!DOCTYPE html>
    <html lang="en" data-critters-container>
      <head>
        <title>My app</title>
        <meta charset="UTF-8">
        <base href="/">
      <link rel="stylesheet" href="styles.css"></head>
    
      <body>
        <app-link label="Test"></app-link>
      <script src="polyfills.js" type="module"></script>
      <script src="main.js" type="module"></script></body>
    </html>