2

I am working with a (.NET Framework MVC) web project that cannot be fully transferred to a full angular project, so I cannot use angular's routing to lazy load, but I also don't want to load everything where the angular components are used. It is an enterprise solution where it is not easy (and cheap) to say: "Hey, lets fully utilize angular and forget about the old project!".

So I have solved this, in my opinion, in a clean way to load different modules based on URL, to avoid loading everything all together:

main.ts

console.log("bootstrapping start");
if (window.location.pathname.toLowerCase().includes("contactplans/details")) {
    console.log("bootstrapping contactplan details");
    platformBrowserDynamic().bootstrapModule(ContactplanDetailsModule)
        .catch(err => console.log(err));
} else if (window.location.pathname.toLowerCase().includes("contactplans/index") || window.location.pathname.toLowerCase().endsWith("contactplans") || window.location.pathname.toLowerCase().includes("settings/contactplans")) {
    console.log("bootstrapping contactplan index");
    platformBrowserDynamic().bootstrapModule(ContactplanListModule) //contact plan index and settings page
        .catch(err => console.log(err));
} 
console.log("bootstrap decision done, bootstrapping menu");
platformBrowserDynamic().bootstrapModule(MenuModule)
    .catch(err => console.log(err));

So based on the URL, it loads modules and on every page it loads the menu module.

For the time being, I kind-of have to do it this way, this is just a small example the the usage of angular will grow significantly on more and more individual pages until we can more easily 'switch' to a full angular project (within .NET Core which works awesome together).

So, this works fine on development. Using ng build --watch does the desired things. Now going production, running ng build --prod it creates issues. To me it looks more like a bug then something else.

In the below screenshot I demonstrate what is being produced after ng build --prod when I make modifications to above code.

Click here to show bigger enter image description here

So as you can see, when only using one line of bootstrap, it works fine, no errors.

But when I have multiple like I want to have, it changes the actual Module to function() {} which then gives the console error:

Uncaught Error: No NgModule metadata found for 'function(){}'.

Is this really a bug or am I doing something wrong?

3
  • I did the same I got this warning when I run ng serve . ``` WARNING in Lazy routes discovery is not enabled. Because there is neither an entryModule nor a statically analyzable bootstrap code in the main file. ``` Commented Jun 4, 2019 at 4:02
  • Hi CularBytes, did you find the solution for this problem ? which approach you have taken? please suggest. Commented Nov 10, 2020 at 22:44
  • @kaleshanagineni unfortunately I couldn't find a better solution then the only answer there is. Commented Nov 11, 2020 at 9:02

1 Answer 1

2

Bootstrapping component based on url

I had the same problem, my solution was to bootstrap different components based on the url rather than bootstrapping different Modules

The solution is based on this article: How to manually bootstrap an Angular application

You don't edit the main.ts but in the AppModule you bootstrap the different components manually based on the url and add them to the DOM

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { ContactplanDetailsComponent } from './ContactplanDetails.component';
import { ContactplanListComponent } from './ContactplanList.component';
import { MenuComponent } from './Menu.component';



@NgModule({
  imports: [BrowserModule],
  declarations: [
     ContactplanDetailsComponent,
     ContactplanListComponent,
     MenuComponent
  ],
  //bootstrap: [AppComponent] Bootstrapping is done manually
  entryComponents: [
     ContactplanDetailsComponent,
     ContactplanListComponent,
     MenuComponent
  ]

})
export class AppModule { 
  ngDoBootStrap(app) {
    bootstrapComponent(app);
  }
}

function bootstrapComponent(app) {

  var name = [];

  const options = {
    'contact-plan-details': ContactplanDetailsComponent,
    'contact-plan-list': ContactplanListComponent,
    'menu': MenuComponent
  };

  if (window.location.pathname.toLowerCase().includes("contactplans/details")) {
    name.push("contact-plan-details"); 
  } else if (window.location.pathname.toLowerCase().includes("contactplans/index") || window.location.pathname.toLowerCase().endsWith("contactplans") || window.location.pathname.toLowerCase().includes("settings/contactplans")) {
    name.push("contact-plan-list");
  } 
  name.push("menu")

  name.forEach(function (element) {

    const componentElement = document.createElement(element);
    document.body.appendChild(componentElement);

    const component = options[element];
    app.bootstrap(component);

  });
}
Sign up to request clarification or add additional context in comments.

1 Comment

Although it is in some way a valid answer, I unfortunately notice that it requires me to import all modules that every component needs. So I am not 100% sure if this would benefit loading time / performance. For example a html editor is imported into AppModule while it is only needed in the ContactplanDetailsComponent. What do you think?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.