diff --git a/package.json b/package.json index 61c0f24..c803644 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "quick:test": "cross-env NODE_DEBUG=adonisjs:assembler node --enable-source-maps --loader=ts-node/esm bin/test.ts" }, "devDependencies": { - "@adonisjs/application": "8.1.0", + "@adonisjs/application": "8.2.1", "@adonisjs/eslint-config": "^1.3.0", "@adonisjs/prettier-config": "^1.3.0", "@adonisjs/tsconfig": "^1.3.0", diff --git a/src/dev_server.ts b/src/dev_server.ts index c3df7d0..ac7b18d 100644 --- a/src/dev_server.ts +++ b/src/dev_server.ts @@ -155,6 +155,12 @@ export class DevServer { }) this.#httpServer.on('message', async (message) => { + void this.#hooks.onHttpServerMessage({ colors: ui.colors, logger: this.#logger }, message, { + restartServer: () => { + this.#restartHTTPServer(port) + }, + }) + if (this.#isAdonisJSReadyMessage(message)) { const host = message.host === '0.0.0.0' ? '127.0.0.1' : message.host diff --git a/src/hooks.ts b/src/hooks.ts index 4b882dc..1e6576a 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -8,10 +8,11 @@ */ import { + RcFile, AssemblerHookNode, - SourceFileChangedHookHandler, AssemblerHookHandler, - RcFile, + HttpServerMessageHookHandler, + SourceFileChangedHookHandler, } from '@adonisjs/application/types' import { RuntimeException } from '@poppinss/utils' import Hooks from '@poppinss/hooks' @@ -20,10 +21,11 @@ export class AssemblerHooks { #config: RcFile['unstable_assembler'] #hooks = new Hooks<{ - onDevServerStarted: [Parameters, []] - onSourceFileChanged: [Parameters, []] onBuildStarting: [Parameters, []] onBuildCompleted: [Parameters, []] + onDevServerStarted: [Parameters, []] + onSourceFileChanged: [Parameters, []] + onHttpServerMessage: [Parameters, []] }>() constructor(config: RcFile['unstable_assembler']) { @@ -54,6 +56,9 @@ export class AssemblerHooks { ...(this.#config?.onSourceFileChanged || []).map(async (node) => this.#hooks.add('onSourceFileChanged', await this.#resolveHookNode(node)) ), + ...(this.#config?.onHttpServerMessage || []).map(async (node) => + this.#hooks.add('onHttpServerMessage', await this.#resolveHookNode(node)) + ), ]) } @@ -98,4 +103,11 @@ export class AssemblerHooks { async onBuildCompleted(...args: Parameters) { await this.#hooks.runner('onBuildCompleted').run(...args) } + + /** + * When a message is received from the HTTP server process + */ + async onHttpServerMessage(...args: Parameters) { + await this.#hooks.runner('onHttpServerMessage').run(...args) + } } diff --git a/src/types.ts b/src/types.ts index fbce209..6f8ea49 100644 --- a/src/types.ts +++ b/src/types.ts @@ -121,7 +121,7 @@ export type DevServerOptions = { */ hooks?: Pick< NonNullable, - 'onDevServerStarted' | 'onSourceFileChanged' + 'onDevServerStarted' | 'onSourceFileChanged' | 'onHttpServerMessage' > } diff --git a/tests/dev_server.spec.ts b/tests/dev_server.spec.ts index 6e3db9e..62558e6 100644 --- a/tests/dev_server.spec.ts +++ b/tests/dev_server.spec.ts @@ -137,4 +137,94 @@ test.group('DevServer', () => { await sleep(500) }).timeout(10_000) + + test('onHttpServerMessage hook should be executed', async ({ assert, fs, cleanup }) => { + let receivedMessages: any[] = [] + + await fs.createJson('tsconfig.json', { + include: ['**/*'], + exclude: [], + }) + await fs.create('index.ts', 'console.log("hey")') + await fs.create( + 'bin/server.js', + ` + process.send({ isAdonisJS: true, environment: 'web' }); + process.send({ type: 'http-server-message', message: 'hello' }); + ` + ) + await fs.create('.env', 'PORT=3334') + + const devServer = new DevServer(fs.baseUrl, { + assets: { enabled: false }, + nodeArgs: [], + scriptArgs: [], + hooks: { + onHttpServerMessage: [ + async () => ({ + default: (_, message, __) => { + receivedMessages.push(message) + }, + }), + ], + }, + }) + + await devServer.startAndWatch(ts) + cleanup(() => devServer.close()) + + await sleep(500) + + assert.deepEqual(receivedMessages, [ + { isAdonisJS: true, environment: 'web' }, + { type: 'http-server-message', message: 'hello' }, + ]) + }) + + test('can restart server from onHttpServerMessage hook', async ({ assert, fs, cleanup }) => { + let receivedMessages: any[] = [] + + await fs.createJson('tsconfig.json', { + include: ['**/*'], + exclude: [], + }) + await fs.create('index.ts', 'console.log("hey")') + await fs.create( + 'bin/server.js', + ` + process.send({ isAdonisJS: true, environment: 'web' }); + process.send({ type: 'restart' }); + ` + ) + await fs.create('.env', 'PORT=3334') + + let wasRestarted = false + + const devServer = new DevServer(fs.baseUrl, { + assets: { enabled: false }, + nodeArgs: [], + scriptArgs: [], + hooks: { + onHttpServerMessage: [ + async () => ({ + default: (_, message, { restartServer }) => { + receivedMessages.push(message) + + if (message.type === 'restart' && !wasRestarted) { + restartServer() + wasRestarted = true + } + }, + }), + ], + }, + }) + + await devServer.startAndWatch(ts) + cleanup(() => devServer.close()) + + await sleep(500) + + assert.deepEqual(receivedMessages.length, 4) + }) })