Skip to content

Commit

Permalink
feat(Store): Add injection token option for feature modules (#153)
Browse files Browse the repository at this point in the history
Fixes AOT issues when providing reducers via an InjectionToken

Closes #116, #141, #147
  • Loading branch information
brandonroberts authored and MikeRyanDev committed Jul 25, 2017
1 parent be02eb9 commit 7f77693
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .angular-cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"apps": [
{
"root": "example-app",
"outDir": "dist",
"outDir": "example-dist",
"assets": [
"assets",
"favicon.ico"
Expand Down
1 change: 1 addition & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies:
test:
override:
- yarn run ci
- yarn run example:test -- --watch=false

deployment:
builds:
Expand Down
8 changes: 4 additions & 4 deletions example-app/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
"baseUrl": ".",
"rootDir": "../",
"paths": {
"@ngrx/effects": ["../modules/effects"],
"@ngrx/store": ["../modules/store"],
"@ngrx/router-store": ["../modules/router-store"],
"@ngrx/store-devtools": ["../modules/store-devtools"]
"@ngrx/effects": ["../dist/effects"],
"@ngrx/store": ["../dist/store"],
"@ngrx/router-store": ["../dist/router-store"],
"@ngrx/store-devtools": ["../dist/store-devtools"]
}
},
"exclude": [
Expand Down
2 changes: 1 addition & 1 deletion modules/effects/spec/effects_metadata.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('Effect Metadata', () => {

describe('getSourceProto', () => {
it('should get the prototype for an instance of a source', () => {
class Fixture { }
class Fixture {}
const instance = new Fixture();

const proto = getSourceForInstance(instance);
Expand Down
20 changes: 20 additions & 0 deletions modules/store/spec/modules.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ describe(`Store Modules`, () => {
'Root Reducers'
);

const featureToken = new InjectionToken<ActionReducerMap<RootState>>(
'Feature Reducers'
);

// Trigger here is basically an action type used to trigger state update
const createDummyReducer = <T>(def: T, trigger: string): ActionReducer<T> => (
s = def,
Expand Down Expand Up @@ -126,11 +130,23 @@ describe(`Store Modules`, () => {
})
class FeatureBModule {}

@NgModule({
imports: [StoreModule.forFeature('c', featureToken)],
providers: [
{
provide: featureToken,
useValue: featureBReducerMap,
},
],
})
class FeatureCModule {}

@NgModule({
imports: [
StoreModule.forRoot<RootState>(reducersToken),
FeatureAModule,
FeatureBModule,
FeatureCModule,
],
providers: [
{
Expand Down Expand Up @@ -158,6 +174,10 @@ describe(`Store Modules`, () => {
list: [1, 2, 3],
index: 2,
},
c: {
list: [1, 2, 3],
index: 2,
},
});
});
});
Expand Down
7 changes: 7 additions & 0 deletions modules/store/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,20 @@ export {
INITIAL_STATE,
_REDUCER_FACTORY,
REDUCER_FACTORY,
_INITIAL_REDUCERS,
INITIAL_REDUCERS,
STORE_FEATURES,
_INITIAL_STATE,
META_REDUCERS,
_STORE_REDUCERS,
_FEATURE_REDUCERS,
FEATURE_REDUCERS,
_FEATURE_REDUCERS_TOKEN,
} from './tokens';
export {
StoreRootModule,
StoreFeatureModule,
_initialStateFactory,
_createStoreReducers,
_createFeatureReducers,
} from './store_module';
68 changes: 61 additions & 7 deletions modules/store/src/store_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ModuleWithProviders,
OnDestroy,
InjectionToken,
Optional,
} from '@angular/core';
import {
Action,
Expand All @@ -17,11 +18,16 @@ import { compose, combineReducers, createReducerFactory } from './utils';
import {
INITIAL_STATE,
INITIAL_REDUCERS,
_INITIAL_REDUCERS,
REDUCER_FACTORY,
_REDUCER_FACTORY,
STORE_FEATURES,
_INITIAL_STATE,
META_REDUCERS,
_STORE_REDUCERS,
FEATURE_REDUCERS,
_FEATURE_REDUCERS,
_FEATURE_REDUCERS_TOKEN,
} from './tokens';
import { ACTIONS_SUBJECT_PROVIDERS, ActionsSubject } from './actions_subject';
import {
Expand Down Expand Up @@ -49,13 +55,19 @@ export class StoreRootModule {
export class StoreFeatureModule implements OnDestroy {
constructor(
@Inject(STORE_FEATURES) private features: StoreFeature<any, any>[],
@Inject(FEATURE_REDUCERS) private featureReducers: ActionReducerMap<any>[],
private reducerManager: ReducerManager
) {
features
.map(feature => {
return typeof feature.initialState === 'function'
? { ...feature, initialState: feature.initialState() }
: feature;
.map((feature, index) => {
const featureReducerCollection = featureReducers.shift();
const reducers = featureReducerCollection[index];

return {
...feature,
reducers,
initialState: _initialStateFactory(feature.initialState),
};
})
.forEach(feature => reducerManager.addFeature(feature));
}
Expand Down Expand Up @@ -94,9 +106,18 @@ export class StoreModule {
useFactory: _initialStateFactory,
deps: [_INITIAL_STATE],
},
{ provide: _INITIAL_REDUCERS, useValue: reducers },
reducers instanceof InjectionToken
? { provide: INITIAL_REDUCERS, useExisting: reducers }
: { provide: INITIAL_REDUCERS, useValue: reducers },
? [{ provide: _STORE_REDUCERS, useExisting: reducers }]
: [],
{
provide: INITIAL_REDUCERS,
deps: [
_INITIAL_REDUCERS,
[new Optional(), new Inject(_STORE_REDUCERS)],
],
useFactory: _createStoreReducers,
},
{
provide: META_REDUCERS,
useValue: config.metaReducers ? config.metaReducers : [],
Expand Down Expand Up @@ -144,19 +165,52 @@ export class StoreModule {
multi: true,
useValue: <StoreFeature<any, any>>{
key: featureName,
reducers: reducers,
reducerFactory: config.reducerFactory
? config.reducerFactory
: combineReducers,
metaReducers: config.metaReducers ? config.metaReducers : [],
initialState: config.initialState,
},
},
{ provide: _FEATURE_REDUCERS, multi: true, useValue: reducers },
{
provide: _FEATURE_REDUCERS_TOKEN,
multi: true,
useExisting:
reducers instanceof InjectionToken ? reducers : _FEATURE_REDUCERS,
},
{
provide: FEATURE_REDUCERS,
multi: true,
deps: [
_FEATURE_REDUCERS,
[new Optional(), new Inject(_FEATURE_REDUCERS_TOKEN)],
],
useFactory: _createFeatureReducers,
},
],
};
}
}

export function _createStoreReducers(
reducers: ActionReducerMap<any, any>,
tokenReducers: ActionReducerMap<any, any>
) {
return reducers instanceof InjectionToken ? tokenReducers : reducers;
}

export function _createFeatureReducers(
reducerCollection: ActionReducerMap<any, any>[],
tokenReducerCollection: ActionReducerMap<any, any>[]
) {
return reducerCollection.map((reducer, index) => {
return reducer instanceof InjectionToken
? tokenReducerCollection[index]
: reducer;
});
}

export function _initialStateFactory(initialState: any): any {
if (typeof initialState === 'function') {
return initialState();
Expand Down
19 changes: 18 additions & 1 deletion modules/store/src/tokens.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { InjectionToken } from '@angular/core';

export const _INITIAL_STATE = new InjectionToken('_ngrx/store Initial State');
export const _INITIAL_STATE = new InjectionToken(
'@ngrx/store Internal Initial State'
);
export const INITIAL_STATE = new InjectionToken('@ngrx/store Initial State');
export const REDUCER_FACTORY = new InjectionToken(
'@ngrx/store Reducer Factory'
Expand All @@ -11,5 +13,20 @@ export const _REDUCER_FACTORY = new InjectionToken(
export const INITIAL_REDUCERS = new InjectionToken(
'@ngrx/store Initial Reducers'
);
export const _INITIAL_REDUCERS = new InjectionToken(
'@ngrx/store Internal Initial Reducers'
);
export const META_REDUCERS = new InjectionToken('@ngrx/store Meta Reducers');
export const STORE_FEATURES = new InjectionToken('@ngrx/store Store Features');
export const _STORE_REDUCERS = new InjectionToken(
'@ngrx/store Internal Store Reducers'
);
export const _FEATURE_REDUCERS = new InjectionToken(
'@ngrx/store Internal Feature Reducers'
);
export const _FEATURE_REDUCERS_TOKEN = new InjectionToken(
'@ngrx/store Internal Feature Reducers Token'
);
export const FEATURE_REDUCERS = new InjectionToken(
'@ngrx/store Feature Reducers'
);
6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@
"test:unit": "node ./tests.js",
"test": "nyc yarn run test:unit",
"clean": "git clean -xdf && yarn && yarn run bootstrap",
"clean:ng-cli-ts": "rimraf \"./node_modules/@angular/cli/node_modules/typescript\"",
"clean:ng-tools-ts": "rimraf \"./node_modules/@ngtools/webpack/node_modules/typescript\"",
"clean:ts": "yarn run clean:ng-cli-ts && yarn run clean:ng-tools-ts",
"cli": "ng",
"coverage:html": "nyc report --reporter=html",
"example:start": "yarn run cli -- serve",
"example:start": "yarn run build && yarn run cli -- serve",
"example:start:aot": "yarn run build && yarn run cli -- serve --aot",
"example:test": "yarn run cli -- test --code-coverage",
"ci": "yarn run build && yarn run test && nyc report --reporter=text-lcov | coveralls",
"prettier": "prettier --parser typescript --single-quote --trailing-comma --write \"./**/*.ts\"",
Expand Down

0 comments on commit 7f77693

Please sign in to comment.