wishtack / wishtack-steroids

Frontend on Steroids: Reactive Component Loader, RxJS Scavenger...
https://wishtack.io
MIT License
95 stars 16 forks source link

[issue] Uncaught (in promise): Error: StaticInjectorError(AppServerModule)[InjectionToken REACTIVE_COMPONENT_LOADER_MODULE_REGISTRY]: #182

Closed elribonazo closed 4 years ago

elribonazo commented 5 years ago

Hi, thanks in advance for any help. This library saved my life.

Well, the thing is that I'm getting an error, I'm not sure if its a bug or not thats why I tagged it with [issue] instead.

Error I'm getting. ERROR { Error: Uncaught (in promise): Error: StaticInjectorError(AppServerModule)[InjectionToken REACTIVE_COMPONENT_LOADER_MODULE_REGISTRY]: StaticInjectorError(Platform: core)[InjectionToken REACTIVE_COMPONENT_LOADER_MODULE_REGISTRY]: NullInjectorError: No provider for InjectionToken REACTIVE_COMPONENT_LOADER_MODULE_REGISTRY! Error: StaticInjectorError(AppServerModule)[InjectionToken REACTIVE_COMPONENT_LOADER_MODULE_REGISTRY]: StaticInjectorError(Platform: core)[InjectionToken REACTIVE_COMPONENT_LOADER_MODULE_REGISTRY]: NullInjectorError: No provider for InjectionToken REACTIVE_COMPONENT_LOADER_MODULE_REGISTRY!

My goal is intead of defining the following each time i needed and adding it to the import of my AppModule, importing all the routes using withModule based on a configuration file (if not i have to replicate routes 2 times...) : ReactiveComponentLoaderModule.withModule({ moduleId: camelCase(route.path, { pascalCase: true }), loadChildren: 'app/views/aboutUs/AboutUs.module#AboutUsModule' })

Approach `const core = NgModule({ imports: config.EngineRegistry.reduce((modules, route: EngineRegistryItem, index) => {

    return ([
        ...modules,
        ReactiveComponentLoaderModule.withModule({
            moduleId: camelCase(route.path, { pascalCase: true }),
            loadChildren: 'app/views/aboutUs/AboutUs.module#AboutUsModule'
        })
    ])
}, [ReactiveComponentLoaderModule.forRoot()]),
providers: [{ provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader }]

})(class { });

@NgModule({ imports: [ SSRTransition.forRoot({ appId: 'my-app' }), BrowserModule, PrebootModule.withConfig({ appRoot: 'app-root', replay: false }), TransferHttpCacheModule, BrowserAnimationsModule, ComponentsModule, RouterModule, AppRoutes, ReactiveComponentLoaderModule.forRoot(), core ], declarations: [AppComponent], bootstrap: [AppComponent], providers: [{ provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader }, SSRService] }) export class AppModule { }`

I'm not sure why I'm getting this but If i add the routes manually it works... hope I don't require to duplicate my filesssss.

yjaaidi commented 5 years ago

Hi Javier,

Sorry for the inconvenience but for the moment the declaration of modules should be done at compile time. That's why you will have to explicitly call ReactiveComponentLoaderModule.withModule for each module with a static moduleId.

I hope to change this behavior soon with the next release that will benefit from Angular 8 lazy module import.

elribonazo commented 5 years ago

Hi Yjaaidi, thanks for writing me back.

At the end, I need to write all the routes in 2 files. I got all my dynamic components with AOT, servers side and a hack to wait for all the subscriptions and render back the content.

My workarround is needed because who decides which view is not the router based in the url. In my case its based on a mongodb response from database.

So, DB tells us to load "template-default", and because we previously declared the lazy module at that point it will load. I've mixed that with state transfer from server to client and as everything is bundled within every route and routes are lazy loaded the performance has improved like 80%. I have also created a <ssr-template [content]="content"> directive, with the hability of rendering contents from the database. I can save and load it after on any view or page without caring if its ssr, lazyload or not.

The issue that I was having is that the server was not returning all the contents correctly rendered, it had a lot of sense because a lot of components had Observers and Subscriptions.

At the end I added a new provider to the AppServerModule
providers: [
        {
            provide: BEFORE_APP_SERIALIZED,
            useFactory: function (core: SSRService): Function {
                return async () => {
                    await core.processPendingTasks()
                };
            },
            deps: [SSRService],
            multi: true
        }
]

If i can help you with the release I'll be happy. I love your Module, thanks!

yjaaidi commented 4 years ago

Awesome! That's a really interesting use case. Any contributions or improvement ideas are welcome 😊 I'm glad you like it, thanks!