Skip to content

Commit 679a32e

Browse files
committed
Feature: allow same paradigm for lazy loading modules
1 parent 31772f0 commit 679a32e

File tree

6 files changed

+99
-5
lines changed

6 files changed

+99
-5
lines changed

docs/en/api.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,12 @@ const store = new Vuex.Store({ ...options })
158158
159159
- **`registerModule(path: string | Array<string>, module: Module)`**
160160
161+
**`registerModule(path: string | Array<string>, module: () => Promise<Module>): Promise<Module>`**
162+
161163
Register a dynamic module. [Details](modules.md#dynamic-module-registration)
162164
165+
Lazy load a dynamic module. [Details](modules.md#lazy-load-dynamic-modules)
166+
163167
- **`unregisterModule(path: string | Array<string>)`**
164168
165169
Unregister a dynamic module. [Details](modules.md#dynamic-module-registration)

docs/en/modules.md

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,57 @@ The module's state will be exposed as `store.state.myModule` and `store.state.ne
242242

243243
Dynamic module registration makes it possible for other Vue plugins to also leverage Vuex for state management by attaching a module to the application's store. For example, the [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) library integrates vue-router with vuex by managing the application's route state in a dynamically attached module.
244244

245-
You can also remove a dynamically registered module with `store.unregisterModule(moduleName)`. Note you cannot remove static modules (declared at store creation) with this method.
245+
### Lazy Load Dynamic Modules
246+
247+
You can code split you Vuex store and dynamically register store modules.
248+
249+
``` js
250+
const myModule = () => import('path/to/module')
251+
252+
store.registerModule('myModule', myModule)
253+
```
254+
255+
This is simple enough, however you will need to ensure that modules are registered before you can use them. Attempting to use a module before it is registered will not work and will cause errors.
256+
257+
For example, with vue-router, you can ensure that routing does not resolve until the required modules have been loaded. You can find further [implementation details here](https://ssr.vuejs.org/en/data.html) under the **Client Data Fetching** section. Using this pattern will ensure that we can register modules before use within components.
258+
259+
Overall this pattern will require more awareness and management of the store module registration, however if well managed it can be a very poweful feature and significantly reduce the initial bundle size of your application.
260+
261+
``` js
262+
import { mapGetters } from 'vuex'
263+
264+
const myModule = () => import('path/to/module')
265+
266+
export default {
267+
asyncData(store) {
268+
return store.registerModule('myModule', myModule)
269+
.then(() => store.dispatch('myModule/getData'))
270+
},
271+
272+
computed: {
273+
...mapGetters('myModule', ['a'])
274+
}
275+
}
276+
```
277+
278+
Using async and await this becomes less verbose for the registering of a module:
279+
280+
``` js
281+
import { mapGetters } from 'vuex'
282+
283+
const myModule = () => import('path/to/module')
284+
285+
export default {
286+
async asyncData(store) {
287+
await store.registerModule('myModule', myModule)
288+
await store.dispatch('myModule/getData')
289+
},
290+
291+
computed: {
292+
...mapGetters('myModule', ['a'])
293+
}
294+
}
295+
```
246296

247297
### Module Reuse
248298

src/store.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,15 @@ export class Store {
158158
assert(path.length > 0, 'cannot register the root module by using registerModule.')
159159
}
160160

161-
this._modules.register(path, rawModule)
162-
installModule(this, this.state, path, this._modules.get(path))
163-
// reset store to update getters...
164-
resetStoreVM(this, this.state)
161+
const moduleResolved = module => {
162+
this._modules.register(path, module.default || module)
163+
installModule(this, this.state, path, this._modules.get(path))
164+
// reset store to update getters...
165+
resetStoreVM(this, this.state)
166+
}
167+
168+
if (typeof rawModule === 'function') return rawModule().then(moduleResolved)
169+
moduleResolved(rawModule)
165170
}
166171

167172
unregisterModule (path) {

test/unit/modules.spec.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,36 @@ describe('Modules', () => {
8282
})
8383
})
8484

85+
it('dynamic module registration with promise (dynamic import)', () => {
86+
const store = new Vuex.Store({
87+
modules: {
88+
a: {
89+
namespaced: true
90+
}
91+
}
92+
})
93+
const actionSpy = jasmine.createSpy()
94+
const mutationSpy = jasmine.createSpy()
95+
const module = () => Promise.resolve({
96+
state: { value: 1 },
97+
getters: { foo: state => state.value },
98+
actions: { foo: actionSpy },
99+
mutations: { foo: mutationSpy }
100+
})
101+
102+
store.registerModule(['a', 'b'], module)
103+
.then(() => {
104+
expect(store.state.a.b.value).toBe(1)
105+
expect(store.getters['a/foo']).toBe(1)
106+
107+
store.dispatch('a/foo')
108+
expect(actionSpy).toHaveBeenCalled()
109+
110+
store.commit('a/foo')
111+
expect(mutationSpy).toHaveBeenCalled()
112+
})
113+
})
114+
85115
// #524
86116
it('should not fire an unrelated watcher', done => {
87117
const spy = jasmine.createSpy()

types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export declare class Store<S> {
2222

2323
registerModule<T>(path: string, module: Module<T, S>): void;
2424
registerModule<T>(path: string[], module: Module<T, S>): void;
25+
registerModule<T>(path: string[], module: () => Promise<Module<T, S>>): Promise<Module<T, S>>;
2526

2627
unregisterModule(path: string): void;
2728
unregisterModule(path: string[]): void;

types/test/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ namespace RegisterModule {
199199
state: { value: 2 }
200200
});
201201

202+
store.registerModule("a", () => Promise.resolve({
203+
state: { value: 1 }
204+
}));
205+
202206
store.unregisterModule(["a", "b"]);
203207
store.unregisterModule("a");
204208
}

0 commit comments

Comments
 (0)