Skip to content

Commit e63abcd

Browse files
feat(overmind): lazy config
1 parent cda8f4f commit e63abcd

File tree

4 files changed

+194
-6
lines changed

4 files changed

+194
-6
lines changed

packages/node_modules/overmind/src/config/config.test.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { merge, namespaced } from './'
1+
import { merge, namespaced, lazy } from './'
2+
import { Overmind } from '../'
23

34
describe('Config', () => {
45
test('should merge configs', () => {
@@ -17,6 +18,7 @@ describe('Config', () => {
1718
expect(merged.state.foo).toEqual('bar')
1819
expect(merged.state.bar).toEqual('baz')
1920
})
21+
2022
test('should namespace', () => {
2123
const configA = {
2224
state: {
@@ -29,10 +31,46 @@ describe('Config', () => {
2931
},
3032
}
3133
const merged = namespaced({ configA, configB })
32-
3334
expect(merged.state.configA.foo).toEqual('bar')
3435
expect(merged.state.configB.bar).toEqual('baz')
3536
})
37+
38+
test('should create lazy config', () => {
39+
const configA = () =>
40+
Promise.resolve({
41+
state: {
42+
foo: 'bar',
43+
},
44+
})
45+
const configB = () =>
46+
Promise.resolve({
47+
state: {
48+
bar: 'baz',
49+
},
50+
})
51+
const merged = merge(
52+
{
53+
actions: {
54+
loadConfigB: ({ lazy }) => {
55+
lazy.loadConfig('configB')
56+
},
57+
},
58+
},
59+
lazy({ configA, configB })
60+
)
61+
const app = new Overmind(merged)
62+
63+
return Promise.all([
64+
app.actions.lazy.loadConfig('configA'),
65+
app.actions.loadConfigB({}),
66+
]).then(() => {
67+
// @ts-ignore
68+
expect(app.state.configA.foo).toEqual('bar')
69+
// @ts-ignore
70+
expect(app.state.configB.bar).toEqual('baz')
71+
})
72+
})
73+
3674
test('should merge normal and namespaced', () => {
3775
const configA = {
3876
state: {

packages/node_modules/overmind/src/config/index.ts

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Configuration } from '../'
1+
import { Configuration, TAction } from '../'
2+
import { SubType } from 'overmind/src/internalTypes'
23

34
/*
45
MERGE
@@ -177,9 +178,9 @@ export function namespaced<T extends NamespacedConfiguration>(
177178
namespaces: T
178179
): {
179180
onInitialize?: any
180-
state: { [P in keyof T]: T[P]['state'] }
181-
effects: { [P in keyof T]: T[P]['effects'] }
182-
actions: { [P in keyof T]: T[P]['actions'] }
181+
state: SubType<{ [P in keyof T]: T[P]['state'] }, object>
182+
effects: SubType<{ [P in keyof T]: T[P]['effects'] }, object>
183+
actions: SubType<{ [P in keyof T]: T[P]['actions'] }, object>
183184
} {
184185
const result: any = {
185186
initializers: [],
@@ -206,3 +207,96 @@ export function namespaced<T extends NamespacedConfiguration>(
206207
: {}
207208
)
208209
}
210+
211+
interface LazyConfiguration {
212+
[namespace: string]: () => Promise<{
213+
onInitialize?: any
214+
state?: {}
215+
effects?: {}
216+
actions?: {}
217+
reactions?: {}
218+
}>
219+
}
220+
221+
type Foo<T, B = T> = { [P in keyof T]: boolean }
222+
223+
export function lazy<T extends LazyConfiguration, B = T>(
224+
configurations: T
225+
): {
226+
onInitialize?: any
227+
state: SubType<
228+
{
229+
[P in keyof T]?: ReturnType<T[P]> extends Promise<infer U>
230+
? U extends { state: any }
231+
? U['state']
232+
: never
233+
: never
234+
},
235+
object
236+
>
237+
effects: SubType<
238+
{
239+
[P in keyof T]?: ReturnType<T[P]> extends Promise<infer U>
240+
? U extends { effects: any }
241+
? U['effects']
242+
: never
243+
: never
244+
},
245+
object
246+
> & {
247+
lazy: {
248+
loadConfig: (config: keyof T) => Promise<void>
249+
}
250+
}
251+
actions: SubType<
252+
{
253+
[P in keyof T]?: ReturnType<T[P]> extends Promise<infer U>
254+
? U extends { actions: any }
255+
? U['actions']
256+
: never
257+
: never
258+
},
259+
object
260+
> & {
261+
lazy: {
262+
loadConfig: TAction<any, keyof T>
263+
}
264+
}
265+
} {
266+
let app
267+
return {
268+
onInitialize({ value }) {
269+
app = value
270+
},
271+
effects: {
272+
lazy: {
273+
loadConfig(config) {
274+
return app.actions.lazy.loadConfig(config)
275+
},
276+
},
277+
},
278+
actions: {
279+
lazy: {
280+
loadConfig({ value: key, state, ...rest }) {
281+
const configToLoad = configurations[key]
282+
configToLoad().then((loadedConfig) => {
283+
const newConfig = namespaced({
284+
[key]: loadedConfig,
285+
})
286+
287+
if (newConfig.state) state[key] = newConfig.state[key]
288+
if (newConfig.effects) app.effects[key] = newConfig.effects[key]
289+
if (newConfig.actions)
290+
app.actions[key] = app.getActions(newConfig.actions[key])
291+
if (newConfig.onInitialize)
292+
newConfig.onInitialize({
293+
value: app,
294+
state,
295+
...rest,
296+
})
297+
})
298+
},
299+
},
300+
},
301+
} as any
302+
}

packages/overmind-website/api/config.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,12 @@ Allows you to namespace configurations by a key.
2020

2121
```marksy
2222
h(Example, { name: "api/config_namespaced" })
23+
```
24+
25+
## lazy (beta)
26+
27+
You can also lazy load configurations. You do this by giving each configuration a key with a function that returns the config when called. To actually load the configurations you can either call an effect or an action with th key of the configuration to load.
28+
29+
```marksy
30+
h(Example, { name: "api/config_lazy" })
2331
```
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
export default (ts) =>
2+
ts
3+
? [
4+
{
5+
fileName: 'app.ts',
6+
code: `
7+
import { Overmind, TConfig } from 'overmind'
8+
import { lazy } from 'overmind/config'
9+
import { Config as ModuleAConfig } from './moduleA'
10+
import { Config as ModuleBConfig } from './moduleB'
11+
12+
const config = lazy({
13+
moduleA: (): Promise<ModuleAConfig> => import('./moduleA'),
14+
moduleB: (): Promise<ModuleBConfig> => import('./moduleB)
15+
})
16+
17+
declare module 'overmind' {
18+
interface IConfig extends TConfig<typeof config> {}
19+
}
20+
21+
const app = new Overmind(config)
22+
23+
app.actions.lazy.loadConfig('moduleA')
24+
25+
export default app
26+
`,
27+
},
28+
]
29+
: [
30+
{
31+
fileName: 'app/index.js',
32+
code: `
33+
import { Overmind } from 'overmind'
34+
import { lazy } from 'overmind/config'
35+
36+
const config = lazy({
37+
moduleA: () => import('./moduleA'),
38+
moduleB: () => import('./moduleB)
39+
})
40+
41+
const app = new Overmind(config)
42+
43+
app.actions.lazy.loadConfig('moduleA')
44+
45+
export default app
46+
`,
47+
},
48+
]

0 commit comments

Comments
 (0)