angularprimengangular-standalone-components

Can't get through third and final step of Angular standalone migration: Providers from the BrowserModule have already been loaded


I've recently successfully migrated an application of mine to Angular 19 and PrimeNG 19. All I had set aside for doing later was migrating to the new, preferred use of standalone components.

The first two steps of that process, automated using ng g @angular/core:standalone:

...went smoothly. The running application after those two steps can be found at https://tzexplorer.org. The above Github link to my development branch has the code in that last successful state.

But my attempts to achieve the final step (Bootstrap the application using standalone APIs) are being thwarted by this run-time error:

enter image description here

My main.ts ends up looking like this:

import { enableProdMode, importProvidersFrom } from '@angular/core';

import { environment } from './environments/environment';
import { initTimezoneLarge } from '@tubular/time';
import { themeProvider } from './app/mytheme';
import { AppService } from './app/app.service';
import { HttpTimePoller } from './app/http-time-poller/http-time-poller';
import { TzExplorerApi } from './app/api/api';
import { provideHttpClient, withInterceptorsFromDi, withJsonpSupport } from '@angular/common/http';
import { AppRoutingModule } from './app/app-routing.module';
import { AutoCompleteModule } from 'primeng/autocomplete';
import { BrowserModule, bootstrapApplication } from '@angular/platform-browser';
import { provideAnimations } from '@angular/platform-browser/animations';
import { ButtonModule } from 'primeng/button';
import { CheckboxModule } from 'primeng/checkbox';
import { DialogModule } from 'primeng/dialog';
import { FormsModule } from '@angular/forms';
import { InputTextModule } from 'primeng/inputtext';
import { RadioButtonModule } from 'primeng/radiobutton';
import { RippleModule } from 'primeng/ripple';
import { SelectModule } from 'primeng/select';
import { TabsModule } from 'primeng/tabs';
import { TubularNgWidgetsModule } from '@tubular/ng-widgets';
import { AppComponent } from './app/app.component';

if (environment.production) {
  enableProdMode();
}

initTimezoneLarge();

bootstrapApplication(AppComponent, {
  providers: [
    importProvidersFrom(AppRoutingModule, AutoCompleteModule, BrowserModule, ButtonModule, CheckboxModule,
      DialogModule, FormsModule, InputTextModule, RadioButtonModule, RippleModule, SelectModule, TabsModule,
      TubularNgWidgetsModule),
    themeProvider,
    AppService,
    HttpTimePoller,
    TzExplorerApi,
    provideHttpClient(withInterceptorsFromDi(), withJsonpSupport()),
    provideAnimations()
  ]
})
  .catch(err => console.error(err));

...which is essentially just a matter of a bunch of imports being pulled out of my barely-otherwise-changed app.component.ts and moved into main.ts, where main.ts has had platformBrowserDynamic().bootstrapModule(AppModule) replaced with the new bootstrapApplication(AppComponent....

All the advice I've been able to find so far relates to tracking down redundant references to BrowserModule, BrowserAnimationsModule, provideAnimations, and provideAnimationsAsync. I have none of that happening in my code, at least in any obvious way.

My main suspect at this point is that some PrimeNG initialization is the source of the redundancy, but if that's the case, I don't know where or how it happens, or how I'd work around that.

I've tried commenting out providers one by one until I'm down to nothing, but the runtime error still remains. I've tried moving much of the complexity of the main.ts file and into a separate app.config.ts, but that didn't help either.

Any ideas anyone?


Solution

  • UPDATE:

    The problem is arising from usage of @tubular/ng-widgets which is using angular 14 version, the providers array is having some conflicts with angular 19, so you should upgrade the package and make the components standalone, also get rid of the module if you are converting the components to standalone.

    @Component({
      selector: 'tze-clocks',
      templateUrl: './clocks.component.html',
      styleUrls: ['./clocks.component.scss'],
      imports: [
        ...
        TubularNgWidgetsModule, // <- problem here
        ...
      ]
    })
    

    The problem will go away if you remove TubularNgWidgetsModule from ClocksComponent and CodeComponent


    You do not need few modules, so remove BrowserModule (taken care by bootstrapApplication), BrowserAnimationsModule, AppRoutingModule.

    Instead use provideRouter and supply your routes array.

    Since you are using primeng 19, providePrimeNG is the new method to use a theme. Use this stackblitz for code reference.

    The imports inside the importProvidersFrom belong in the imports array of the standalone component, if they are used.

    After the migrations you will no longer need any modules, your application should work the same but with standalone as the core concept.

    bootstrapApplication(AppComponent, {
      providers: [
        importProvidersFrom(TubularNgWidgetsModule),
        provideRouter(routes), // <- routes array goes here!,     provideHttpClient(withInterceptorsFromDi(), withJsonpSupport()),
        provideAnimationsAsync(),
        providePrimeNG({
          theme: { preset: Aura },
        }),
      ]
    }).catch(err => console.error(err));