Fix multiple apps (#316)
* chore: multiple apps * fix: multiple apps with application options * fix: multiple apps AppSelector type * chore: multiple apps with plugin config * chore: rename multiple-apps to multiple-apps-manager * chore: application association * chore: plugin multi-app manager
This commit is contained in:
		
							parent
							
								
									ea0dd6e31a
								
							
						
					
					
						commit
						b1086ee728
					
				| @ -3,7 +3,7 @@ import http, { IncomingMessage } from 'http'; | ||||
| import EventEmitter from 'events'; | ||||
| import { applyMixins, AsyncEmitter } from '@nocobase/utils'; | ||||
| 
 | ||||
| type AppSelector = (ctx) => Application | string; | ||||
| type AppSelector = (req: IncomingMessage) => Application | string | undefined | null; | ||||
| 
 | ||||
| export class AppManager extends EventEmitter { | ||||
|   public applications: Map<string, Application> = new Map<string, Application>(); | ||||
| @ -63,7 +63,7 @@ export class AppManager extends EventEmitter { | ||||
| 
 | ||||
|   callback() { | ||||
|     return async (req, res) => { | ||||
|       let handleApp = this.appSelector(req); | ||||
|       let handleApp = this.appSelector(req) || this.app; | ||||
| 
 | ||||
|       if (typeof handleApp === 'string') { | ||||
|         handleApp = (await this.getApplication(handleApp)) || this.app; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| { | ||||
|   "name": "@nocobase/plugin-multiple-apps", | ||||
|   "name": "@nocobase/plugin-multi-app-manager", | ||||
|   "version": "0.6.2-alpha.12", | ||||
|   "main": "lib/index.js", | ||||
|   "license": "MIT", | ||||
| @ -1,7 +1,6 @@ | ||||
| import { Plugin } from '@nocobase/server'; | ||||
| import { ApplicationModel } from '../models/application'; | ||||
| import { Plugin, PluginManager } from '@nocobase/server'; | ||||
| import { mockServer } from '@nocobase/test'; | ||||
| import { PluginMultipleApps } from '../server'; | ||||
| import { PluginMultiAppManager } from '../server'; | ||||
| 
 | ||||
| describe('test with start', () => { | ||||
|   it('should load subApp on create', async () => { | ||||
| @ -24,11 +23,12 @@ describe('test with start', () => { | ||||
| 
 | ||||
|     const mockGetPluginByName = jest.fn(); | ||||
|     mockGetPluginByName.mockReturnValue(TestPlugin); | ||||
|     ApplicationModel.getPluginByName = mockGetPluginByName; | ||||
|     PluginManager.resolvePlugin = mockGetPluginByName; | ||||
| 
 | ||||
|     const app = mockServer(); | ||||
|     await app.cleanDb(); | ||||
|     app.plugin(PluginMultipleApps); | ||||
| 
 | ||||
|     app.plugin(PluginMultiAppManager); | ||||
| 
 | ||||
|     await app.loadAndInstall(); | ||||
|     await app.start(); | ||||
| @ -38,11 +38,9 @@ describe('test with start', () => { | ||||
|     await db.getRepository('applications').create({ | ||||
|       values: { | ||||
|         name: 'sub1', | ||||
|         plugins: [ | ||||
|           { | ||||
|             name: 'test-package', | ||||
|           }, | ||||
|         ], | ||||
|         options: { | ||||
|           plugins: ['test-package'], | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
| 
 | ||||
| @ -55,7 +53,7 @@ describe('test with start', () => { | ||||
|   it('should install into difference database', async () => { | ||||
|     const app = mockServer(); | ||||
|     await app.cleanDb(); | ||||
|     app.plugin(PluginMultipleApps); | ||||
|     app.plugin(PluginMultiAppManager); | ||||
| 
 | ||||
|     await app.loadAndInstall(); | ||||
|     await app.start(); | ||||
| @ -65,11 +63,9 @@ describe('test with start', () => { | ||||
|     await db.getRepository('applications').create({ | ||||
|       values: { | ||||
|         name: 'sub1', | ||||
|         plugins: [ | ||||
|           { | ||||
|             name: '@nocobase/plugin-ui-schema-storage', | ||||
|           }, | ||||
|         ], | ||||
|         options: { | ||||
|           plugins: ['@nocobase/plugin-ui-schema-storage'], | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
|     await app.destroy(); | ||||
| @ -84,7 +80,7 @@ describe('test with start', () => { | ||||
| 
 | ||||
|     let app = mockServer(); | ||||
|     await app.cleanDb(); | ||||
|     app.plugin(PluginMultipleApps); | ||||
|     app.plugin(PluginMultiAppManager); | ||||
| 
 | ||||
|     await app.loadAndInstall(); | ||||
|     await app.start(); | ||||
| @ -93,16 +89,14 @@ describe('test with start', () => { | ||||
| 
 | ||||
|     const mockGetPluginByName = jest.fn(); | ||||
|     mockGetPluginByName.mockReturnValue(TestPlugin); | ||||
|     ApplicationModel.getPluginByName = mockGetPluginByName; | ||||
|     PluginManager.resolvePlugin = mockGetPluginByName; | ||||
| 
 | ||||
|     await db.getRepository('applications').create({ | ||||
|       values: { | ||||
|         name: 'sub1', | ||||
|         plugins: [ | ||||
|           { | ||||
|             name: 'test-package', | ||||
|           }, | ||||
|         ], | ||||
|         options: { | ||||
|           plugins: ['test-package'], | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
| 
 | ||||
| @ -114,7 +108,7 @@ describe('test with start', () => { | ||||
|       database: app.db, | ||||
|     }); | ||||
| 
 | ||||
|     newApp.plugin(PluginMultipleApps); | ||||
|     newApp.plugin(PluginMultiAppManager); | ||||
|     await newApp.db.reconnect(); | ||||
| 
 | ||||
|     await newApp.load(); | ||||
| @ -1,6 +1,6 @@ | ||||
| import { mockServer, MockServer } from '@nocobase/test'; | ||||
| import { Database } from '@nocobase/database'; | ||||
| import { PluginMultipleApps } from '../server'; | ||||
| import { PluginMultiAppManager } from '../server'; | ||||
| 
 | ||||
| describe('multiple apps create', () => { | ||||
|   let app: MockServer; | ||||
| @ -10,7 +10,7 @@ describe('multiple apps create', () => { | ||||
|     app = mockServer({}); | ||||
|     db = app.db; | ||||
|     await app.cleanDb(); | ||||
|     app.plugin(PluginMultipleApps); | ||||
|     app.plugin(PluginMultiAppManager); | ||||
| 
 | ||||
|     await app.loadAndInstall(); | ||||
|   }); | ||||
| @ -51,29 +51,30 @@ describe('multiple apps create', () => { | ||||
|     await db.getRepository('applications').create({ | ||||
|       values: { | ||||
|         name: 'miniApp', | ||||
|         plugins: [ | ||||
|           { | ||||
|             name: '@nocobase/plugin-ui-schema-storage', | ||||
|           }, | ||||
|         ], | ||||
|         options: { | ||||
|           plugins: [['@nocobase/plugin-ui-schema-storage', { test: 'B' }]], | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
| 
 | ||||
|     const miniApp = app.appManager.applications.get('miniApp'); | ||||
|     expect(miniApp).toBeDefined(); | ||||
| 
 | ||||
|     expect(miniApp.pm.get('@nocobase/plugin-ui-schema-storage')).toBeDefined(); | ||||
|     const plugin = miniApp.pm.get('@nocobase/plugin-ui-schema-storage'); | ||||
| 
 | ||||
|     expect(plugin).toBeDefined(); | ||||
|     expect(plugin.options).toEqual({ | ||||
|       test: 'B', | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   it('should lazy load applications', async () => { | ||||
|     await db.getRepository('applications').create({ | ||||
|       values: { | ||||
|         name: 'miniApp', | ||||
|         plugins: [ | ||||
|           { | ||||
|             name: '@nocobase/plugin-ui-schema-storage', | ||||
|           }, | ||||
|         ], | ||||
|         options: { | ||||
|           plugins: ['@nocobase/plugin-ui-schema-storage'], | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
| 
 | ||||
| @ -4,21 +4,26 @@ export default defineCollection({ | ||||
|   name: 'applications', | ||||
|   model: 'ApplicationModel', | ||||
|   autoGenId: false, | ||||
|   title: '{{t("Applications")}}', | ||||
|   sortable: 'sort', | ||||
|   createdBy: true, | ||||
|   fields: [ | ||||
|     { | ||||
|       type: 'string', | ||||
|       type: 'uid', | ||||
|       name: 'name', | ||||
|       primaryKey: true, | ||||
|       prefix: 'a', | ||||
|       interface: 'input', | ||||
|       uiSchema: { | ||||
|         type: 'string', | ||||
|         title: '{{t("Application name")}}', | ||||
|         'x-component': 'Input', | ||||
|         'x-read-pretty': true, | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       type: 'json', | ||||
|       name: 'options', | ||||
|     }, | ||||
|     { | ||||
|       type: 'hasMany', | ||||
|       name: 'plugins', | ||||
|       target: 'applicationPlugins', | ||||
|       foreignKey: 'applicationName', | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
							
								
								
									
										1
									
								
								packages/plugins/multi-app-manager/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/plugins/multi-app-manager/src/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| export { PluginMultiAppManager as default } from './server'; | ||||
| @ -8,10 +8,6 @@ interface registerAppOptions extends TransactionAble { | ||||
| } | ||||
| 
 | ||||
| export class ApplicationModel extends Model { | ||||
|   static getPluginByName(pluginName: string) { | ||||
|     return require(pluginName).default; | ||||
|   } | ||||
| 
 | ||||
|   static getDatabaseConfig(app: Application): IDatabaseOptions { | ||||
|     return lodash.cloneDeep( | ||||
|       lodash.isPlainObject(app.options.database) | ||||
| @ -23,15 +19,12 @@ export class ApplicationModel extends Model { | ||||
|   async registerToMainApp(mainApp: Application, options: registerAppOptions) { | ||||
|     const { transaction } = options; | ||||
|     const appName = this.get('name') as string; | ||||
|     const app = mainApp.appManager.createApplication(appName, ApplicationModel.initOptions(appName, mainApp)); | ||||
|     const appOptions = (this.get('options') as any) || {}; | ||||
| 
 | ||||
|     // @ts-ignore
 | ||||
|     const plugins = await this.getPlugins({ transaction }); | ||||
| 
 | ||||
|     for (const pluginInstance of plugins) { | ||||
|       const plugin = ApplicationModel.getPluginByName(pluginInstance.get('name') as string); | ||||
|       app.plugin(plugin); | ||||
|     } | ||||
|     const app = mainApp.appManager.createApplication(appName, { | ||||
|       ...ApplicationModel.initOptions(appName, mainApp), | ||||
|       ...appOptions, | ||||
|     }); | ||||
| 
 | ||||
|     app.on('beforeInstall', async function createDatabase() { | ||||
|       const { host, port, username, password, database, dialect } = ApplicationModel.getDatabaseConfig(app); | ||||
| @ -3,7 +3,7 @@ import { resolve } from 'path'; | ||||
| import { ApplicationModel } from './models/application'; | ||||
| import { AppManager } from '@nocobase/server'; | ||||
| 
 | ||||
| export class PluginMultipleApps extends Plugin { | ||||
| export class PluginMultiAppManager extends Plugin { | ||||
|   getName(): string { | ||||
|     return this.getPackageName(__dirname); | ||||
|   } | ||||
| @ -1,17 +0,0 @@ | ||||
| import { defineCollection } from '@nocobase/database'; | ||||
| 
 | ||||
| export default defineCollection({ | ||||
|   name: 'applicationPlugins', | ||||
|   timestamps: false, | ||||
|   fields: [ | ||||
|     { | ||||
|       type: 'string', | ||||
|       name: 'name', | ||||
|     }, | ||||
|     { | ||||
|       type: 'belongsTo', | ||||
|       name: 'application', | ||||
|       foreignKey: 'applicationName', | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| @ -14,7 +14,7 @@ Promise.all(packageDirs.map((d) => getDirectories(d))) | ||||
|   .then((res) => res.flat()) | ||||
|   .then((res) => | ||||
|     res.forEach((d) => { | ||||
|       exec(`cd ${d} && npm unpublish -f  && npm publish`, (error, stdout, stderr) => { | ||||
|       exec(`cd ${d} && npm unpublish -f; npm publish`, (error, stdout, stderr) => { | ||||
|         if (error) { | ||||
|           console.log(`error: ${error.message}`); | ||||
|           return; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user