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

Viewed 913

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?

2 Answers

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

Is there a way to share code between the regular Angular Component and the Angular Element?

Yes, This is why we use libraries. Libraries are not just a way to share code in Nx. They are also useful for factoring out code into small units with a well-defined public API. The NX recommends having a small number of library types.

According to angular.io, Angular elements are Angular components packaged as custom elements (also called Web Components), so what you need is Nx Plugin for Web which contains generators for managing Web Component applications and libraries within an Nx workspace. You may need the helpful instructions inside Create Libs in Angular using NX to meet your purpose.

Is there a way to nest the regular component inside the element?

Yes, As Angular allows us to put reusable logic into the separate units.

Related