Skip to content

Micro-Frontend: Allow to have separate build/ releasable elements for lazy loaded modules #20056

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mohyeid opened this issue Feb 13, 2021 · 6 comments

Comments

@mohyeid
Copy link

mohyeid commented Feb 13, 2021

🚀 feature request

Relevant Package

@angular/cli

Description

With Micro-frontend being a hot topic those days, I have seen people taking the wrong approach with their angular projects. Thankfully, we have angular elements that allow us to create pure web-components, but unfortunately this have been misused to allow the micro frontend concept in an angular application. To allow smaller releasable packages, engineers started to create angular elements release them to a CDN site, and re-use them. This created a lot of fraction and challenges to integrate the different pieces. Not only that, but it's also awkward, as you are creating vanilla javascript code from angular code to re-use it back again from an angular code. Other solutions was iframing, which also does not scale. Or releasing smaller libs to npm and re-using them in the code, which is not desired in the case of end to end integration and mon-repo large applications.

Describe the solution you'd like

If you have a solution in mind, please describe it.

Today, we are blessed by having the lazy loading approach which help us to generate separate chunks of the code and lazy load them as the user is visiting the relevant code. While this is great, there is no way to build those chunks separately and/or publish them to a standalone CDN/Server to be used later. I think to help teams avoid mistakes like listed above, it would be awesome if we can have angular CLI able to build these chunks separately, generate an artifact for it, which can be released individually. When this is accomplished, we can then have something like this:

const routes: Routes = [
  {
    path: 'items',
    loadChildren: () => import(env.prod? 'https://CDN-XYA/chunk1.js' : './items/items.module' ).then(m => m.ItemsModule)
  }
]; 

Describe alternatives you've considered

Yes, above but it's not ideal. I think angular team need to get into the micro frontend business.

@mohyeid mohyeid changed the title Allow me to have separate build/ releasable elements for lazy loaded modules Micro-Frontend: Allow me to have separate build/ releasable elements for lazy loaded modules Feb 13, 2021
@mohyeid mohyeid changed the title Micro-Frontend: Allow me to have separate build/ releasable elements for lazy loaded modules Micro-Frontend: Allow to have separate build/ releasable elements for lazy loaded modules Feb 13, 2021
@flash-me
Copy link

We can for a long time already, see here

cheers
flash ⚡

@petebacondarwin petebacondarwin transferred this issue from angular/angular Feb 13, 2021
@mohyeid
Copy link
Author

mohyeid commented Feb 16, 2021

@flash-me that's interesting approach, but does it seem what I am trying to avoid? If you can have a pure lazy loaded angular code chunk, why do you need to create a web-component? Append the script manually and enable custom component schema which allow for bad elements to be added to the code without error handling? I wish we can accomplish something with the basic angular lazy loading!

@flash-me
Copy link

flash-me commented Feb 16, 2021

@flash-me that's interesting approach, but does it seem what I am trying to avoid? If you can have a pure lazy loaded angular code chunk, why do you need to create a web-component? Append the script manually and enable custom component schema which allow for bad elements to be added to the code without error handling? I wish we can accomplish something with the basic angular lazy loading!

Because this way you can use the resulting web-components everywhere. E.g. embed them in other frameworks etc. You also have the option to use them as regular NgModules and import them as usual.
I'm not sure to what you are referring to by saying bad elements, but you won't find any CUSTOM_ELEMENTS_SCHEMA in that repository.
Once you start to decouple the compilation of your apps into multiple parts, things get really interesting, believe me.
E.g. Versioning of the different parts, their dependencies, etc.. just to name some.

If you want a basic approach, go with the lazy loading. It's not like in other frameworks where you can just fetch some files and append your application. In angular you also have the powerful DI and it's dependency tree, which needs to be considered. Dynamically loading some modules on runtime is always critical and error prone.
Just curious: How would you load your independently compiled lazy loaded modules, which are not known at compile time to the app itself, if appending the script is that bad?
Anyway, that repo is a POC. If the approach doesn't fit, don't use it. Also no one stops you from hiding / wrapping that complexity in some easy to use functions.

But this doesn't mean it's impossible. To dynamically "import" NgModules, you can have a look on the answer here (also note the issues that guy had there)
You can even go a step further and completely lazy load angular libraries including their childroutes. Example code would here. Even though that repo is not really up2date, the approach is still the same. These days we could even solve that in a cleaner way by using ESM, but that's another topic. The interesting part for you would be this particular function

cheers
flash ⚡

@alan-agius4
Copy link
Collaborator

alan-agius4 commented Feb 18, 2021

Thank you all for chiming in.

Lazy-loading modules and microfrontends are very different and each solves different problems. Lazy-loaded modules are dependent on other parts of the application, are not self contained and cannot be built without building the entire application. It also means that changes in a lazy-loaded module might cause either one or more of the common/shared modules to be invalidated. A microfrontend on the other hand is dependency free and can be built and released on its own, in other words it's isolated.

There are multiple ways to achieve microfrontends, it mostly depends on your use-case.

  • Angular Elements
  • Single SPA https://single-spa.js.org/ which is a popular microfrontend router for React, Angular and Ember.
  • Module Federation
  • Iframes

If you are using lazy-loading modules and want to release only what changed you can always check the diff and push to production the changed files. But again, lazy-loading and microfrontend are two different things and each solves different problems.

Thankfully, we have angular elements that allow us to create pure web-components, but unfortunately this have been misused to allow the micro frontend concept in an angular application. To allow smaller releasable packages, engineers started to create angular elements release them to a CDN site, and re-use them.

This is interesting, I don't know that approach used here, but, I wonder if Angular Elements have been created at a low level instead of a higher level. For example, let's say I have an item details page, in this case I would only create the top level component of the as an Elements and of it's child components are still standard Angular components.

Items microfrontend application

- item-details-page     // Angular Element Component
-- item-item-component  // Angular Component
--- add-to-chart-button // Angular Component

- item-list-page           // Angular Element Component
-- item-grid-item-component // Angular Component
--- item-item-component     // Angular Component
---- view-more-button       // Angular Component

A lazy-loaded module in an application is not self contained and hence it breaks the microfrontend concept. Therefore,
I am closing this issue as at this point I don't see anything which is actionable by the tooling team.

Module federation is being tracked here #17556

Feel free to reply.

@flash-me
Copy link

Unpopular opinion:
If I have to recompile my shell in order to modify the micro Frontends I want to load, as it is required in kinda EVERY EXAMPLE out there, (e. g. here), then it is not micro Frontends we're talking about. Absolutely not. This is just lazy loading with some overhead.
Kill me to it

This doesn't mean it's impossible to accomplish it with webpack. Even more, back in 2019, my first approaches were done with webpack. But this was not the development experience I want to have and I couldn't expect this from casual developer to handle it the right way.
Which lead me to ng-packagr, which comes with everything out of the box. Even ESM works

Anyway, everyone can do everything and call it whatever one wants to call it. I really don't give a single f@ck anymore.
Live and let live, right?

Have a nice day folks and don't let anyone f@ck you up. There are better things in life

I'm going to archive my repos, but won't touch them anymore.

cheers
flash ⚡

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Mar 22, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants