Skip to content

Commit cfeb2b1

Browse files
committed
Huge refactor of the project.
We have dropped `withAsyncComponents` and replaced it with `asyncBootstrapper` that is sourced from the generalised `react-async-bootstrapper` library. This gives us a greater degree of flexibility and interoperability with other libraries that have asynchronous bootstrapping needs. You are now required to manually wrap your application with an instance of the `AsyncComponentProvider`. The `Loading` component option for `createAsyncComponent` has been renamed to `LoadingComponent`. An `ErrorComponent` component option has been added to the `createAsyncComponent` helper, allowing you to render a custom error should a component resolver fail.
1 parent d864c00 commit cfeb2b1

11 files changed

+393
-155
lines changed

.eslintrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@
1313
"defaultParams": true
1414
},
1515
"rules": {
16+
"no-confusing-arrow": 0,
17+
18+
"max-len": [
19+
"error",
20+
{
21+
"ignoreComments": false,
22+
"ignoreStrings": true,
23+
"code": 80
24+
}
25+
],
26+
1627
// Going hipster
1728
"semi": [2, "never"],
1829

package.json

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@
3535
"test:coverage": "yarn run test -- --coverage",
3636
"test:coverage:deploy": "yarn run test:coverage && codecov"
3737
},
38+
"jest": {
39+
"collectCoverageFrom": [
40+
"src/**/*.{js,jsx}"
41+
],
42+
"snapshotSerializers": [
43+
"<rootDir>/node_modules/enzyme-to-json/serializer"
44+
],
45+
"testPathIgnorePatterns": [
46+
"<rootDir>/(commonjs|coverage|flow-typed|node_modules|tools|umd)/"
47+
]
48+
},
3849
"lint-staged": {
3950
"*.js": [
4051
"prettier-eslint --write",
@@ -46,7 +57,7 @@
4657
"react-dom": "^0.14.0 || ^15.0.0-0"
4758
},
4859
"dependencies": {
49-
"react-tree-walker": "2.0.0-alpha.1"
60+
"react-async-bootstrapper": "^0.0.2"
5061
},
5162
"devDependencies": {
5263
"app-root-dir": "1.0.2",
@@ -61,8 +72,8 @@
6172
"babel-preset-react": "6.23.0",
6273
"babel-preset-stage-3": "6.22.0",
6374
"babel-register": "6.24.0",
64-
"codecov": "1.0.1",
65-
"cross-env": "3.2.3",
75+
"codecov": "2.0.1",
76+
"cross-env": "3.2.4",
6677
"enzyme": "2.7.1",
6778
"enzyme-to-json": "1.5.0",
6879
"eslint": "3.17.1",
@@ -76,7 +87,7 @@
7687
"jest": "19.0.2",
7788
"lint-staged": "3.4.0",
7889
"prettier": "0.22.0",
79-
"prettier-eslint": "4.2.1",
90+
"prettier-eslint": "4.3.2",
8091
"prettier-eslint-cli": "^3.1.2",
8192
"pretty-bytes": "4.0.2",
8293
"ramda": "0.23.0",
@@ -85,20 +96,9 @@
8596
"react-dom": "15.4.2",
8697
"readline-sync": "1.4.6",
8798
"rimraf": "2.6.1",
88-
"sinon": "1.17.7",
99+
"sinon": "2.0.0",
89100
"webpack": "2.2.1",
90101
"webpack-dev-middleware": "1.10.1",
91102
"webpack-hot-middleware": "2.17.1"
92-
},
93-
"jest": {
94-
"collectCoverageFrom": [
95-
"src/**/*.{js,jsx}"
96-
],
97-
"snapshotSerializers": [
98-
"<rootDir>/node_modules/enzyme-to-json/serializer"
99-
],
100-
"testPathIgnorePatterns": [
101-
"<rootDir>/(commonjs|coverage|flow-typed|node_modules|tools|umd)/"
102-
]
103103
}
104104
}

src/AsyncComponentProvider.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ class AsyncComponentProvider extends React.Component {
1313
return {
1414
asyncComponents: {
1515
getNextId: this.execContext.getNextId,
16-
getComponent: this.execContext.getComponent,
1716
registerComponent: this.execContext.registerComponent,
17+
getComponent: this.execContext.getComponent,
18+
registerError: this.execContext.registerError,
19+
getError: this.execContext.getError,
1820
},
1921
}
2022
}
@@ -28,8 +30,10 @@ AsyncComponentProvider.propTypes = {
2830
children: React.PropTypes.node.isRequired,
2931
execContext: React.PropTypes.shape({
3032
getNextId: React.PropTypes.func.isRequired,
31-
getComponent: React.PropTypes.func.isRequired,
3233
registerComponent: React.PropTypes.func.isRequired,
34+
getComponent: React.PropTypes.func.isRequired,
35+
registerError: React.PropTypes.func.isRequired,
36+
getError: React.PropTypes.func.isRequired,
3337
}),
3438
}
3539

@@ -40,8 +44,10 @@ AsyncComponentProvider.defaultProps = {
4044
AsyncComponentProvider.childContextTypes = {
4145
asyncComponents: React.PropTypes.shape({
4246
getNextId: React.PropTypes.func.isRequired,
43-
getComponent: React.PropTypes.func.isRequired,
4447
registerComponent: React.PropTypes.func.isRequired,
48+
getComponent: React.PropTypes.func.isRequired,
49+
registerError: React.PropTypes.func.isRequired,
50+
getError: React.PropTypes.func.isRequired,
4551
}).isRequired,
4652
}
4753

src/__tests__/__snapshots__/integration.test.js.snap

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`integration tests render server and client 1`] = `"<div><div><div><span>In Render.</span></div><div><span>In Boundary but outside an AsyncComponent, server render me!</span></div></div></div>"`;
3+
exports[`integration tests render server and client 1`] = `"<div><div><div><span>In Render.</span></div><div>DeferredAsyncBob Loading</div><div><span>In Boundary but outside an AsyncComponent, server render me!</span></div><div>This always errors</div></div></div>"`;
44

55
exports[`integration tests render server and client 2`] = `
66
Object {
7+
"errors": Object {
8+
"6": "This always errors",
9+
},
710
"resolved": Object {
811
"1": true,
912
"2": true,
@@ -17,9 +20,11 @@ exports[`integration tests render server and client 3`] = `
1720
execContext={
1821
Object {
1922
"getComponent": [Function],
23+
"getError": [Function],
2024
"getNextId": [Function],
2125
"getState": [Function],
2226
"registerComponent": [Function],
27+
"registerError": [Function],
2328
}
2429
}
2530
>
@@ -36,7 +41,13 @@ exports[`integration tests render server and client 3`] = `
3641
</div>
3742
</Bob>
3843
</AsyncBobTwo>
39-
<DeferredAsyncBob />
44+
<DeferredAsyncBob>
45+
<LoadingComponent>
46+
<div>
47+
DeferredAsyncBob Loading
48+
</div>
49+
</LoadingComponent>
50+
</DeferredAsyncBob>
4051
<BoundaryAsyncBob>
4152
<Bob>
4253
<div>
@@ -47,6 +58,15 @@ exports[`integration tests render server and client 3`] = `
4758
</div>
4859
</Bob>
4960
</BoundaryAsyncBob>
61+
<ErrorAsyncComponent>
62+
<ErrorComponent
63+
message="This always errors"
64+
>
65+
<div>
66+
This always errors
67+
</div>
68+
</ErrorComponent>
69+
</ErrorAsyncComponent>
5070
</div>
5171
</div>
5272
</Bob>
@@ -59,9 +79,11 @@ exports[`integration tests render server and client 4`] = `
5979
execContext={
6080
Object {
6181
"getComponent": [Function],
82+
"getError": [Function],
6283
"getNextId": [Function],
6384
"getState": [Function],
6485
"registerComponent": [Function],
86+
"registerError": [Function],
6587
}
6688
}
6789
>
@@ -105,9 +127,66 @@ exports[`integration tests render server and client 4`] = `
105127
</div>
106128
</Bob>
107129
</BoundaryAsyncBob>
130+
<ErrorAsyncComponent>
131+
<ErrorComponent
132+
message="This always errors"
133+
>
134+
<div>
135+
This always errors
136+
</div>
137+
</ErrorComponent>
138+
</ErrorAsyncComponent>
108139
</div>
109140
</div>
110141
</Bob>
111142
</AsyncBob>
112143
</AsyncComponentProvider>
113144
`;
145+
146+
exports[`integration tests renders the ErrorComponent 1`] = `
147+
<AsyncComponentProvider
148+
execContext={
149+
Object {
150+
"getComponent": [Function],
151+
"getError": [Function],
152+
"getNextId": [Function],
153+
"getState": [Function],
154+
"registerComponent": [Function],
155+
"registerError": [Function],
156+
}
157+
}
158+
>
159+
<AsyncComponent>
160+
<ErrorComponent
161+
message="An error occurred"
162+
>
163+
<div>
164+
An error occurred
165+
</div>
166+
</ErrorComponent>
167+
</AsyncComponent>
168+
</AsyncComponentProvider>
169+
`;
170+
171+
exports[`integration tests renders the LoadingComponent 1`] = `
172+
<AsyncComponentProvider
173+
execContext={
174+
Object {
175+
"getComponent": [Function],
176+
"getError": [Function],
177+
"getNextId": [Function],
178+
"getState": [Function],
179+
"registerComponent": [Function],
180+
"registerError": [Function],
181+
}
182+
}
183+
>
184+
<AsyncComponent>
185+
<LoadingComponent>
186+
<div>
187+
Loading...
188+
</div>
189+
</LoadingComponent>
190+
</AsyncComponent>
191+
</AsyncComponentProvider>
192+
`;

src/__tests__/createAsyncComponent.test.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,26 @@ describe('createAsyncComponent', () => {
88
const contextStub = {
99
asyncComponents: {
1010
getNextId: () => 1,
11-
getComponent: () => undefined,
1211
registerComponent: () => undefined,
12+
getComponent: () => undefined,
13+
registerError: () => undefined,
14+
getError: () => undefined,
1315
},
1416
}
1517

1618
it('should handle unmounting ensuring that resolved promises do not call setState', () => {
1719
const resolveDelay = 10
1820
const Bob = createAsyncComponent({
19-
resolve: () => new Promise(resolve =>
20-
setTimeout(
21-
() => resolve(() => <div>bob</div>),
22-
resolveDelay,
23-
),
24-
),
21+
resolve: () =>
22+
new Promise(resolve =>
23+
setTimeout(() => resolve(() => <div>bob</div>), resolveDelay)),
2524
})
2625
const setStateSpy = sinon.spy(Bob.prototype, 'setState')
2726
const renderWrapper = mount(<Bob />, { context: contextStub })
2827
expect(setStateSpy.callCount).toEqual(0)
2928
renderWrapper.unmount()
30-
return new Promise(resolve => setTimeout(resolve, resolveDelay + 2))
31-
.then(() => expect(setStateSpy.callCount).toEqual(0))
29+
return new Promise(resolve =>
30+
setTimeout(resolve, resolveDelay + 2)).then(() =>
31+
expect(setStateSpy.callCount).toEqual(0))
3232
})
3333
})

0 commit comments

Comments
 (0)