Closed zerefel closed 6 years ago
This works with @angular/cli
projects: see @angular-redux/example-app
for instance. Running that with ng serve --aot
works correctly.
I'm guessing you're not using @angular/cli
? Can you provide some more details about how you build and bundle your code?
Thanks for the reply!
My project is based on this repo: https://github.com/angularclass/angular2-webpack-starter It is using webpack to build and bundle the code.
I am running the npm run build:aot:prod
command. It basically cleans up the dist
folder to prepare it for the new release and then executes webpack --config config/webpack.prod.js
.
Unfortunately I cannot link the repo where I can reproduce it, as it is private. However, the way I am injecting the NgReduxRouter service might be causing some trouble:
@Injectable()
export class StoreConfig {
constructor(private redux: NgRedux<AppState>,
private injector: Injector
) {
}
private get reduxRouter(): NgReduxRouter {
return this.injector.get(NgReduxRouter);
}
load(): Promise<any> {
const store = ...;
// some async function calls with redux-persist
// after the store is recovered, initialize redux and the redux router
this.redux.provideStore(store);
this.reduxRouter.initialize();
}
}
Basically, I have a service with a load()
method, which is invoked during App Initialization, using the APP_INITIALIZER provider in app.module.ts
The reason why I'm injecting it in a getter is due to some case-specific reasons, which I don't want to trouble you with, unless you suspect they could be causing the problem.
Did you ever find a solution for this? I'm seeing this error w/ @angular/core
4.1.3 and @angular-redux/router
6.3.0.
@drewloomer Not yet, I am currently using JiT compilation for my production environment as I'm pressed by time. I will make sure to report here if and when I find a solution.
The solution I found was to NOT setup the store and router in the app module constructor, but rather in a separate store module (like in the example app).
store.module.ts
import { NgModule } from '@angular/core';
import { Action } from 'redux';
import { NgReduxModule, NgRedux, DevToolsExtension } from '@angular-redux/store';
import { NgReduxRouterModule, NgReduxRouter } from '@angular-redux/router';
import { createLogger } from 'redux-logger';
import { TestActions } from '../actions';
import { rootReducer } from '../reducers';
import { IAppState, INITIAL_STATE } from './store.model';
@NgModule({
imports: [NgReduxModule, NgReduxRouterModule],
providers: [TestActions],
})
export class StoreModule {
constructor(
public ngRedux: NgRedux<IAppState>,
devTools: DevToolsExtension,
ngReduxRouter: NgReduxRouter
) {
ngRedux.configureStore(
rootReducer,
INITIAL_STATE,
[createLogger()],
devTools.isEnabled() ? [ devTools.enhancer() ] : []);
ngReduxRouter.initialize();
}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { NgReduxModule } from '@angular-redux/core';
import { NgReduxRouterModule } from '@angular-redux/router';
import { RouterModule } from '@angular/router';
import { StoreModule } from './store/store.module';
import { routes } from './routes';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
RouterModule.forRoot(routes),
BrowserModule,
FormsModule,
HttpModule,
NgReduxModule,
NgReduxRouterModule,
StoreModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
@drewloomer Unfortunately this does not work for me, because I need the store to be initialized before the Angular application has started. This is why I use the APP_INITIALIZER provider.
app.module.ts
@NgModule({
bootstrap: [AppComponent],
declarations: [
AppComponent
],
imports: [ // Import modules here (NEVER IMPORT LAZY MODULES!!!)
StoreModule
],
providers: [ // expose our Services and Providers into Angular's dependency injection
ENV_PROVIDERS,
APP_PROVIDERS,
{
provide: APP_INITIALIZER, // APP_INITIALIZER will execute the function when the app is initialized and delay what it provides.
useFactory: initStore,
deps: [StoreConfig],
multi: true
}
]
})
export function initStore(storeConfig: StoreConfig): Function {
return () => storeConfig.load();
}
store.service.ts
import { Injectable, Injector, isDevMode } from '@angular/core';
import { NgRedux, DevToolsExtension } from '@angular-redux/store';
import { NgReduxRouter } from '@angular-redux/router';
import { combineEpics, createEpicMiddleware, } from 'redux-observable';
import { createStore, compose, applyMiddleware, Store } from 'redux';
import * as localForage from "localforage";
import { persistStore, autoRehydrate, getStoredState } from 'redux-persist';
import { AppState, rootReducer } from './store';
import { ContentEpics } from './epics/content.epics';
import { UserEpics } from './epics/user.epics';
import { AppEpics } from './epics/app.epics';
import { ExpertsEpics } from './epics/experts.epics';
import { DashboardEpics } from './epics/dashboard.epics';
@Injectable()
export class StoreConfig {
constructor(private redux: NgRedux<AppState>,
private injector: Injector,
private contentEpics: ContentEpics,
private userEpics: UserEpics,
private appEpics: AppEpics,
private expertsEpics: ExpertsEpics,
private dashboardEpics: DashboardEpics) {
}
private get devTools(): DevToolsExtension {
return this.injector.get(DevToolsExtension);
}
private get reduxRouter(): NgReduxRouter {
return this.injector.get(NgReduxRouter);
}
load(): Promise<any> {
const epics = combineEpics(
this.contentEpics.epics,
this.userEpics.epics,
this.appEpics.epics,
this.expertsEpics.epics,
this.dashboardEpics.epics
);
let enhancer: any = null;
if (isDevMode() && this.devTools.isEnabled()) {
enhancer = compose(
applyMiddleware(createEpicMiddleware(epics)),
autoRehydrate(),
this.devTools.enhancer());
} else {
enhancer = compose(
applyMiddleware(createEpicMiddleware(epics)),
autoRehydrate());
}
const persistConfig = {storage: localForage, whitelist: ['app', 'user'], blacklist: ['content']};
return new Promise((resolve: any) => {
getStoredState(persistConfig, (err, state) => {
const store = createStore(
rootReducer,
state,
enhancer);
persistStore(store, persistConfig, () => {
this.redux.provideStore(store);
this.reduxRouter.initialize();
resolve(true);
});
});
});
}
}
I use the Angular Injector to inject the NgReduxRouter and the DevTools enhancers, because if I do not, I get a Cannot instantiate cyclic dependency! ApplicationRef
error in the console.
Hey there, when making an AoT compilation, the following error is thrown:
ERROR Error: Uncaught (in promise): Error: No provider for NgReduxRouter! Error at injectionError (core.es5.js:1231) [angular] at noProviderError (core.es5.js:1269) [angular] at ReflectiveInjector_._throwOrNull (core.es5.js:2770) [angular] at ReflectiveInjector_._getByKeyDefault (core.es5.js:2809) [angular] at ReflectiveInjector_._getByKey (core.es5.js:2741) [angular] at ReflectiveInjector_.get (core.es5.js:2610) [angular] at AppModuleInjector.NgModuleInjector.get (core.es5.js:3557) [angular] at StoreConfig.get [as reduxRouter] (store.service.ts:36) [angular]
The module works just fine when used in JiT.
Angular version: 4.0.1 Node version
node -v
: 6.9.2 @angular-redux/router version: 6.1.0