/
create_store.js
162 lines (151 loc) · 5.31 KB
/
create_store.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/**
* 创建store
*
* - 返回store实例
* - 为store添加辅助方法
* - 在config.store中进行配置,参考https://vuex.vuejs.org/zh/api/#vuex-store-%E6%9E%84%E9%80%A0%E5%99%A8%E9%80%89%E9%A1%B9
* - hook store.alter
*
* @module core/create_store
*/
import _ from 'lodash';
import Vue from 'vue';
import Vuex from 'vuex';
import plugin from './plugin';
import loadConfig from './load_config';
const config = loadConfig();
Vue.use(Vuex);
/**
* 返回store实例,并给实例添加register
* @param {[type]} context [description]
* @return {[type]} [description]
*/
export default context => {
let store = new Vuex.Store(_.get(config, 'store', {}));
/**
* 给store动态添加模块,保证不会在命名空间上重复添加。
* @param {String|Array} namespace 命名空间
* @param {String} modulepath 模块路径,相对于~/store/modules这个路径,如果忽略这个属
* 性,则以namespace作为模块路径。
* @return {Boolean} 返回是否添加成功。
*/
store.register = function(namespace, modulepath, ...args){
namespace = getNamespace(namespace);
// 不能重复注册
if(this.isRegistered(namespace)) return false;
if(!modulepath) modulepath = namespace;
// 模块的引用统一成下划线命名模式,snakeCase
let {filename, pluginName} = plugin.parseModulePath(modulepath);
filename = filename.split('/').map(i => _.snakeCase(i)).join('/');
try{
let mod = plugin.getModule('store/modules/' + filename, pluginName);
mod(namespace, {...context, store}, ...args)
this.registerModule(namespace, mod(namespace, {...context, store}, ...args));
return true;
}catch(e){
e.name = e.name + `(store ${namespace}注册出错,filename:${filename}, pluginName:${pluginName})`
throw e;
}
}
/**
* 从store中卸载模块。
* @param {String|Array} namespace 命名空间名称
* @return {Boolean} 是否卸载成功。
*/
store.unregister = function(namespace){
namespace = getNamespace(namespace);
try{
this.unregisterModule(namespace);
delete this.cache[namespace];
return true;
}catch(e){
return false;
}
}
/**
* 该命名空间下是否注册过模块
* @param {String|Array} namespace 命名空间
* @return {Boolean} 该命名空间下是否注册过模块
*/
store.isRegistered = function(namespace){
namespace = getNamespace(namespace);
// 命名空间是以'/'结尾进行保存的。
return !!this._modulesNamespaceMap[namespace + '/'];
}
/**
* 检测该命名空间的这个方法只执行一遍,已执行过则不会再执行。
* @param {String} type 执行类型, dispatch|commit
* @param {String} namespace 命名空间
* @param {String} name 执行的名称
* @param {Array} args 参数
* @return {Mixed} dispath/commit函数返回值。如果已执行,则返回undefined.
* @todo 完善和应用。
*/
store.cache = {};
store.once = function(type, namespace, name, ...args){
if(type != 'dispatch' && type != 'commit'){
throw new Error(`store.once arguments type not support ${type}.`);
}
namespace = getNamespace(namespace);
let key = `${type}:${name}`,
cacheKey = `${type}:${name}:cache`,
cache = this.cache[namespace];
if(!cache){
cache = this.cache[namespace] = {}
}
if(this.ensure(type, namespace, name)) return cache[cacheKey];
cache[key] = true;
cache[cacheKey] = this[type](namespace + '/' + name, ...args);
return cache[cacheKey];
}
/**
* 检测该命名空间的的这个方法有没有执行过。
* @param {[type]} type [description]
* @param {[type]} namespace [description]
* @param {[type]} name [description]
* @return {[type]} [description]
*/
store.ensure = function(type, namespace, name){
namespace = getNamespace(namespace);
return !!this.cache[namespace][`${type}:${name}`];
}
/**
* 检测是否拥有这个方法
* @param {String} type dispatch or commit
* @param {String} namespace 命名空间。
* @param {String} name 方法名
* @return {Boolean}
*/
store.has = function(type, namespace, name){
if(_.isArray(namespace)) namespace = namespace.join('/');
if(namespace) name = namespace + '/' + name;
name = type == 'dispatch' ? `_actions.${name}` : `_mutations.${name}`;
return _.has(this, name);
}
/**
* 模块有方法就运行,没有就不了。
* @param {[type]} type dispatch or commit
* @param {[type]} namespace [description]
* @param {[type]} name [description]
* @return {[type]} [description]
*/
store.try = function(type, namespace, name, ...args){
namespace = getNamespace(namespace);
if(this.has(type, namespace, name)){
return this[type](namespace + '/' + name, ...args);
}
}
// Hook store.alter
plugin.invokeAll('store.alter', {...context, store});
return store;
}
/**
* 返回命名空间字符串
* @param {String|Array} namespace 命名空间
* @return {String} 命名空间字符串
*/
function getNamespace(namespace){
if(namespace instanceof Array) namespace = namespace.join('/');
namespace = namespace.replace(/\//ig, '/');
return namespace;
}