Skip to content

Commit 7f77693

Browse files
brandonrobertsMikeRyanDev
authored andcommitted
feat(Store): Add injection token option for feature modules (ngrx#153)
Fixes AOT issues when providing reducers via an InjectionToken Closes ngrx#116, ngrx#141, ngrx#147
1 parent be02eb9 commit 7f77693

File tree

9 files changed

+115
-18
lines changed

9 files changed

+115
-18
lines changed

.angular-cli.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"apps": [
77
{
88
"root": "example-app",
9-
"outDir": "dist",
9+
"outDir": "example-dist",
1010
"assets": [
1111
"assets",
1212
"favicon.ico"

circle.yml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dependencies:
1616
test:
1717
override:
1818
- yarn run ci
19+
- yarn run example:test -- --watch=false
1920

2021
deployment:
2122
builds:

example-app/tsconfig.app.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
"baseUrl": ".",
1717
"rootDir": "../",
1818
"paths": {
19-
"@ngrx/effects": ["../modules/effects"],
20-
"@ngrx/store": ["../modules/store"],
21-
"@ngrx/router-store": ["../modules/router-store"],
22-
"@ngrx/store-devtools": ["../modules/store-devtools"]
19+
"@ngrx/effects": ["../dist/effects"],
20+
"@ngrx/store": ["../dist/store"],
21+
"@ngrx/router-store": ["../dist/router-store"],
22+
"@ngrx/store-devtools": ["../dist/store-devtools"]
2323
}
2424
},
2525
"exclude": [

modules/effects/spec/effects_metadata.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('Effect Metadata', () => {
5858

5959
describe('getSourceProto', () => {
6060
it('should get the prototype for an instance of a source', () => {
61-
class Fixture { }
61+
class Fixture {}
6262
const instance = new Fixture();
6363

6464
const proto = getSourceForInstance(instance);

modules/store/spec/modules.spec.ts

+20
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ describe(`Store Modules`, () => {
2222
'Root Reducers'
2323
);
2424

25+
const featureToken = new InjectionToken<ActionReducerMap<RootState>>(
26+
'Feature Reducers'
27+
);
28+
2529
// Trigger here is basically an action type used to trigger state update
2630
const createDummyReducer = <T>(def: T, trigger: string): ActionReducer<T> => (
2731
s = def,
@@ -126,11 +130,23 @@ describe(`Store Modules`, () => {
126130
})
127131
class FeatureBModule {}
128132

133+
@NgModule({
134+
imports: [StoreModule.forFeature('c', featureToken)],
135+
providers: [
136+
{
137+
provide: featureToken,
138+
useValue: featureBReducerMap,
139+
},
140+
],
141+
})
142+
class FeatureCModule {}
143+
129144
@NgModule({
130145
imports: [
131146
StoreModule.forRoot<RootState>(reducersToken),
132147
FeatureAModule,
133148
FeatureBModule,
149+
FeatureCModule,
134150
],
135151
providers: [
136152
{
@@ -158,6 +174,10 @@ describe(`Store Modules`, () => {
158174
list: [1, 2, 3],
159175
index: 2,
160176
},
177+
c: {
178+
list: [1, 2, 3],
179+
index: 2,
180+
},
161181
});
162182
});
163183
});

modules/store/src/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,20 @@ export {
2626
INITIAL_STATE,
2727
_REDUCER_FACTORY,
2828
REDUCER_FACTORY,
29+
_INITIAL_REDUCERS,
2930
INITIAL_REDUCERS,
3031
STORE_FEATURES,
3132
_INITIAL_STATE,
3233
META_REDUCERS,
34+
_STORE_REDUCERS,
35+
_FEATURE_REDUCERS,
36+
FEATURE_REDUCERS,
37+
_FEATURE_REDUCERS_TOKEN,
3338
} from './tokens';
3439
export {
3540
StoreRootModule,
3641
StoreFeatureModule,
3742
_initialStateFactory,
43+
_createStoreReducers,
44+
_createFeatureReducers,
3845
} from './store_module';

modules/store/src/store_module.ts

+61-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ModuleWithProviders,
55
OnDestroy,
66
InjectionToken,
7+
Optional,
78
} from '@angular/core';
89
import {
910
Action,
@@ -17,11 +18,16 @@ import { compose, combineReducers, createReducerFactory } from './utils';
1718
import {
1819
INITIAL_STATE,
1920
INITIAL_REDUCERS,
21+
_INITIAL_REDUCERS,
2022
REDUCER_FACTORY,
2123
_REDUCER_FACTORY,
2224
STORE_FEATURES,
2325
_INITIAL_STATE,
2426
META_REDUCERS,
27+
_STORE_REDUCERS,
28+
FEATURE_REDUCERS,
29+
_FEATURE_REDUCERS,
30+
_FEATURE_REDUCERS_TOKEN,
2531
} from './tokens';
2632
import { ACTIONS_SUBJECT_PROVIDERS, ActionsSubject } from './actions_subject';
2733
import {
@@ -49,13 +55,19 @@ export class StoreRootModule {
4955
export class StoreFeatureModule implements OnDestroy {
5056
constructor(
5157
@Inject(STORE_FEATURES) private features: StoreFeature<any, any>[],
58+
@Inject(FEATURE_REDUCERS) private featureReducers: ActionReducerMap<any>[],
5259
private reducerManager: ReducerManager
5360
) {
5461
features
55-
.map(feature => {
56-
return typeof feature.initialState === 'function'
57-
? { ...feature, initialState: feature.initialState() }
58-
: feature;
62+
.map((feature, index) => {
63+
const featureReducerCollection = featureReducers.shift();
64+
const reducers = featureReducerCollection[index];
65+
66+
return {
67+
...feature,
68+
reducers,
69+
initialState: _initialStateFactory(feature.initialState),
70+
};
5971
})
6072
.forEach(feature => reducerManager.addFeature(feature));
6173
}
@@ -94,9 +106,18 @@ export class StoreModule {
94106
useFactory: _initialStateFactory,
95107
deps: [_INITIAL_STATE],
96108
},
109+
{ provide: _INITIAL_REDUCERS, useValue: reducers },
97110
reducers instanceof InjectionToken
98-
? { provide: INITIAL_REDUCERS, useExisting: reducers }
99-
: { provide: INITIAL_REDUCERS, useValue: reducers },
111+
? [{ provide: _STORE_REDUCERS, useExisting: reducers }]
112+
: [],
113+
{
114+
provide: INITIAL_REDUCERS,
115+
deps: [
116+
_INITIAL_REDUCERS,
117+
[new Optional(), new Inject(_STORE_REDUCERS)],
118+
],
119+
useFactory: _createStoreReducers,
120+
},
100121
{
101122
provide: META_REDUCERS,
102123
useValue: config.metaReducers ? config.metaReducers : [],
@@ -144,19 +165,52 @@ export class StoreModule {
144165
multi: true,
145166
useValue: <StoreFeature<any, any>>{
146167
key: featureName,
147-
reducers: reducers,
148168
reducerFactory: config.reducerFactory
149169
? config.reducerFactory
150170
: combineReducers,
151171
metaReducers: config.metaReducers ? config.metaReducers : [],
152172
initialState: config.initialState,
153173
},
154174
},
175+
{ provide: _FEATURE_REDUCERS, multi: true, useValue: reducers },
176+
{
177+
provide: _FEATURE_REDUCERS_TOKEN,
178+
multi: true,
179+
useExisting:
180+
reducers instanceof InjectionToken ? reducers : _FEATURE_REDUCERS,
181+
},
182+
{
183+
provide: FEATURE_REDUCERS,
184+
multi: true,
185+
deps: [
186+
_FEATURE_REDUCERS,
187+
[new Optional(), new Inject(_FEATURE_REDUCERS_TOKEN)],
188+
],
189+
useFactory: _createFeatureReducers,
190+
},
155191
],
156192
};
157193
}
158194
}
159195

196+
export function _createStoreReducers(
197+
reducers: ActionReducerMap<any, any>,
198+
tokenReducers: ActionReducerMap<any, any>
199+
) {
200+
return reducers instanceof InjectionToken ? tokenReducers : reducers;
201+
}
202+
203+
export function _createFeatureReducers(
204+
reducerCollection: ActionReducerMap<any, any>[],
205+
tokenReducerCollection: ActionReducerMap<any, any>[]
206+
) {
207+
return reducerCollection.map((reducer, index) => {
208+
return reducer instanceof InjectionToken
209+
? tokenReducerCollection[index]
210+
: reducer;
211+
});
212+
}
213+
160214
export function _initialStateFactory(initialState: any): any {
161215
if (typeof initialState === 'function') {
162216
return initialState();

modules/store/src/tokens.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { InjectionToken } from '@angular/core';
22

3-
export const _INITIAL_STATE = new InjectionToken('_ngrx/store Initial State');
3+
export const _INITIAL_STATE = new InjectionToken(
4+
'@ngrx/store Internal Initial State'
5+
);
46
export const INITIAL_STATE = new InjectionToken('@ngrx/store Initial State');
57
export const REDUCER_FACTORY = new InjectionToken(
68
'@ngrx/store Reducer Factory'
@@ -11,5 +13,20 @@ export const _REDUCER_FACTORY = new InjectionToken(
1113
export const INITIAL_REDUCERS = new InjectionToken(
1214
'@ngrx/store Initial Reducers'
1315
);
16+
export const _INITIAL_REDUCERS = new InjectionToken(
17+
'@ngrx/store Internal Initial Reducers'
18+
);
1419
export const META_REDUCERS = new InjectionToken('@ngrx/store Meta Reducers');
1520
export const STORE_FEATURES = new InjectionToken('@ngrx/store Store Features');
21+
export const _STORE_REDUCERS = new InjectionToken(
22+
'@ngrx/store Internal Store Reducers'
23+
);
24+
export const _FEATURE_REDUCERS = new InjectionToken(
25+
'@ngrx/store Internal Feature Reducers'
26+
);
27+
export const _FEATURE_REDUCERS_TOKEN = new InjectionToken(
28+
'@ngrx/store Internal Feature Reducers Token'
29+
);
30+
export const FEATURE_REDUCERS = new InjectionToken(
31+
'@ngrx/store Feature Reducers'
32+
);

package.json

+2-4
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010
"test:unit": "node ./tests.js",
1111
"test": "nyc yarn run test:unit",
1212
"clean": "git clean -xdf && yarn && yarn run bootstrap",
13-
"clean:ng-cli-ts": "rimraf \"./node_modules/@angular/cli/node_modules/typescript\"",
14-
"clean:ng-tools-ts": "rimraf \"./node_modules/@ngtools/webpack/node_modules/typescript\"",
15-
"clean:ts": "yarn run clean:ng-cli-ts && yarn run clean:ng-tools-ts",
1613
"cli": "ng",
1714
"coverage:html": "nyc report --reporter=html",
18-
"example:start": "yarn run cli -- serve",
15+
"example:start": "yarn run build && yarn run cli -- serve",
16+
"example:start:aot": "yarn run build && yarn run cli -- serve --aot",
1917
"example:test": "yarn run cli -- test --code-coverage",
2018
"ci": "yarn run build && yarn run test && nyc report --reporter=text-lcov | coveralls",
2119
"prettier": "prettier --parser typescript --single-quote --trailing-comma --write \"./**/*.ts\"",

0 commit comments

Comments
 (0)