diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 85c03b0f9..d9ea9e6e7 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -4,22 +4,22 @@ import { middlewares } from '@nocobase/server'; (async () => { api.resourcer.use(middlewares.actionParams()); - await api.loadPlugins(); - - if (process.env.NOCOBASE_ENV === 'demo') { - api.resourcer.use(middlewares.demoBlacklistedActions({ - emails: [process.env.ADMIN_EMAIL], + api.on('plugins.afterLoad', async () => { + console.log('plugins.afterLoad') + if (process.env.NOCOBASE_ENV === 'demo') { + api.resourcer.use(middlewares.demoBlacklistedActions({ + emails: [process.env.ADMIN_EMAIL], + })); + } + api.use(middlewares.appDistServe({ + root: process.env.APP_DIST, + useStaticServer: !(process.env.APP_USE_STATIC_SERVER === 'false' || !process.env.APP_USE_STATIC_SERVER), })); - } - - api.use(middlewares.appDistServe({ - root: process.env.APP_DIST, - useStaticServer: !(process.env.APP_USE_STATIC_SERVER === 'false' || !process.env.APP_USE_STATIC_SERVER), - })); - - await api.database.getModel('collections').load(); - - api.listen(process.env.API_PORT, () => { - console.log(`http://localhost:${process.env.API_PORT}/`); }); + + const start = Date.now(); + await api.start(process.env.API_PORT); + console.log(api.database.getTables().map(t => t.getName())); + console.log(`Start-up time: ${(Date.now() - start) / 1000}s`); + console.log(`http://localhost:${process.env.API_PORT}/`); })(); diff --git a/packages/plugin-collections/src/server.ts b/packages/plugin-collections/src/server.ts index 08b1a7df2..005a545d5 100644 --- a/packages/plugin-collections/src/server.ts +++ b/packages/plugin-collections/src/server.ts @@ -11,6 +11,10 @@ export default async function (this: Application, options = {}) { database.import({ directory: path.resolve(__dirname, 'collections'), }); + this.on('server.beforeStart', async () => { + console.log('server.beforeStart'); + await database.getModel('collections').load(); + }); const [Collection, Field] = database.getModels(['collections', 'fields']); Field.beforeCreate(async (model) => { if (!model.get('name')) { diff --git a/packages/server/src/application.ts b/packages/server/src/application.ts index 32f5dd687..7326ca202 100644 --- a/packages/server/src/application.ts +++ b/packages/server/src/application.ts @@ -23,6 +23,60 @@ export class Application extends Koa { // this.runHook('afterInit'); } + async emitAsync(event: string | symbol, ...args: any[]): Promise { + // @ts-ignore + const events = this._events; + let callbacks = events[event]; + if (!callbacks) { + return false; + } + // helper function to reuse as much code as possible + const run = (cb) => { + switch (args.length) { + // fast cases + case 0: + cb = cb.call(this); + break; + case 1: + cb = cb.call(this, args[0]); + break; + case 2: + cb = cb.call(this, args[0], args[1]); + break; + case 3: + cb = cb.call(this, args[0], args[1], args[2]); + break; + // slower + default: + cb = cb.apply(this, args); + } + + if ( + cb && ( + cb instanceof Promise || + typeof cb.then === 'function' + ) + ) { + return cb; + } + + return Promise.resolve(true); + }; + + if (typeof callbacks === 'function') { + await run(callbacks); + } else if (typeof callbacks === 'object') { + callbacks = callbacks.slice().filter(Boolean); + await callbacks.reduce((prev, next) => { + return prev.then((res) => { + return run(next).then((result) => Promise.resolve(res.concat(result))); + }); + }, Promise.resolve([])); + } + + return true; + } + registerPlugin(key: string | object, plugin?: any) { if (typeof key === 'object') { Object.keys(key).forEach((k) => { @@ -46,10 +100,18 @@ export class Application extends Koa { } async loadPlugins() { + await this.emitAsync('plugins.beforeLoad'); const allPlugins = this.plugins.values(); for (const plugin of allPlugins) { plugin.instance = await this.loadPlugin(plugin); } + await this.emitAsync('plugins.afterLoad'); + } + + async start(port) { + await this.loadPlugins(); + await this.emitAsync('server.beforeStart'); + this.listen(port); } protected async loadPlugin({ entry, options = {} }: { entry: string | Function, options: any }) {