Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have angular library that emits Angular elements in single js file?

I'm starting to get into the angular 6 bits, and am very interested in Angular Elements as well as the new library projects. I have an upcoming project that will probably need both these new features.

I have the need to create custom UI components that are reusable across web frameworks, but I'd also like to have first class support for using them in angular projects. I've followed this tutorial and have an angular6 app that registers custom elements, and concats the webpack bundles in a single file. I can then use that single js file in a plain html page and everything works very well.

The sticking point is it would be great to create these custom elements in a library project. That way I can distribute my library on our internal npm registry, as well as build the js that contains all the custom elements and deploy it on a CDN.

Is it possible to build Angular Elements in the new library projects?

like image 644
cobolstinks Avatar asked Jul 06 '18 20:07

cobolstinks


Video Answer


1 Answers

Introduction

What I will describe here is a way to have a mono-repo containing a main Angular app (host) and one or more Angular Elements based apps (childs). You will be able to use the elements in your main app by bundling all them together or you can pack your element with npm and import it as a npm dependency. This is heavily based on what is described by Manfred Steyer in his Angular Elements blog series so I advice you to read that to get some context and fill some missing pieces.

Be aware though, that currently the approach I describe here will not avoid duplicated dependencies across your multiple apps.

Solution

In your existing Angular project you can create a child application with ng generate application <name>. See documentation for more details.

Turn your newly created project to an Angular Element.

To help you build your projects take a look at the Angular CLI extension ngx-build-plus here. For my case I didn't apply most of the recipe described in the ngx-build-plus docs as it is about sharing dependencies across projects which I will not detail here. All I needed was what follows.

The steps to build this architecture are roughly:

  • ng add ngx-build-plus
  • ng add ngx-build-plus --project <name>
  • create npm scripts:
    • for elements projects: "build:client-a": "ng build --prod --project client-a --single-bundle true --output-hashing none --vendor-chunk false"
    • for host app, regular build commands like ng build, ng serve
  • add path to the generated elements JS file to the host app build configuration - you add it in scripts property in angular.json
  • add path to the custom elements polyfill JS file to the element apps build configuration - you add it in scripts property in angular.json. Each app has its own configuration and scripts entry.

After you build your elements project, its single file bundle will typically go to ./dist/<project-name>/. You can create an npm package from that content and use it as a library.

Notes

  • Two ways to bundle the child apps with the host app. In the host app scripts configuration, you either add the path to the child apps in the dist/ folder or you add the path to the child apps in node-modules/ folder (when child apps are imported as npm packages).

  • Creating an Angular library instead of an Angular application for this purpose will not work because Angular libraries generated by the CLI cannot be used outside an Angular project - this was not very clear in the documentation.

  • Make sure that the component doesn't have dependencies to the parent app and you should be fine. I handled dependencies by converting them to component inputs or by doing content projection.

  • When you have a component A which includes a component B. You want to turn component A into an angular element but component B is used in several parts of your application. If you don't want to maintain two copies, one in the application and other in your component A library, it might be a good case to take advantage of content projection (aka Web Component slots).

  • Be aware that I haven't done this in production and its not what you would call a stable architecture.

like image 104
Rui Marques Avatar answered Oct 22 '22 21:10

Rui Marques