Skip to content

Commit ffa6b8e

Browse files
author
drodichkin
committed
For danielroe#266: Add support of (un)registering global dynamic modules support
1 parent 97c6cb7 commit ffa6b8e

File tree

7 files changed

+104
-18
lines changed

7 files changed

+104
-18
lines changed

packages/nuxt-typed-vuex/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ const nuxtTypedVuex: Module = function nuxtTypedVuex() {
2424

2525
;(nuxtTypedVuex as any).meta = { name, version }
2626

27+
export * from './types/accessorRegisterModule'
2728
export default nuxtTypedVuex
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type {Module} from "vuex";
2+
3+
type AccessorRegisterModule = (path: string | [string, ...string[]], module: Module<any, any>) => void
4+
5+
declare module '@nuxt/types' {
6+
interface NuxtAppOptions {
7+
$accessorRegisterModule: AccessorRegisterModule;
8+
}
9+
10+
interface Context {
11+
$accessorRegisterModule: AccessorRegisterModule;
12+
}
13+
}
14+
15+
declare module 'vue/types/vue' {
16+
interface Vue {
17+
$accessorRegisterModule: AccessorRegisterModule;
18+
}
19+
}
20+
21+
declare module 'vuex/types/index' {
22+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
23+
interface Store<S> {
24+
$accessorRegisterModule: AccessorRegisterModule;
25+
}
26+
}
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import { getAccessorFromStore } from 'typed-vuex'
1+
import { getAccessorFromStore, registerModule } from 'typed-vuex'
22

33
import { createStore } from '<%= options.store %>'
44

55
const storeAccessor = getAccessorFromStore(createStore())
66

77
export default async ({ store }, inject) => {
8-
inject('accessor', storeAccessor(store))
8+
const accessor = storeAccessor(store)
9+
inject('accessor', accessor)
10+
inject('accessorRegisterModule', (path, module) => {
11+
registerModule(path, store, accessor, module)
12+
})
913
}

packages/typed-vuex/src/accessor.ts

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
import { Store, GetterTree, MutationTree, ActionTree } from 'vuex'
2-
import { NuxtStoreInput, MergedStoreType, BlankStore } from './types/store'
3-
import { State, StateType } from './types/state'
4-
import { NuxtModules } from './types/modules'
1+
import {ActionTree, GetterTree, Module, MutationTree, Store} from 'vuex'
2+
import {BlankStore, MergedStoreType, NuxtStoreInput} from './types/store'
3+
import {State, StateType} from './types/state'
4+
import {NuxtModules} from './types/modules'
55

6-
export const getAccessorType = <
7-
T extends State,
6+
export const getAccessorType = <T extends State,
87
G extends GetterTree<StateType<T>, any>,
98
M extends MutationTree<StateType<T>>,
109
A extends ActionTree<StateType<T>, any>,
11-
S extends NuxtModules
12-
>(
10+
S extends NuxtModules>(
1311
store: Partial<NuxtStoreInput<T, G, M, A, S>>
1412
) => {
1513
return (undefined as any) as MergedStoreType<typeof store & BlankStore>
@@ -65,13 +63,11 @@ const createAccessor = <T extends State, G, M, A, S extends NuxtModules>(
6563
return accessor
6664
}
6765

68-
export const useAccessor = <
69-
T extends State,
66+
export const useAccessor = <T extends State,
7067
G extends GetterTree<StateType<T>, any>,
7168
M extends MutationTree<StateType<T>>,
7269
A extends ActionTree<StateType<T>, any>,
73-
S extends NuxtModules
74-
>(
70+
S extends NuxtModules>(
7571
store: Store<any>,
7672
input: Partial<NuxtStoreInput<T, G, M, A, S>>,
7773
namespace?: string
@@ -97,3 +93,56 @@ export const getAccessorFromStore = (pattern: any) => {
9793
return (store: Store<any>) =>
9894
useAccessor(store, pattern._modules.root._rawModule)
9995
}
96+
97+
export const registerModule = (
98+
path: string | [string, ...string[]],
99+
store: Store<any>,
100+
accessor: MergedStoreType<Partial<NuxtStoreInput<any, any, any, any, any>> & BlankStore, string>,
101+
module: Module<any, any>
102+
) => {
103+
module.namespaced = true
104+
105+
if (module.modules) module.modules = Object.entries(module.modules).reduce((acc, [key, value]) => ({
106+
...acc,
107+
[key]: {
108+
...value,
109+
namespaced: true,
110+
}
111+
}), {}) as typeof module['modules']
112+
113+
let preserveState = false
114+
if (typeof path === 'string') preserveState = !!store.state[path]
115+
else {
116+
let target = store.state
117+
for (const key of path) {
118+
if (!target) break
119+
target = target[key]
120+
}
121+
preserveState = !!target
122+
}
123+
124+
const paths = typeof path === 'string' ? [path] : path
125+
126+
let target = accessor;
127+
paths.forEach((part, index) => {
128+
if (index === paths.length - 1) {
129+
if (!target) throw new Error(`Could not find parent module for ${paths[index - 1] || paths[index]}`);
130+
131+
store.registerModule(path as string, module as Module<any, any>, {
132+
preserveState,
133+
})
134+
target[part] = useAccessor(store, module, paths.join('/'));
135+
} else {
136+
target = target[part];
137+
}
138+
})
139+
}
140+
141+
export const unregisterModule = (
142+
path: string | [string, ...string[]],
143+
store: Store<any>,
144+
accessor: MergedStoreType<Partial<NuxtStoreInput<any, any, any, any, any>> & BlankStore, string>
145+
) => {
146+
store.unregisterModule(path as string)
147+
delete accessor[path[path.length - 1]]
148+
}

packages/typed-vuex/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ export * from './types/actions'
33
export * from './types/getters'
44
export * from './types/mutations'
55
export * from './types/utils'
6-
export { useAccessor, getAccessorType, getAccessorFromStore } from './accessor'
6+
export { useAccessor, getAccessorType, getAccessorFromStore, registerModule, unregisterModule } from './accessor'
77
export { createMapper } from './utils'
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { NuxtStore, MergedStoreType, BlankStore } from './store'
22

3-
export type NuxtModules = Record<string, Partial<NuxtStore>>
3+
export type NuxtModules = Record<string, Partial<NuxtStore & {dynamic: boolean}>>
4+
5+
type TransformedModule<T extends NuxtModules, P extends keyof T, O = string> = MergedStoreType<T[P] & BlankStore, O>
46

57
export type ModuleTransformer<T, O = string> = T extends NuxtModules
6-
? { [P in keyof T]: MergedStoreType<T[P] & BlankStore, O> }
8+
? { [P in keyof T]: T[P]['dynamic'] extends boolean ? undefined | TransformedModule<T, P, O> : TransformedModule<T, P, O> }
79
: {}

packages/typed-vuex/src/types/store.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,16 @@ export interface NuxtStore {
2626
modules: NuxtModules
2727
}
2828

29+
export interface ExtendedNuxtStore extends NuxtStore {
30+
dynamic: boolean;
31+
}
32+
2933
export interface NuxtStoreInput<
3034
T extends State,
3135
G,
3236
M,
3337
A,
34-
S extends { [key: string]: Partial<NuxtStore> }
38+
S extends { [key: string]: Partial<ExtendedNuxtStore> }
3539
> {
3640
namespaced?: boolean
3741
state: T

0 commit comments

Comments
 (0)