Search code examples
angularangular-componentsangular-elements

How to share code between a regular Angular component and an Angular Element?


Lets assume that I'll use nx to be able to share libraries between different sites in a mono repo. I have two sites:

  • Site 1: Angular App
  • Site 2: Static Site

Site 1 has a helloWorld Angular Component. On site 2 I want to use the helloWorld component, but as a web component created by an Angular Element. All the Angular Components and Elements should be stored in a shared, external nx library.

Is there a way to share code between the regular Angular Component and the Angular Element? Or, nest the regular component inside the element?


Solution

  • There is a possible solution in a few steps.

    1. Generate a library

    The first step is to generate nx library where you want to store shared custom elements.
    nx g lib custom-elements

    Add build step for this library in angular.json with something like:

            "build": {
              "builder": "@angular-devkit/build-angular:browser",
              "options": {
                "outputPath": "dist/libs/custom-elements",
                "index": "libs/custom-elements/src/lib/index.html",
                "main": "libs/custom-elements/src/lib/main.ts",
                "tsConfig": "libs/custom-elements/tsconfig.lib.json",
                "aot": true,
                "assets": [],
                "styles": [],
                "scripts": []
              },
              "configurations": {
                "production": {
                  "fileReplacements": [],
                  "optimization": true,
                  "outputHashing": "none",
                  "sourceMap": false,
                  "namedChunks": false,
                  "extractLicenses": true,
                  "vendorChunk": false,
                  "buildOptimizer": true,
                  "budgets": [
                    {
                      "type": "initial",
                      "maximumWarning": "2mb",
                      "maximumError": "5mb"
                    },
                    {
                      "type": "anyComponentStyle",
                      "maximumWarning": "6kb",
                      "maximumError": "10kb"
                    }
                  ]
                }
              }
            },
    

    The main part there is "builder": "@angular-devkit/build-angular:browser",, because we will use files built by this library later. Also don't forget to add empty index.html file.

    2. Mark your angular components as custom elements

    Firstly, add angular elements npm install @angular/elements.
    Then mark the components you want to share using createCustomElement:

    
    @NgModule({
       imports: [BrowserModule],
       entryComponents: [SomeComponent],
    })
    export class SharedComponentsModule {
       constructor(readonly injector: Injector) {
           const ngElement = createCustomElement(SomeComponent, {
               injector,
           });
    
           customElements.define('some-component', ngElement);
       }
    
       ngDoBootstrap() {}
    }
    

    3. Build the library and add necessary scripts to your static page

    Run nx build custom-elements. You will get all the files in dist/libs/custom-elements. You are now able to add them to any page and use custom elements!

    Working example

    I created a working example here https://github.com/nickbullock/share-custom-elements-between-angular-and-static-app

    How to run angular app: npm start
    How to run static app: npm run app2:serve

    Additional read

    https://indepth.dev/posts/1116/angular-web-components-a-complete-guide

    https://medium.com/angular-in-depth/how-to-compile-your-angular-components-library-into-web-components-47ff0ac73bd7