Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support on-event command for watch changes #571

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ You can pass the following options via CLI arguments. You can also use `--config
| Set the inspector host to listen on (default: loopback address or `0.0.0.0` inside Docker) | | `--debug-host` | `FASTIFY_DEBUG_HOST` |
| Prints pretty logs | `-P` | `--pretty-logs` | `FASTIFY_PRETTY_LOGS` |
| Watch process.cwd() directory for changes, recursively; when that happens, the process will auto reload | `-w` | `--watch` | `FASTIFY_WATCH` |
| When watch triggers a restart, run a command. | `-e` | `--on-watch-event` | `FASTIFY_ON_WATCH_EVENT ` |
| Ignore changes to the specified files or directories when watch is enabled. (e.g. `--ignore-watch='node_modules .git logs/error.log'` ) | | `--ignore-watch` | `FASTIFY_IGNORE_WATCH` |
| Prints events triggered by watch listener (useful to debug unexpected reload when using `--watch` ) | `-V` | `--verbose-watch` | `FASTIFY_VERBOSE_WATCH` |
| Use custom options | `-o` | `--options` | `FASTIFY_OPTIONS` |
Expand Down
5 changes: 4 additions & 1 deletion args.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const DEFAULT_ARGUMENTS = {
prettyLogs: false,
watch: false,
verboseWatch: false,
onWatchEvent: '',
debug: false,
debugPort: 9320,
options: false,
Expand All @@ -27,7 +28,7 @@ module.exports = function parseArgs (args) {
'populate--': true
},
number: ['port', 'inspect-port', 'body-limit', 'plugin-timeout', 'close-grace-delay'],
string: ['log-level', 'address', 'socket', 'prefix', 'ignore-watch', 'logging-module', 'debug-host', 'lang', 'require', 'config'],
string: ['log-level', 'address', 'socket', 'prefix', 'ignore-watch', 'on-watch-event', 'logging-module', 'debug-host', 'lang', 'require', 'config'],
boolean: ['pretty-logs', 'options', 'watch', 'verbose-watch', 'debug', 'standardlint'],
envPrefix: 'FASTIFY_',
alias: {
Expand All @@ -41,6 +42,7 @@ module.exports = function parseArgs (args) {
prefix: ['x'],
require: ['r'],
debug: ['d'],
'on-watch-event': ['e'],
'debug-port': ['I'],
'log-level': ['l'],
'pretty-logs': ['P'],
Expand Down Expand Up @@ -81,6 +83,7 @@ module.exports = function parseArgs (args) {
debugHost: parsedArgs.debugHost,
ignoreWatch,
verboseWatch: parsedArgs.verboseWatch,
onWatchEvent: parsedArgs.onWatchEvent,
logLevel: parsedArgs.logLevel,
address: parsedArgs.address,
socket: parsedArgs.socket,
Expand Down
4 changes: 4 additions & 0 deletions help/start.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ OPTS
[env: FASTIFY_WATCH]
Watch process.cwd() directory for changes, recursively; when that happens, the process will auto reload.

-e, --on-watch-event
[env: FASTIFY_ON_WATCH_EVENT]
When watch triggers a restart, run a command.

-x, --prefix
[env: FASTIFY_PREFIX]
Set the prefix
Expand Down
7 changes: 7 additions & 0 deletions lib/watch/fork.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict'

const { execSync } = require('child_process')
const chalk = require('chalk')
const { stop, runFastify } = require('../../start')

Expand Down Expand Up @@ -37,6 +38,12 @@ process.on('uncaughtException', (err) => {
})

const main = async () => {

if (process.env.onWatchEvent) {
const output = execSync(process.env.onWatchEvent).toString()
process.send(output)
}

fastify = await runFastify(process.argv.splice(2))
const type = process.env.childEvent

Expand Down
8 changes: 5 additions & 3 deletions lib/watch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const EventEmitter = require('events')
const chokidar = require('chokidar')
const forkPath = path.join(__dirname, './fork.js')

const watch = function (args, ignoreWatch, verboseWatch) {
const watch = function (args, ignoreWatch, verboseWatch, onWatchEvent) {
const emitter = new EventEmitter()
let allStop = false
let childs = []
Expand Down Expand Up @@ -38,12 +38,13 @@ const watch = function (args, ignoreWatch, verboseWatch) {
let readyEmitted = false

const run = (event) => {
const childEvent = { childEvent: event }
const childEvent = { childEvent: event, onWatchEvent }
const env = Object.assign({}, require('dotenv').config().parsed, process.env, childEvent)
const _child = cp.fork(forkPath, args, {
env,
cwd: process.cwd(),
encoding: 'utf8'
encoding: 'utf8',
stdio: 'inherit'
})

_child.on('exit', function (code, signal) {
Expand Down Expand Up @@ -106,6 +107,7 @@ const watch = function (args, ignoreWatch, verboseWatch) {
})

emitter.stop = stop.bind(null, watcher)
emitter.childs = childs

return emitter
}
Expand Down
2 changes: 1 addition & 1 deletion start.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ async function start (args) {
loadModules(opts)

if (opts.watch) {
return watch(args, opts.ignoreWatch, opts.verboseWatch)
return watch(args, opts.ignoreWatch, opts.verboseWatch, opts.onWatchEvent)
}

return runFastify(args)
Expand Down
14 changes: 13 additions & 1 deletion test/args.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ test('should parse args correctly', t => {
'--log-level', 'info',
'--pretty-logs', 'true',
'--watch', 'true',
'--on-watch-event', 'echo changed',
'--ignore-watch', 'ignoreme.js',
'--verbose-watch', 'true',
'--options', 'true',
Expand All @@ -34,6 +35,7 @@ test('should parse args correctly', t => {
prettyLogs: true,
options: true,
watch: true,
onWatchEvent: 'echo changed',
ignoreWatch: 'node_modules build dist .git bower_components logs .swp .nyc_output ignoreme.js',
verboseWatch: true,
port: 7777,
Expand Down Expand Up @@ -65,6 +67,7 @@ test('should parse args with = assignment correctly', t => {
'--log-level=info',
'--pretty-logs=true',
'--watch=true',
'--on-watch-event="echo changed"',
'--ignore-watch=ignoreme.js',
'--verbose-watch=true',
'--options=true',
Expand All @@ -86,6 +89,7 @@ test('should parse args with = assignment correctly', t => {
prettyLogs: true,
options: true,
watch: true,
onWatchEvent: 'echo changed',
ignoreWatch: 'node_modules build dist .git bower_components logs .swp .nyc_output ignoreme.js',
verboseWatch: true,
port: 7777,
Expand Down Expand Up @@ -116,6 +120,7 @@ test('should parse env vars correctly', t => {
process.env.FASTIFY_LOG_LEVEL = 'info'
process.env.FASTIFY_PRETTY_LOGS = 'true'
process.env.FASTIFY_WATCH = 'true'
process.env.FASTIFY_ON_WATCH_EVENT = 'echo changed'
process.env.FASTIFY_IGNORE_WATCH = 'ignoreme.js'
process.env.FASTIFY_VERBOSE_WATCH = 'true'
process.env.FASTIFY_OPTIONS = 'true'
Expand All @@ -136,6 +141,7 @@ test('should parse env vars correctly', t => {
delete process.env.FASTIFY_LOG_LEVEL
delete process.env.FASTIFY_PRETTY_LOGS
delete process.env.FASTIFY_WATCH
delete process.env.FASTIFY_ON_WATCH_EVENT
delete process.env.FASTIFY_IGNORE_WATCH
delete process.env.FASTIFY_VERBOSE_WATCH
delete process.env.FASTIFY_OPTIONS
Expand All @@ -156,6 +162,7 @@ test('should parse env vars correctly', t => {
prettyLogs: true,
options: true,
watch: true,
onWatchEvent: 'echo changed',
ignoreWatch: 'node_modules build dist .git bower_components logs .swp .nyc_output ignoreme.js',
verboseWatch: true,
address: 'fastify.io:9999',
Expand All @@ -177,7 +184,7 @@ test('should parse env vars correctly', t => {
})

test('should respect default values', t => {
t.plan(13)
t.plan(14)

const argv = [
'app.js'
Expand All @@ -189,6 +196,7 @@ test('should respect default values', t => {
t.equal(parsedArgs.options, false)
t.equal(parsedArgs.prettyLogs, false)
t.equal(parsedArgs.watch, false)
t.equal(parsedArgs.onWatchEvent, '')
t.equal(parsedArgs.ignoreWatch, 'node_modules build dist .git bower_components logs .swp .nyc_output')
t.equal(parsedArgs.verboseWatch, false)
t.equal(parsedArgs.logLevel, 'fatal')
Expand All @@ -211,6 +219,7 @@ test('should parse custom plugin options', t => {
'--log-level', 'info',
'--pretty-logs', 'true',
'--watch', 'true',
'--on-watch-event', 'echo changed',
'--ignore-watch', 'ignoreme.js',
'--verbose-watch', 'true',
'--options', 'true',
Expand Down Expand Up @@ -239,6 +248,7 @@ test('should parse custom plugin options', t => {
prettyLogs: true,
options: true,
watch: true,
onWatchEvent: 'echo changed',
ignoreWatch: 'node_modules build dist .git bower_components logs .swp .nyc_output ignoreme.js',
verboseWatch: true,
port: 7777,
Expand Down Expand Up @@ -284,6 +294,7 @@ test('should parse config file correctly and prefer config values over default o
prettyLogs: true,
options: false,
watch: true,
onWatchEvent: '',
debug: false,
debugPort: 4000,
debugHost: '1.1.1.1',
Expand Down Expand Up @@ -323,6 +334,7 @@ test('should prefer command line args over config file options', t => {
prettyLogs: true,
options: false,
watch: true,
onWatchEvent: '',
debug: false,
debugPort: 9320,
debugHost: '1.1.1.1',
Expand Down
15 changes: 13 additions & 2 deletions test/start.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ test('should start the server with watch options that the child process restart
})

test('should start the server with watch and verbose-watch options that the child process restart when directory changed with console message about changes ', { skip: process.platform === 'win32' }, async (t) => {
t.plan(4)
t.plan(5)

const spy = sinon.spy()
const watch = proxyquire('../lib/watch', {
Expand All @@ -582,7 +582,7 @@ test('should start the server with watch and verbose-watch options that the chil
const port = getPort()

await writeFile(tmpjs, 'hello world')
const argv = ['-p', port, '-w', '--verbose-watch', './examples/plugin.js']
const argv = ['-p', port, '-w', '--verbose-watch', '--on-watch-event="echo changed"', './examples/plugin.js']
const fastifyEmitter = await start.start(argv)

t.teardown(async () => {
Expand All @@ -592,12 +592,23 @@ test('should start the server with watch and verbose-watch options that the chil
await fastifyEmitter.stop()
})

// listen for any of the forked processes messages
const onChanges = new Promise((resolve, reject) => {
for (const child of fastifyEmitter.childs) {
child.on('message', resolve)
setTimeout(reject, 300)
}
})

await once(fastifyEmitter, 'ready')
t.pass('should receive ready event')

await writeFile(tmpjs, 'hello fastify', { flag: 'a+' }) // chokidar watch can't catch change event in CI, but local test is all ok. you can remove annotation in local environment.
t.pass('change tmpjs')

const message = await onChanges
t.ok(message.includes('changed'), 'forked process sends "changed" message')

// this might happen more than once but does not matter in this context
await once(fastifyEmitter, 'restart')
t.pass('should receive restart event')
Expand Down