更新: Ok。我们发现了如何复制,见最小复制
描述
在生产和非生产环境中,我们可以在服务器日志中看到以下两个致命错误中的许多:
致命
main.js:xx
NgxsSelectSnapshotModuleIsNotImported
错误
:您忘记导入"NgxsSelectSnapshotModule“了!在getStore的assertDefined (/opt/app/dist/server/main.js:xx:yy)
致命
main.js:xx
错误:您忘记导入NGXS模块!在createSelectObservable (/opt/app/dist/server/main.js:1:yy)
很明显,我们已经在AppModule和Feature Modules中导入了ngxs模块。在App模块中:
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内容)。
?最小重现
好的。我们找到了复制的方法:
在浏览器中打开页面
刷新
快速中止加载
再次快速刷新
-->许多致命错误
猜想:这可能是因为角度破坏了所有的东西,两个ngxs模块都会清除注入器onDestroy。因为只有当我们在中止后快速重新加载时才会发生错误(仅仅中止永远不会产生错误),它一定是关于角度通用的(re-?)使用一些组件,而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发布于 2021-03-01 23:16:59
此问题的根本原因是此文件:
https://github.com/ngxs/store/blob/master/packages/store/src/decorators/select/select-factory.ts
SelectFactory类中的存储键是整个服务器的单例(它不是特定于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
我建议重构这个装饰器,使其依赖于所使用的每个组件中的Store,而不是依赖于store,后者是整个服务器的单例。
此外,这个问题也存在于select-snapshot存储库中,这与服务器范围的单例(
https://github.com/ngxs-labs/select-snapshot
)
https://stackoverflow.com/questions/66402180
复制相似问题