store.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import Vue from 'vue';
  2. import Vuex from 'vuex';
  3. Vue.use(Vuex);
  4. const files = require.context('@/store', true, /^\.\/(?!-)[^.]+\.(js|mjs)$/);
  5. const filenames = files.keys();
  6. // Store
  7. let storeData = {};
  8. // Check if {dir.store}/index.js exists
  9. const indexFilename = filenames.find(filename => filename.includes('./index.'));
  10. if (indexFilename) {
  11. storeData = getModule(indexFilename);
  12. }
  13. // If store is not an exported method = modules store
  14. if (typeof storeData !== 'function') {
  15. // Store modules
  16. if (!storeData.modules) {
  17. storeData.modules = {};
  18. }
  19. for (const filename of filenames) {
  20. let name = filename.replace(/^\.\//, '').replace(/\.(js|mjs)$/, '');
  21. if (name === 'index') continue;
  22. const namePath = name.split(/\//);
  23. name = namePath[namePath.length - 1];
  24. if (['state', 'getters', 'actions', 'mutations'].includes(name)) {
  25. const module = getModuleNamespace(storeData, namePath, true);
  26. appendModule(module, filename, name);
  27. continue;
  28. }
  29. // If file is foo/index.js, it should be saved as foo
  30. const isIndex = name === 'index';
  31. if (isIndex) {
  32. namePath.pop();
  33. }
  34. const module = getModuleNamespace(storeData, namePath);
  35. const fileModule = getModule(filename);
  36. name = namePath.pop();
  37. module[name] = module[name] || {};
  38. // if file is foo.js, existing properties take priority
  39. // because it's the least specific case
  40. if (!isIndex) {
  41. module[name] = Object.assign({}, fileModule, module[name]);
  42. module[name].namespaced = true;
  43. continue;
  44. }
  45. // if file is foo/index.js we want to overwrite properties from foo.js
  46. // but not from appended mods like foo/actions.js
  47. const appendedMods = {};
  48. if (module[name].appends) {
  49. appendedMods.appends = module[name].appends;
  50. for (const append of module[name].appends) {
  51. appendedMods[append] = module[name][append];
  52. }
  53. }
  54. module[name] = Object.assign({}, module[name], fileModule, appendedMods);
  55. module[name].namespaced = true;
  56. }
  57. }
  58. // createStore
  59. export const createStore =
  60. storeData instanceof Function
  61. ? storeData
  62. : () => {
  63. return new Vuex.Store(
  64. Object.assign(
  65. {
  66. strict: process.env.NODE_ENV !== 'production',
  67. },
  68. storeData,
  69. {
  70. state: storeData.state instanceof Function ? storeData.state() : {},
  71. }
  72. )
  73. );
  74. };
  75. // Dynamically require module
  76. function getModule(filename) {
  77. const file = files(filename);
  78. const module = file.default || file;
  79. if (module.commit) {
  80. throw new Error('[nuxt] store/' + filename.replace('./', '') + ' should export a method which returns a Vuex instance.');
  81. }
  82. if (module.state && typeof module.state !== 'function') {
  83. throw new Error('[nuxt] state should be a function in store/' + filename.replace('./', ''));
  84. }
  85. return module;
  86. }
  87. function getModuleNamespace(storeData, namePath, forAppend = false) {
  88. if (namePath.length === 1) {
  89. if (forAppend) {
  90. return storeData;
  91. }
  92. return storeData.modules;
  93. }
  94. const namespace = namePath.shift();
  95. storeData.modules[namespace] = storeData.modules[namespace] || {};
  96. storeData.modules[namespace].namespaced = true;
  97. storeData.modules[namespace].modules = storeData.modules[namespace].modules || {};
  98. return getModuleNamespace(storeData.modules[namespace], namePath, forAppend);
  99. }
  100. function appendModule(module, filename, name) {
  101. const file = files(filename);
  102. module.appends = module.appends || [];
  103. module.appends.push(name);
  104. module[name] = file.default || file;
  105. }