Skip to content
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

Standalone API in module-based apps: StoreFeatureModule exception #4092

Open
1 of 2 tasks
mauriziocescon opened this issue Oct 23, 2023 · 6 comments
Open
1 of 2 tasks
Assignees

Comments

@mauriziocescon
Copy link

mauriziocescon commented Oct 23, 2023

Which @ngrx/* package(s) are the source of the bug?

store

Minimal reproduction of the bug/regression with instructions

Standalone API in module-based apps: imagine you have a reusable module where some ngrx actions / reducers are defined (typical example: shared-module). Since it's a reusable one, it's imported by other ones (route-based and app modules).

Now, it seems to me this is not working fine as long as provideState is used. In particular there's an exception in the StoreFeatureModule constructor for modules importing the shared one (featureReducers = []).

This is an example you can check it out (my reusable module is called CoreModule):

@NgModule({
  imports: [
    // WORKING FINE
    StoreModule.forFeature(coreFeature),
    EffectsModule.forFeature(coreEffects),
  ],
   ...
  providers: [
    // NOT WORKING: exception in the console
    // provideState(coreFeature),
    // provideEffects(coreEffects),
  ],
  ...
})
export class CoreModule {
}

Consider this a reusable module, imported by other route-based ones (in my example InstanceDetailModule and InstanceListModule) and AppModule.

Here are some screenshots:

Screenshot 2023-10-23 at 11 30 17 Screenshot 2023-10-23 at 11 31 23

Expected behavior

For big enterprise applications, there's no other way than mixing and matching different styles of code. Therefore:

StoreModule.forFeature(...),
EffectsModule.forFeature(...),
provideState(...),
provideEffects(...),

should be interchangeable and provideState should work fine when called multiple times with the same data (as StoreModule.forFeature does).

Versions of NgRx, Angular, Node, affected browser(s) and operating system(s)

NgRx: ^16.0.0
Angular: ^16.0.0
Node: ^18.0.0
Browser(s): any
Operating systems): OSX

Other information

No other info

I would be willing to submit a PR to fix this issue

  • Yes
  • No
@LayZeeDK
Copy link
Contributor

LayZeeDK commented Oct 24, 2023

I experience similar issues when mixing the classic NgRx state APIs with the standalone NgRx state APIs.

In my minimal reproducible example we see that replacing StoreModule.forFeature with provideState or EffectsModule.forFeature with provideEffects in an Angular feature module results in a NullInjectorError:

Error: Uncaught (in promise): NullInjectorError: NullInjectorError: No provider for InjectionToken @ngrx/store Root Store Provider!

This example uses platformBrowser().bootstrapModule(AppModule), a classic AppComponent, and a classic (NgModule-based) Angular feature.

@LayZeeDK
Copy link
Contributor

Related #4063

@mauriziocescon
Copy link
Author

@LayZeeDK not sure it's the same case... IMO in your AppModule you're missing some mandatory providers (which are defined in my case):

@NgModule({
  bootstrap: [AppComponent],
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpClientModule,
    RouterModule.forRoot(routes),
    StoreModule.forRoot(
      {},
      {
        runtimeChecks: {
          strictStateImmutability: true,
          strictActionImmutability: true,
          strictStateSerializability: true,
          strictActionSerializability: true,
          strictActionWithinNgZone: true,
          strictActionTypeUniqueness: true,
        },
      }
    ),
    StoreDevtoolsModule.instrument({ maxAge: 25 }),
    EffectsModule.forRoot(),
    RouterLink,
    RouterOutlet,
  ],
  providers: [
    provideStore(),
    provideEffects(),
  ],
})
export class AppModule {}

https://ngrx.io/guide/store/reducers#standalone-api-in-module-based-apps

@mauriziocescon
Copy link
Author

I checked also #4063 and it seems to me it's a little bit different: my setup (AppModule) is module-based... so I guess the error might be the same (as the root cause) but according to the doc... well it seems to me it shouldn't fail.

The main point is: in a huge module-based app, I think it's pretty natural start any code migration from reusable-modules. I believe It's also natural avoid changing the way these modules are consumed (the imports). And since they are reusable, they can be imported by other modules everywhere.

@LayZeeDK
Copy link
Contributor

Thank you for the reference to NgRx Store Standalone API in module-based apps and NgRx Effects Standalone API in module-based apps, @mauriziocescon.

As seen in this StackBlitz fork, duplicating arguments between StoreModule.forRoot and provideStore as well as EffectsModule.forRoot and provideEffects in AppModule.imports and AppModule.providers solves my issue

@mauriziocescon
Copy link
Author

Just in case, this is an easier example to check
https://stackblitz.com/edit/stackblitz-starters-pculha?file=src%2Fapp%2Fshared.module.ts

@brandonroberts brandonroberts self-assigned this Oct 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants