-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Feature: allow same paradigm for lazy loading modules #839
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
test/unit/modules.spec.js
Outdated
mutations: { foo: mutationSpy } | ||
}) | ||
|
||
store.registerModule(['a', 'b'], module()).then(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be store.registerModule(['a', 'b'], module).then(() => {
?
(don't call the module
function here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes good spot, either way it will work
src/store.js
Outdated
return module | ||
} | ||
|
||
if (isPromise(rawModule)) return rawModule.then(moduleResolved) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to check whether rawModule
is a function or not for proposed API rather than Promise
.
src/store.js
Outdated
const moduleResolved = module => { | ||
this._modules.register(path, module.default || module) | ||
installModule(this, this.state, path, this._modules.get(path)) | ||
// reset store to update getters... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be redundant spaces before the comment 🙏
docs/en/api.md
Outdated
@@ -156,10 +156,10 @@ const store = new Vuex.Store({ ...options }) | |||
|
|||
Most commonly used in plugins. [Details](plugins.md) | |||
|
|||
- **`registerModule(path: string | Array<string>, module: Module)`** | |||
- **`registerModule(path: string | Array<string>, module: Module|Function): Module|Function`** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be better to add a space around |
?
src/store.js
Outdated
installModule(this, this.state, path, this._modules.get(path)) | ||
// reset store to update getters... | ||
resetStoreVM(this, this.state) | ||
return module |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to return the module here? I have no idea about use cases 🤔
src/store.js
Outdated
} | ||
|
||
if (isPromise(rawModule)) return rawModule.then(moduleResolved) | ||
return moduleResolved(rawModule) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to always return Promise for consistency?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you return a Promise, it will mean you will need to ensure that Vuex is used with Promises which may require pollyfils. This will ensure users don't need it if they are following standard flow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Vuex requires Promise to work. So we can consider that Promise is always there 🙂
I have a small concern of this API. When some getters/actions/mutations are used before loading the corresponding module, it can be failed. |
@ktsn I will run through the code and check some of points, some points may be right to change need to explore. The main purpose of the API is to keep code splitting of modules simple to use and consistent with other parts of the Vue ecosystem. Perhaps extra documentation for lazy loading is needed to make this feature more informative. I think having a section on Lazy loading dynamic modules would be great. There is some gotchas users should be aware of, using the client None the less we should highlight prerequisites and patterns required for this use, in the right environment this feature will be extremely powerful for applications that are large. |
Furthermore doing the latter of your comment would invoke technical complexity, as this mains if you use an action to get changes is will be deferred. The current API just makes it easier to use code splitting but will require user to correctly manage registering modules. |
@blake-newman |
@blake-newman, thank you for the effort, was thinking about this feature for some time, would help me a lot. |
ff327e2
to
679a32e
Compare
types/index.d.ts
Outdated
@@ -22,6 +22,7 @@ export declare class Store<S> { | |||
|
|||
registerModule<T>(path: string, module: Module<T, S>): void; | |||
registerModule<T>(path: string[], module: Module<T, S>): void; | |||
registerModule<T>(path: string[], module: () => Promise<Module<T, S>>): Promise<Module<T, S>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it returns Promise<void>
docs/en/modules.md
Outdated
@@ -242,7 +242,57 @@ The module's state will be exposed as `store.state.myModule` and `store.state.ne | |||
|
|||
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. | |||
|
|||
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you remove this? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks to be an accident... Will ammend
3ff2951
to
6bb72f7
Compare
6bb72f7
to
cfb3c65
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I like the idea but I'm not sure if this is entirely necessary, because asyncData (store) {
return import('./foo.module.js')
.then(m => store.registerModule('foo', m))
.then(() => store.dispatch('foo/bar'))
} Or async asyncData (store) {
store.registerModule('foo', await import('./foo.module.js'))
await store.dispatch('foo/bar')
} The primary reason for the async component syntax is because components need to be used in declarative scenarios where const store = new Vuex.Store({
modules: {
foo: import('./foo.module.js')
}
}) But this is extremely tricky to get right, since the state access is synchronous. |
@yyx990803 agree. Probably just needs documentation rather than internal changes. IMO in hindsight this doesn't add much value other than syntax sugar that only abstracts implementation detail that is truly not that much more difficult. |
I agree on this is not necessary, but I consider that if it doesn't cause any trouble, it's a nice syntax sugar added. When writing Lazy load in Vue using Webpack's code splitting, I could easily realize it's easy by doing it in the way Evan mentioned. But some people were expecting it to work in the same way than components or router (even some though Aside: does it make sense to lazy load modules on declaration? I think the use case is to load them under a determined condition |
As described in #837
This will keep the same paradigm in Vuex as rest of ecosystem for dynamically loading store modules:
store.registerModule('a', () => import('@/store/modules/a'))