Skip to content

Commit f84da30

Browse files
ktsnyyx990803
authored andcommitted
Implement module namespace option (#420)
* refactoring: adding module tree model * add namespace if module namepsace option is specified * hot reload namespace * localize getters, dispatch and commit if module is namespaced * add error message for unknown local action/mutation * namespace option only accepts string value * add more test for local getters, dispatch and commit * update docs for namespace options * add a caveat for plugin developers * add more tests * add typings for module namespace feature * use normal object for local getters to compat with root getters * remove unused this._options * use root dispatch and commit if there is no namespace
1 parent 9420e2b commit f84da30

File tree

11 files changed

+846
-126
lines changed

11 files changed

+846
-126
lines changed

docs/en/modules.md

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -81,42 +81,93 @@ const moduleA = {
8181

8282
### Namespacing
8383

84-
Note that actions, mutations and getters inside modules are still registered under the **global namespace** - this allows multiple modules to react to the same mutation/action type. You can namespace the module assets yourself to avoid name clashing by prefixing or suffixing their names. And you probably should if you are writing a reusable Vuex module that will be used in unknown environments. For example, we want to create a `todos` module:
84+
Note that actions, mutations and getters inside modules are still registered under the **global namespace** - this allows multiple modules to react to the same mutation/action type. You probably should namespace your Vuex module if you are writing a reusable one that will be used in unknown environments. To support namespacing for avoiding name clashing, Vuex provides `namespace` option. If you specify string value to `namespace` option, module assets types are prefixed by the given value:
8585

8686
``` js
87-
// types.js
87+
export default {
88+
namespace: 'account/',
8889

89-
// define names of getters, actions and mutations as constants
90-
// and they are prefixed by the module name `todos`
91-
export const DONE_COUNT = 'todos/DONE_COUNT'
92-
export const FETCH_ALL = 'todos/FETCH_ALL'
93-
export const TOGGLE_DONE = 'todos/TOGGLE_DONE'
90+
// module assets
91+
state: { ... }, // module state will not be changed by prefix option
92+
getters: {
93+
isAdmin () { ... } // -> getters['account/isAdmin']
94+
},
95+
actions: {
96+
login () { ... } // -> dispatch('account/login')
97+
},
98+
mutations: {
99+
login () { ... } // -> commit('account/login')
100+
},
101+
102+
// nested modules
103+
modules: {
104+
// inherit the namespace from parent module
105+
myPage: {
106+
state: { ... },
107+
getters: {
108+
profile () { ... } // -> getters['account/profile']
109+
}
110+
},
111+
112+
// nest the namespace
113+
posts: {
114+
namespace: 'posts/',
115+
116+
state: { ... },
117+
getters: {
118+
popular () { ... } // -> getters['account/posts/popular']
119+
}
120+
}
121+
}
122+
}
94123
```
95124

96-
``` js
97-
// modules/todos.js
98-
import * as types from '../types'
125+
Namespaced getters and actions will receive localized `getters`, `dispatch` and `commit`. In other words, you can use the module assets without writing prefix in the same module. If you want to use the global ones, `rootGetters` is passed to the 4th argument of getter functions and the property of the action context. In addition, `dispatch` and `commit` receives `root` option on their last argument.
99126

100-
// define getters, actions and mutations using prefixed names
101-
const todosModule = {
102-
state: { todos: [] },
127+
``` js
128+
export default {
129+
namespace: 'prefix/',
103130

104131
getters: {
105-
[types.DONE_COUNT] (state) {
106-
// ...
107-
}
132+
// `getters` is localized to this module's getters
133+
// you can use rootGetters via 4th argument of getters
134+
someGetter (state, getters, rootState, rootGetters) {
135+
getters.someOtherGetter // -> 'prefix/someOtherGetter'
136+
rootGetters.someOtherGetter // -> 'someOtherGetter'
137+
},
138+
someOtherGetter: state => { ... }
108139
},
109140

110141
actions: {
111-
[types.FETCH_ALL] (context, payload) {
112-
// ...
113-
}
114-
},
142+
// dispatch and commit are also localized for this module
143+
// they will accept `root` option for the root dispatch/commit
144+
someAction ({ dispatch, commit, getters, rootGetters }) {
145+
getters.someGetter // -> 'prefix/someGetter'
146+
rootGetters.someGetter // -> 'someGetter'
147+
148+
dispatch('someOtherAction') // -> 'prefix/someOtherAction'
149+
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
150+
151+
commit('someMutation') // -> 'prefix/someMutation'
152+
commit('someMutation', null, { root: true }) // -> 'someMutation'
153+
},
154+
someOtherAction (ctx, payload) { ... }
155+
}
156+
}
157+
```
115158

116-
mutations: {
117-
[types.TOGGLE_DONE] (state, payload) {
118-
// ...
119-
}
159+
#### Caveat for Plugin Developers
160+
161+
You may care about unpredictable namespacing for your modules when you create a [plugin](plugins.md) that provides the modules and let users add them to a Vuex store. Your modules will be also namespaced if the plugin users add your modules under a namespaced module. To adapt this situation, you may need to receive a namespace value via your plugin option:
162+
163+
``` js
164+
// get namespace value via plugin option
165+
// and returns Vuex plugin function
166+
export function createPlugin (options = {}) {
167+
return function (store) {
168+
// add namespace to plugin module's types
169+
const namespace = options.namespace || ''
170+
store.dispatch(namespace + 'pluginAction')
120171
}
121172
}
122173
```

0 commit comments

Comments
 (0)