@libs-for-dev/vue-modular-application 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +410 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +61 -0
- package/dist/index.d.mts +61 -0
- package/dist/index.mjs +1 -0
- package/package.json +75 -0
package/README.md
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
# Vue Modular Application
|
|
2
|
+
|
|
3
|
+
A library for creating modular Vue.js applications with support for automatic registration of modules, plugins, widgets, and routes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`@libs-for-dev/vue-modular-application` provides an architecture for building scalable Vue.js applications based on a modular system. The library allows you to:
|
|
8
|
+
|
|
9
|
+
- Automatically register client modules
|
|
10
|
+
- Manage Vue plugins and widgets
|
|
11
|
+
- Integrate Inversify containers for dependency injection
|
|
12
|
+
- Combine routes and navigation from different modules
|
|
13
|
+
- Support SSR (Server-Side Rendering)
|
|
14
|
+
- Ensure complete module isolation
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @libs-for-dev/vue-modular-application
|
|
20
|
+
# or
|
|
21
|
+
yarn add @libs-for-dev/vue-modular-application
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Peer Dependencies
|
|
25
|
+
|
|
26
|
+
The library requires the following dependencies:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install vue@^3.0.0 vue-router@^4.0.0
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For dependency injection usage (optional):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install inversify@^6.0.0 reflect-metadata@^0.2.0
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Creating a Client Module
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import type {
|
|
44
|
+
ClientModuleInterface,
|
|
45
|
+
ContainerPluginInterface,
|
|
46
|
+
VuePluginInterface,
|
|
47
|
+
VueWidgetsInterface
|
|
48
|
+
} from '@libs-for-dev/vue-modular-application'
|
|
49
|
+
import type { RouteRecordRaw } from 'vue-router'
|
|
50
|
+
import { Container } from 'inversify'
|
|
51
|
+
|
|
52
|
+
export class UserModule implements ClientModuleInterface<NavigationItem[], RouteRecordRaw[], Container> {
|
|
53
|
+
readonly name = 'user-module'
|
|
54
|
+
|
|
55
|
+
getRoutes(): RouteRecordRaw[] {
|
|
56
|
+
return [
|
|
57
|
+
{
|
|
58
|
+
path: '/users',
|
|
59
|
+
name: 'Users',
|
|
60
|
+
component: () => import('./components/UsersPage.vue')
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getNavigation(): NavigationItem[] {
|
|
66
|
+
return [
|
|
67
|
+
{
|
|
68
|
+
label: 'Users',
|
|
69
|
+
path: '/users',
|
|
70
|
+
icon: 'users'
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getPlugins(): VuePluginInterface[] {
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
install(app) {
|
|
79
|
+
app.config.globalProperties.$userService = new UserService()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getContainer(): ContainerPluginInterface<Container>[] {
|
|
86
|
+
const container = new Container()
|
|
87
|
+
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
container,
|
|
91
|
+
install() {
|
|
92
|
+
container.bind('UserService').to(UserService).inSingletonScope()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
getWidgets(): VueWidgetsInterface[] {
|
|
99
|
+
return [
|
|
100
|
+
{
|
|
101
|
+
namespace: 'user',
|
|
102
|
+
widgets: {
|
|
103
|
+
UserCard: () => import('./widgets/UserCard.vue'),
|
|
104
|
+
UserStats: () => import('./widgets/UserStats.vue')
|
|
105
|
+
},
|
|
106
|
+
install() {
|
|
107
|
+
// Additional widget installation logic
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 2. Module Registration
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { ModuleLoader } from '@libs-for-dev/vue-modular-application'
|
|
119
|
+
import { UserModule } from './modules/UserModule'
|
|
120
|
+
|
|
121
|
+
// Register module
|
|
122
|
+
ModuleLoader.registerModuleProvider(new UserModule())
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 3. Application Creation
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { createApp } from 'vue'
|
|
129
|
+
import { createWebHistory } from 'vue-router'
|
|
130
|
+
import { VueApplication, ModuleLoader } from '@libs-for-dev/vue-modular-application'
|
|
131
|
+
|
|
132
|
+
// Get modules registry
|
|
133
|
+
const moduleRegistry = ModuleLoader.getModulesRegistry()
|
|
134
|
+
|
|
135
|
+
// Create application instance
|
|
136
|
+
const appInstance = new VueApplication(
|
|
137
|
+
createApp,
|
|
138
|
+
createWebHistory(),
|
|
139
|
+
moduleRegistry
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
// Build application
|
|
143
|
+
const app = appInstance.build(App)
|
|
144
|
+
|
|
145
|
+
// Mount
|
|
146
|
+
app.mount('#app')
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## API Reference
|
|
150
|
+
|
|
151
|
+
### VueApplication
|
|
152
|
+
|
|
153
|
+
Main class for creating Vue applications with modular architecture.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
class VueApplication<Navigation, Routes, Container> {
|
|
157
|
+
constructor(
|
|
158
|
+
createApp: CreateAppFunction<Element>,
|
|
159
|
+
routerHistory: RouterHistory,
|
|
160
|
+
moduleRegistry: ModuleRegistry<Navigation, Routes, Container>
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
build(element: DefineComponent): App<Element>
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### ModuleLoader
|
|
168
|
+
|
|
169
|
+
Static class for managing module registration.
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
class ModuleLoader {
|
|
173
|
+
static registerModuleProvider(module: ClientModuleInterface<unknown, unknown>): void
|
|
174
|
+
static getModulesRegistry(): ModuleRegistry<unknown, unknown, unknown>
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### ModuleRegistry
|
|
179
|
+
|
|
180
|
+
Module registry providing access to registered modules and their resources.
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
class ModuleRegistry<Navigation, Routes, Container> {
|
|
184
|
+
constructor(clientModules: ClientModuleInterface<Navigation, Routes, Container>[])
|
|
185
|
+
|
|
186
|
+
getAllRoutes(): Routes[]
|
|
187
|
+
getModules(): ClientModuleInterface<Navigation, Routes, Container>[]
|
|
188
|
+
getNavigation(): Ref<UnwrapRef<Navigation[]>>
|
|
189
|
+
getWidget(namespace: string, widgetName: string): unknown
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Interfaces
|
|
194
|
+
|
|
195
|
+
### ClientModuleInterface
|
|
196
|
+
|
|
197
|
+
Base interface for all client modules.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
interface ClientModuleInterface<Navigation, Routes, Container = unknown> {
|
|
201
|
+
readonly name: string
|
|
202
|
+
|
|
203
|
+
getRoutes(): Routes
|
|
204
|
+
getNavigation(): Navigation
|
|
205
|
+
getPlugins(): VuePluginInterface[]
|
|
206
|
+
getContainer(): ContainerPluginInterface<Container>[]
|
|
207
|
+
getWidgets(): VueWidgetsInterface[]
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### VuePluginInterface
|
|
212
|
+
|
|
213
|
+
Interface for Vue plugins.
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
interface VuePluginInterface {
|
|
217
|
+
install(app: App): void
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### ContainerPluginInterface
|
|
222
|
+
|
|
223
|
+
Interface for plugins with Inversify container.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
interface ContainerPluginInterface<Container> extends VuePluginInterface {
|
|
227
|
+
container: Container
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### VueWidgetsInterface
|
|
232
|
+
|
|
233
|
+
Interface for widgets with extended functionality.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
interface VueWidgetsInterface extends VuePluginInterface {
|
|
237
|
+
namespace: string
|
|
238
|
+
options?: Record<string, unknown>
|
|
239
|
+
widgets: Record<string, Component>
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### SSR Support
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { createSSRApp } from 'vue'
|
|
247
|
+
import { createMemoryHistory } from 'vue-router'
|
|
248
|
+
import { renderToString } from 'vue/server-renderer'
|
|
249
|
+
import { VueApplication, ModuleLoader } from '@libs-for-dev/vue-modular-application'
|
|
250
|
+
|
|
251
|
+
export async function renderApp(url: string) {
|
|
252
|
+
const moduleRegistry = ModuleLoader.getModulesRegistry()
|
|
253
|
+
const appInstance = new VueApplication(
|
|
254
|
+
createSSRApp,
|
|
255
|
+
createMemoryHistory(),
|
|
256
|
+
moduleRegistry
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
const app = appInstance.build({
|
|
260
|
+
name: 'App',
|
|
261
|
+
template: '<router-view />'
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
// Set route for SSR
|
|
265
|
+
app.config.globalProperties.$router.push(url)
|
|
266
|
+
await app.config.globalProperties.$router.isReady()
|
|
267
|
+
|
|
268
|
+
const html = await renderToString(app)
|
|
269
|
+
|
|
270
|
+
return html
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Advanced Scenarios
|
|
275
|
+
|
|
276
|
+
### Conditional Module Loading
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
// Dynamic module registration based on conditions
|
|
280
|
+
if (process.env.NODE_ENV === 'development') {
|
|
281
|
+
ModuleLoader.registerModuleProvider(new DevToolsModule())
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (userHasAdminRole()) {
|
|
285
|
+
ModuleLoader.registerModuleProvider(new AdminModule())
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Custom Plugins with Typing
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
interface CustomPluginOptions {
|
|
293
|
+
apiUrl: string
|
|
294
|
+
timeout: number
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
class CustomPlugin implements VuePluginInterface {
|
|
298
|
+
constructor(private options: CustomPluginOptions) {}
|
|
299
|
+
|
|
300
|
+
install(app: App) {
|
|
301
|
+
app.config.globalProperties.$customService = new CustomService(this.options)
|
|
302
|
+
|
|
303
|
+
app.provide('customService', app.config.globalProperties.$customService)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Usage in module
|
|
308
|
+
getPlugins(): VuePluginInterface[] {
|
|
309
|
+
return [
|
|
310
|
+
new CustomPlugin({
|
|
311
|
+
apiUrl: 'https://api.example.com',
|
|
312
|
+
timeout: 5000
|
|
313
|
+
})
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Route Middleware
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
export class ProtectedModule implements ClientModuleInterface<NavigationItem[], RouteRecordRaw[], Container> {
|
|
322
|
+
getRoutes(): RouteRecordRaw[] {
|
|
323
|
+
return [
|
|
324
|
+
{
|
|
325
|
+
path: '/admin',
|
|
326
|
+
name: 'Admin',
|
|
327
|
+
component: () => import('./components/AdminPage.vue'),
|
|
328
|
+
meta: {
|
|
329
|
+
requiresAuth: true,
|
|
330
|
+
roles: ['admin']
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
getPlugins(): VuePluginInterface[] {
|
|
337
|
+
return [
|
|
338
|
+
{
|
|
339
|
+
install(app) {
|
|
340
|
+
// Register middleware for authorization check
|
|
341
|
+
app.config.globalProperties.$router.beforeEach((to, from, next) => {
|
|
342
|
+
if (to.meta.requiresAuth && !isAuthenticated()) {
|
|
343
|
+
next('/login')
|
|
344
|
+
} else {
|
|
345
|
+
next()
|
|
346
|
+
}
|
|
347
|
+
})
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Architectural Principles
|
|
356
|
+
|
|
357
|
+
### 1. Complete Module Isolation
|
|
358
|
+
|
|
359
|
+
Modules should not have direct dependencies on each other. Interaction occurs only through:
|
|
360
|
+
|
|
361
|
+
- **ModuleRegistry** - for accessing widgets from other modules
|
|
362
|
+
- **Data Denormalization** - passing `authorId` + `authorName` instead of importing `UserInterface`
|
|
363
|
+
- **Common Interfaces** - using base types from shared library
|
|
364
|
+
|
|
365
|
+
### 2. Modular Structure
|
|
366
|
+
|
|
367
|
+
```text
|
|
368
|
+
src/modules/
|
|
369
|
+
├── module-name/
|
|
370
|
+
│ ├── module-name.module.ts # Module entry point
|
|
371
|
+
│ ├── module-name.service.ts # Module business logic
|
|
372
|
+
│ ├── pages/ # Module pages(optional)
|
|
373
|
+
│ └── widgets/ # Module widgets(optional)
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### 3. Dependency Injection
|
|
377
|
+
|
|
378
|
+
Example of using Inversify for dependency management within modules:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
getContainer(): ContainerPluginInterface<Container>[] {
|
|
382
|
+
const container = new Container()
|
|
383
|
+
|
|
384
|
+
return [{
|
|
385
|
+
container,
|
|
386
|
+
install() {
|
|
387
|
+
container.bind('UserService').to(UserService).inSingletonScope()
|
|
388
|
+
}
|
|
389
|
+
}]
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Tips and Recommendations
|
|
394
|
+
|
|
395
|
+
1. **Module Naming**: Use unique names for modules to avoid conflicts
|
|
396
|
+
2. **Lazy Loading**: Use dynamic imports for components and widgets
|
|
397
|
+
3. **Typing**: Define types for Navigation and Routes for better typing
|
|
398
|
+
4. **Testing**: Each module should be covered by unit tests
|
|
399
|
+
5. **Performance**: Register only necessary modules for specific environment
|
|
400
|
+
6. **Isolation**: Avoid direct imports between modules
|
|
401
|
+
7. **Denormalization**: Pass required data explicitly instead of importing types
|
|
402
|
+
|
|
403
|
+
## License
|
|
404
|
+
|
|
405
|
+
MIT
|
|
406
|
+
|
|
407
|
+
## Support
|
|
408
|
+
|
|
409
|
+
- [Issues](https://gitlab.com/libs-for-dev/nodejs/vue-modular-application/-/issues)
|
|
410
|
+
- [Repository](https://gitlab.com/libs-for-dev/nodejs/vue-modular-application)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=require(`vue`),t=require(`vue-router`);const n=Symbol(`ModuleRegistry`);var r=class{widgets=new Map;constructor(e){this.clientModules=e;let t=this.clientModules.flatMap(e=>e.getWidgets());for(let e of t)this.registerWidget(e)}getAllRoutes(){return this.getModules().flatMap(e=>e.getRoutes())}getModules(){return this.clientModules}getNavigation(){let t=(0,e.ref)([]);for(let e of this.getModules()){let n=e.getNavigation();t.value.push(...n)}return t}getWidget(e,t){return this.widgets.get(e)?.widgets[t]}registerWidget(e){this.widgets.set(e.namespace,e)}},i=class{static modules=new Map;static getModulesRegistry(){return new r([...this.modules.values()])}static registerModuleProvider(e){let{name:t}=e;this.modules.has(t)||this.modules.set(t,e)}},a=class{constructor(e,t,n){this.createApp=e,this.routerHistory=t,this.moduleRegistry=n}build(e){let r=this.createApp(e);r.provide(n,this.moduleRegistry);let i=this.moduleRegistry.getAllRoutes();(0,t.createRouter)({history:this.routerHistory,routes:i}).install(r);let a=this.moduleRegistry.getModules();for(let e of a.flatMap(e=>[...e.getContainer(),...e.getPlugins(),...e.getWidgets()]))e.install(r);return r}};exports.MODULE_REGISTRY=n,exports.ModuleLoader=i,exports.ModuleRegistry=r,exports.VueApplication=a;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { App, Component, CreateAppFunction, DefineComponent, Ref, UnwrapRef } from "vue";
|
|
2
|
+
import { RouteRecordRaw, RouterHistory } from "vue-router";
|
|
3
|
+
|
|
4
|
+
//#region src/client-module/plugins/vue-plugin.interface.d.ts
|
|
5
|
+
interface VuePluginInterface {
|
|
6
|
+
install(app: App): void;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/client-module/plugins/container-plugin.interface.d.ts
|
|
10
|
+
interface ContainerPluginInterface<Container> extends VuePluginInterface {
|
|
11
|
+
container: Container;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/client-module/plugins/vue-widget.interface.d.ts
|
|
15
|
+
interface VueWidgetsInterface extends VuePluginInterface {
|
|
16
|
+
namespace: string;
|
|
17
|
+
options?: Record<string, unknown>;
|
|
18
|
+
widgets: Record<string, Component>;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/client-module/client-module.interface.d.ts
|
|
22
|
+
interface ClientModuleInterface<Routes extends RouteRecordRaw[], Navigation$1, Container = unknown> {
|
|
23
|
+
getContainer(): ContainerPluginInterface<Container>[];
|
|
24
|
+
getNavigation(): Navigation$1;
|
|
25
|
+
getPlugins(): VuePluginInterface[];
|
|
26
|
+
getRoutes(): Routes;
|
|
27
|
+
getWidgets(): VueWidgetsInterface[];
|
|
28
|
+
readonly name: string;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/client-module/module-registry.d.ts
|
|
32
|
+
declare const MODULE_REGISTRY: unique symbol;
|
|
33
|
+
declare class ModuleRegistry<Routes extends RouteRecordRaw[], Navigation$1> {
|
|
34
|
+
private readonly clientModules;
|
|
35
|
+
private readonly widgets;
|
|
36
|
+
constructor(clientModules: ClientModuleInterface<Routes, Navigation$1>[]);
|
|
37
|
+
getAllRoutes(): RouteRecordRaw[];
|
|
38
|
+
getModules(): ClientModuleInterface<Routes, Navigation$1>[];
|
|
39
|
+
getNavigation(): Ref<UnwrapRef<Navigation$1[]>>;
|
|
40
|
+
getWidget(namespace: string, widgetName: string): unknown;
|
|
41
|
+
private registerWidget;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/client-module/module-loader.d.ts
|
|
45
|
+
declare class ModuleLoader {
|
|
46
|
+
private static readonly modules;
|
|
47
|
+
static getModulesRegistry(): ModuleRegistry<RouteRecordRaw[], unknown[]>;
|
|
48
|
+
static registerModuleProvider(module: ClientModuleInterface<RouteRecordRaw[], unknown[]>): void;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/vue-application.d.ts
|
|
52
|
+
type Navigation = unknown[];
|
|
53
|
+
declare class VueApplication {
|
|
54
|
+
private readonly createApp;
|
|
55
|
+
private readonly routerHistory;
|
|
56
|
+
private readonly moduleRegistry;
|
|
57
|
+
constructor(createApp: CreateAppFunction<Element>, routerHistory: RouterHistory, moduleRegistry: ModuleRegistry<RouteRecordRaw[], Navigation>);
|
|
58
|
+
build(element: DefineComponent): App<Element>;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { ClientModuleInterface, ContainerPluginInterface, MODULE_REGISTRY, ModuleLoader, ModuleRegistry, VueApplication, VuePluginInterface, VueWidgetsInterface };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { App, Component, CreateAppFunction, DefineComponent, Ref, UnwrapRef } from "vue";
|
|
2
|
+
import { RouteRecordRaw, RouterHistory } from "vue-router";
|
|
3
|
+
|
|
4
|
+
//#region src/client-module/plugins/vue-plugin.interface.d.ts
|
|
5
|
+
interface VuePluginInterface {
|
|
6
|
+
install(app: App): void;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/client-module/plugins/container-plugin.interface.d.ts
|
|
10
|
+
interface ContainerPluginInterface<Container> extends VuePluginInterface {
|
|
11
|
+
container: Container;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/client-module/plugins/vue-widget.interface.d.ts
|
|
15
|
+
interface VueWidgetsInterface extends VuePluginInterface {
|
|
16
|
+
namespace: string;
|
|
17
|
+
options?: Record<string, unknown>;
|
|
18
|
+
widgets: Record<string, Component>;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/client-module/client-module.interface.d.ts
|
|
22
|
+
interface ClientModuleInterface<Routes extends RouteRecordRaw[], Navigation$1, Container = unknown> {
|
|
23
|
+
getContainer(): ContainerPluginInterface<Container>[];
|
|
24
|
+
getNavigation(): Navigation$1;
|
|
25
|
+
getPlugins(): VuePluginInterface[];
|
|
26
|
+
getRoutes(): Routes;
|
|
27
|
+
getWidgets(): VueWidgetsInterface[];
|
|
28
|
+
readonly name: string;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/client-module/module-registry.d.ts
|
|
32
|
+
declare const MODULE_REGISTRY: unique symbol;
|
|
33
|
+
declare class ModuleRegistry<Routes extends RouteRecordRaw[], Navigation$1> {
|
|
34
|
+
private readonly clientModules;
|
|
35
|
+
private readonly widgets;
|
|
36
|
+
constructor(clientModules: ClientModuleInterface<Routes, Navigation$1>[]);
|
|
37
|
+
getAllRoutes(): RouteRecordRaw[];
|
|
38
|
+
getModules(): ClientModuleInterface<Routes, Navigation$1>[];
|
|
39
|
+
getNavigation(): Ref<UnwrapRef<Navigation$1[]>>;
|
|
40
|
+
getWidget(namespace: string, widgetName: string): unknown;
|
|
41
|
+
private registerWidget;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/client-module/module-loader.d.ts
|
|
45
|
+
declare class ModuleLoader {
|
|
46
|
+
private static readonly modules;
|
|
47
|
+
static getModulesRegistry(): ModuleRegistry<RouteRecordRaw[], unknown[]>;
|
|
48
|
+
static registerModuleProvider(module: ClientModuleInterface<RouteRecordRaw[], unknown[]>): void;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/vue-application.d.ts
|
|
52
|
+
type Navigation = unknown[];
|
|
53
|
+
declare class VueApplication {
|
|
54
|
+
private readonly createApp;
|
|
55
|
+
private readonly routerHistory;
|
|
56
|
+
private readonly moduleRegistry;
|
|
57
|
+
constructor(createApp: CreateAppFunction<Element>, routerHistory: RouterHistory, moduleRegistry: ModuleRegistry<RouteRecordRaw[], Navigation>);
|
|
58
|
+
build(element: DefineComponent): App<Element>;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { ClientModuleInterface, ContainerPluginInterface, MODULE_REGISTRY, ModuleLoader, ModuleRegistry, VueApplication, VuePluginInterface, VueWidgetsInterface };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ref as e}from"vue";import{createRouter as t}from"vue-router";const n=Symbol(`ModuleRegistry`);var r=class{widgets=new Map;constructor(e){this.clientModules=e;let t=this.clientModules.flatMap(e=>e.getWidgets());for(let e of t)this.registerWidget(e)}getAllRoutes(){return this.getModules().flatMap(e=>e.getRoutes())}getModules(){return this.clientModules}getNavigation(){let t=e([]);for(let e of this.getModules()){let n=e.getNavigation();t.value.push(...n)}return t}getWidget(e,t){return this.widgets.get(e)?.widgets[t]}registerWidget(e){this.widgets.set(e.namespace,e)}},i=class{static modules=new Map;static getModulesRegistry(){return new r([...this.modules.values()])}static registerModuleProvider(e){let{name:t}=e;this.modules.has(t)||this.modules.set(t,e)}},a=class{constructor(e,t,n){this.createApp=e,this.routerHistory=t,this.moduleRegistry=n}build(e){let r=this.createApp(e);r.provide(n,this.moduleRegistry);let i=this.moduleRegistry.getAllRoutes();t({history:this.routerHistory,routes:i}).install(r);let a=this.moduleRegistry.getModules();for(let e of a.flatMap(e=>[...e.getContainer(),...e.getPlugins(),...e.getWidgets()]))e.install(r);return r}};export{n as MODULE_REGISTRY,i as ModuleLoader,r as ModuleRegistry,a as VueApplication};
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@libs-for-dev/vue-modular-application",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Vue modular application",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vue"
|
|
7
|
+
],
|
|
8
|
+
"homepage": "https://gitlab.com/libs-for-dev/nodejs/vue-modular-application",
|
|
9
|
+
"bugs": "https://gitlab.com/libs-for-dev/nodejs/vue-modular-application/-/issues",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://gitlab.com/libs-for-dev/nodejs/vue-modular-application.git"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "libs-for-dev"
|
|
17
|
+
},
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": "./dist/index.mjs",
|
|
23
|
+
"require": "./dist/index.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"main": "dist/index.mjs",
|
|
27
|
+
"types": "dist/index.d.mts",
|
|
28
|
+
"files": [
|
|
29
|
+
"dist"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "rm -rf ./dist && cti create ./src && tsdown && cti clean ./src",
|
|
33
|
+
"dev:quality": "yarn concurrently --timings --kill-others-on-fail 'yarn lint' 'yarn test'",
|
|
34
|
+
"dev:test:watch": "vitest",
|
|
35
|
+
"lint": "yarn concurrently --timings 'yarn:lint:*'",
|
|
36
|
+
"lint:audit": "yarn npm audit",
|
|
37
|
+
"lint:depcheck": "knip",
|
|
38
|
+
"lint:eslint": "eslint --cache .",
|
|
39
|
+
"lint:scriptlint": "scriptlint",
|
|
40
|
+
"lint:tsc": "tsc --noEmit --pretty --project .",
|
|
41
|
+
"test": "yarn concurrently --timings 'npm:test:*'",
|
|
42
|
+
"test:mutation": "yarn stryker run",
|
|
43
|
+
"test:unit": "vitest run"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@libs-for-dev/eslint-rules": "2.5.0",
|
|
47
|
+
"@stryker-mutator/core": "9.4.0",
|
|
48
|
+
"@stryker-mutator/vitest-runner": "9.4.0",
|
|
49
|
+
"@tsconfig/strictest": "^2.0.8",
|
|
50
|
+
"@types/node": "25.0.6",
|
|
51
|
+
"@vitest/coverage-v8": "4.0.16",
|
|
52
|
+
"concurrently": "9.2.1",
|
|
53
|
+
"create-ts-index": "1.14.0",
|
|
54
|
+
"eslint": "9.39.2",
|
|
55
|
+
"jiti": "2.6.1",
|
|
56
|
+
"knip": "5.80.2",
|
|
57
|
+
"reflect-metadata": "0.2.2",
|
|
58
|
+
"sass-embedded": "1.97.2",
|
|
59
|
+
"scriptlint": "3.0.0",
|
|
60
|
+
"tsdown": "0.19.0",
|
|
61
|
+
"typescript": "5.9.3",
|
|
62
|
+
"vitest": "4.0.16",
|
|
63
|
+
"vue": "3.5.26",
|
|
64
|
+
"vue-router": "4.6.4",
|
|
65
|
+
"yarn-audit-fix": "10.1.1"
|
|
66
|
+
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"vue": ">=3.0.0 <4.0.0",
|
|
69
|
+
"vue-router": ">=4.0.0 <5.0.0"
|
|
70
|
+
},
|
|
71
|
+
"packageManager": "yarn@4.12.0",
|
|
72
|
+
"engines": {
|
|
73
|
+
"node": "^24.7.0"
|
|
74
|
+
}
|
|
75
|
+
}
|