您忘记导入 "NgxsSelectSnapshotModule" // NGXS 模块

You've forgotten to import "NgxsSelectSnapshotModule" // the NGXS module

[更新:好的。我们找到了如何复制,参见最小复制]

描述

我们在服务器日志中看到生产环境和非生产环境中的许多这 2 个致命错误:

我们显然已经在 AppModule 和功能模块中导入了两个 ngxs 模块。 在应用程序模块中:

      NgxsModule.forRoot(
      [
      xxx....
      ],
      {
        developmentMode: !environment.production,
      },
    ),
    NgxsRouterPluginModule.forRoot(),
    NgxsFormPluginModule.forRoot(),
    NgxsSelectSnapshotModule.forRoot(),
    NgxsStoragePluginModule.forRoot({
         ...xxx
      },
    }),
    NgxsReduxDevtoolsPluginModule.forRoot({
      name: 'xxxx',
      disabled: environment.production,
    }),

在功能模块中:

    NgxsModule.forFeature([xxx, yyy]),
    NgxsSelectSnapshotModule,

这是一个非常庞大的项目,包含许多模块和组件...错误仅通过 SSR 发生,而且在我们的开发机器上很少发生...不过,当它发生时,我们会看到很多连续出现错误语句,而没有其他组件或模块抱怨错误。它只是 ngxs。 看起来,SSR 仍然提供 html,并且 Angular 应用程序在客户端上的加载仍然很好(包括所有 ngxs 的东西)

最小复制

好的。我们发现了如何重现:

  1. 在浏览器中打开一个页面
  2. 刷新
  3. 快速中止加载
  4. 再次快速刷新
  5. --> 很多很多致命错误

猜测:这可能是由于 angular 销毁了所有东西,两个 ngxs 模块都会清除 Injector onDestroy。 由于只有当我们在中止后快速重新加载时才会发生错误(只是中止永远不会产生错误),所以它一定是关于 angular 通用仍然(重新?)使用一些组件而 ngxs 已经摆脱了它的注入器引用。

https://github.com/ngxs-labs/select-snapshot/blob/0b3b7fea09cd6db9fd7327f2b2710d24391e75a1/src/lib/core/internals/static-injector.ts#L27

异常或错误

FATAL [main.js:2897] Error: You have forgotten to import the NGXS module! 
    at createSelectObservable (/opt/app/dist/server/main.js:1:xx) 
    at AppComponent.get [as progress] (/opt/app/dist/server/main.js:1:xx) 
    at AppComponent_Template (/opt/app/dist/server/main.js:2897:1625353) 
    at executeTemplate (/opt/app/dist/server/main.js:2897:xx) 
    at refreshView (/opt/app/dist/server/main.js:2897:xx) 
    at refreshComponent (/opt/app/dist/server/main.js:2897:xx) 
    at refreshChildComponents (/opt/app/dist/server/main.js:2897:xx) 
    at refreshView (/opt/app/dist/server/main.js:2897:xx) 
    at renderComponentOrTemplate (/opt/app/dist/server/main.js:2897:xx)
    at tickRootContext (/opt/app/dist/server/main.js:2897:xx)

or....

FATAL [main.js:2897] NgxsSelectSnapshotModuleIsNotImported [Error]: You've forgotten to import "NgxsSelectSnapshotModule"! 
    at assertDefined (/opt/app/dist/server/main.js:2897:xx) 
    at getStore (/opt/app/dist/server/main.js:2897:xx) 
    at XXXComponent.get [as isXXX] (/opt/app/dist/server/main.js:2897:xx) 
    at XXXComponent_Template (/opt/app/dist/server/main.js:2897:xx) 
    at executeTemplate (/opt/app/dist/server/main.js:2897:xx) 
    at refreshView (/opt/app/dist/server/main.js:2897:xx) 
    at refreshComponent (/opt/app/dist/server/main.js:2897:xx) 
    at refreshChildComponents (/opt/app/dist/server/main.js:2897:xx) 
    at refreshView (/opt/app/dist/server/main.js:2897:xx) 
    at refreshComponent (/opt/app/dist/server/main.js:2897:xx)

环境

Libs:
    "@angular/core": "^11.0.6",
    "@ngxs/store": "^3.7.1",
    "@ngxs-labs/select-snapshot": "^2.0.1",

Browser: only on SSR

这个问题的根本原因是这个文件:https://github.com/ngxs/store/blob/master/packages/store/src/decorators/select/select-factory.ts

SelectFactory class 中存在的存储键是整个服务器的单例(它不是 Angular 特定的单例)。从装饰器内部的使用方式可以看出:https://github.com/ngxs/store/blob/8b52ae654c0a707612a8d23bde4737e69cbb8ee9/packages/store/src/decorators/select/symbols.ts#L11

因此,如果某个用户的 NGXS 模块在某个时刻被破坏,而此时另一个用户的服务器端代码仍然是 运行,则会出现错误

https://user-images.githubusercontent.com/37243777/109517260-bb977f00-7ab1-11eb-9b6c-7c92344b2465.png

我建议重构这个装饰器,使其依赖于每个使用的组件中的商店,而不是依赖于商店,商店是整个服务器的单例。

此外,这个问题也存在于 select-快照存储库中,并且与服务器范围的单例 (https://github.com/ngxs-labs/select-snapshot)

存在相同的潜在问题