Angular-cli: Multiple entryModule support

Created on 5 Sep 2018  路  15Comments  路  Source: angular/angular-cli

_From @artonge on May 7, 2018 14:51_

Bug Report or Feature Request (mark with an x)

- [ ] bug report -> please search issues before submitting
- [x] feature request

Area

- [x] devkit
- [ ] schematics

Versions


node version: v9.4.0
npm version: 5.6.0
Linux (Ubuntu 17.10)

Repro steps

Clone this example: https://github.com/artonge/multiple-entrymodules

The log given by the failure

At execution in the browser I have:
Uncaught Error: No NgModule metadata found for 'AppModule'.
This error only appears for the module that wasn't specified has the entryModule in the webpack config.

Desired functionality

At my company our webpack config has two entry points for two different apps, and generate two bundles for the two apps. The problem is that when using AOT, we can only specify one entryModule, but the two apps have different entryModule. It would be nice to specify two entryModules so the metadata are generated for both of them.

_Copied from original issue: angular/devkit#861_

ngtoolwebpack triage #1 feature

Most helpful comment

I would love to find a solution as well.

All 15 comments

_From @james-criscuolo on May 7, 2018 20:41_

I am also running into this issue while upgrading. I used to be able to use the ngtools/webpack loader without the plugin, which allowed me to get around this issue. I would do this in development, then for production builds I would have the significantly longer build where I sent each entry point individually through webpack. Now I have no choice but to use the plugin in development, so my build process will suffer tremendously once I complete the upgrade.

_From @artonge on May 9, 2018 9:3_

Could this feature be backported to version 1.10.2 ? Any ETA ?
Can a maintainer provide some indications to help me to add this feature ? Where should I look ? How to backport it ?

When trying to install @ngtools/webpack dependencies with npm install, I have the following error:
No matching version found for @angular-devkit/[email protected]

_From @artonge on May 15, 2018 9:33_

Duplicate of:

@clydin could you help me comming with a solution ? I created a pull request #875 but some tests failed...

_From @filipesilva on May 24, 2018 17:33_

This is something we are interested it, but not for 6.x. We will re-evaluate when the Angular Ivy compiler is available as that changes how this feature would work.

_From @sherlock1982 on May 24, 2018 17:54_

Could you please provide a kind of a workaround for this? Because I don't quite understand how can I code-split two endpoints in one app. Or for example how a custom element and an app can code-split angular.

_From @artonge on May 25, 2018 9:32_

Thanks for the answer @filipesilva ! As @sherlock1982 asked, could you provide some workaround ? Or tell us if my solution in #875 is safe to use ?

I would love to find a solution as well.

is it still relevant?
I'm still not able to configure multiple entries using @ngtools/webpack 7.3.8

This is a fairly significant blocker. Our application can't be an SPA due to varying concerns/implementations. We really want to use Angular w/AOT and have implemented a significant amount of our frontend code using Angular 7. Not being able to bootstrap multiple root modules is a huge blocker for us since we don't need a complete page takeover, but multiple modules to only takeover certain parts of the UI since the majority of the UI is generated on the backend.

Having multiple root modules work via JIT, but not AOT, doesn't make a lot of sense and gives a false impression during development that it would work in production w/AOT. I didn't even realize this was a limitation since I didn't see anything about it in the documentation. It took me troubleshooting and looking on stackoverflow/googling for 3 days to find this out. The documentation does give an example of having multiple roots, which is kinda confusing.

Creating multiple projects doesn't seem like a reasonable option, either. As it would lead to having to create an individual project for each part of the UI that needs to be taken over.
If this is something that the Angular team is looking at implementing, as @filipesilva indicated in his post on the original issue:

_From @filipesilva on May 24, 2018 17:33_

This is something we are interested it, but not for 6.x. We will re-evaluate when the Angular Ivy compiler is available as that changes how this feature would work.

Could we get some feedback on whether there is an approach to workaround this issue, other than sticking with JIT? There were other comments asking for clarity on it that never received a response.

_From @artonge on May 25, 2018 9:32_

Thanks for the answer @filipesilva ! As @sherlock1982 asked, could you provide some workaround ? Or tell us if my solution in #875 is safe to use ?

If there were a way to have a root module that could then conditionally bootstrap other modules, that would at least provide a work-around.

I attempted this workaround while attempting to utilize lazy-loading. But it doesn't work since the root module doesn't actually attach to the DOM and I was simply attempting to bootstrap the other modules.

No matter my attempt, I consistently received the "Uncaught Error: No NgModule metadata found" exception in the browser for AOT. During the build process, no errors were being generated.

@trickeyone For AOT you may want to try my fork of @ngtools/webpack (which is forked from @artonge). Install @rush/webpack (https://github.com/Rush/angular-cli)

And use it like so:

const AotPlugin = require('@rush/webpack').AngularCompilerPlugin;

const aotPlugins = USE_AOT ? [
  new AotPlugin({
    tsConfigPath: IS_PRODUCTION ? 'tsconfig.prod.json' : 'tsconfig.dev.json',
    entryModules: [
      path.join(__dirname, 'src/js/app/app.module#AppModule'),
      path.join(__dirname, 'src/js/app/landing.module#LandingModule'),
    ],
    skipCodeGeneration: !IS_PRODUCTION,
  })
] : [];

If there were a way to have a root module that could then conditionally bootstrap other modules, that would at least provide a work-around.

Kind of :-)

// unfortunately for AOT compiler to work, these components need to be defined twice
// (AOT will throw)
const declarations = [
    LandingComponent,
    GetNotifiedComponent,
    TypedComponent,
    StickyBarComponent,
    ImageGalleryComponent,
    RequestDemoFormComponent,
    PricingPlansComponent,
    SalesRequestFormComponent,
    DetailedPricingPlansComponent,
];

const landingComponents = {
    'landing-root': LandingComponent,
    'get-notified': GetNotifiedComponent,
    'typed-component': TypedComponent,
    'sticky-bar': StickyBarComponent,
    'image-gallery': ImageGalleryComponent,
    'request-demo-form': RequestDemoFormComponent,
    'pricing-plans': PricingPlansComponent,
    'detailed-pricing-plans': DetailedPricingPlansComponent,
    'standalone-help-manual': StandaloneHelpManualComponent,
};

function hasKey<O>(obj: O, key: string | number | symbol): key is (keyof O) {
    return key in obj;
}

// tslint:disable-next-line:max-classes-per-file
@NgModule({
    declarations,
    entryComponents: [...declarations, StandaloneHelpManualComponent],
    imports: [
        BrowserModule,
        CommonModule,
        ClarityModule,
        LightboxModule,
        HttpClientModule,
        FormsModule,
        BrowserAnimationsModule,
        HelpModule,
    ],
    providers: [
        WaitlistedService,
        PricingService,
    ],
})
export class LandingModule {
    ngDoBootstrap(applicationRef: ApplicationRef) {
        for (const tagName in landingComponents) {
            if (hasKey(landingComponents, tagName)) {
                const component = landingComponents[tagName];
                if (document.getElementsByTagName(tagName).length) {
                    applicationRef.bootstrap(component as any);
                }
            }
        }
    }
}

As you can see I am using both methods. I have one app which is a plain old regular Angular app and a LandingModule which is using the above trick to get different components bootstrapped on different landing pages.

After doing some research into @angular/elements, I have been able to, so far, successfully implement partial takeovers. It's taken some reworking of a number of components, to allow for them to be used as regular Angular components and then to also be used as custom elements.

I do really like the @angular/elements setup, but I would suggest possibly allowing for components to be included as custom elements without having to do the createCustomElement(...) and customElements.define(...) routine. While it's not necessarily a large amount of overhead for the developer (i.e. me) to do, it does seem to be a significant amount of extra work for this feature to work. I would suggest possibly allowing this to be implemented using the @Component metadata and possibly a new @NgModule section to include custom elements.

i.e.

@Component({
    selector: 'my-component',
    templateUrl: '...'
})
class MyComponent {
}

@NgModule({
...
    customElements: [MyElementComponent]
})
class AppModule {}

This seems like it would a much easier implementation. If @angular/elements is not present and customElements is defined, then an exception could be thrown(?).

if you need an option for multiple paths instead of multiple entry modules, I've forked @rush (based from @artonge) and added this feature
https://github.com/jetlogs/angular-cli

npm install @jetlogs/webpack

import { AngularCompilerPlugin } from "@jetlogs/webpack";


new AngularCompilerPlugin({
    tsConfigPath: "tsconfig.json",
    paths: [
      "/path/to/entry1.ts",
      "/path/to/entry2.ts"
    ]
})


Any news on this feature? Do you have an ETA for the multi entryModule support? It's a blocker for us.
It looks like this commit by @Rush implements it:
https://github.com/Rush/angular-cli/commit/d439496e2550be29d59c2677ec323d360fc19b51

Is it possible to add this commit to webpack repository?

I'm glad to see some activity on this issue! For what it's worth, I have my own branches in which I've rebased the work by @Rush and @artonge onto the v9.1.7 release of angular-cli:

https://github.com/francisli/angular-cli/tree/v9.1.7-multiple-entry-modules

And I've built the package for direct reference in package.json files here (instead of publishing yet another variation of the package to npm):

https://github.com/francisli/ngtools-webpack-builds/tree/9.1.x-multiple-entry-modules

Hope this helps anyone else landing here, looking for this support with the latest release of Angular and TypeScript...

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._

Was this page helpful?
0 / 5 - 0 ratings