UNPKG

2.75 kBJavaScriptView Raw
1#!/usr/bin/env node
2const { fork } = require('child_process');
3const parse = require('yargs-parser');
4const chokidar = require('chokidar');
5const detect = require('detect-port');
6const path = require('path');
7const log = require('../lib/utils/log');
8
9let child = null;
10const rawArgv = parse(process.argv.slice(2));
11const scriptPath = require.resolve('./child-process-start.js');
12const configPath = path.resolve(rawArgv.config || 'build.json');
13
14const inspectRegExp = /^--(inspect(?:-brk)?)(?:=(?:([^:]+):)?(\d+))?$/;
15
16async function modifyInspectArgv(execArgv, processArgv) {
17 /**
18 * Enable debugger by exec argv, eg. node --inspect node_modules/.bin/build-scripts start
19 * By this way, there will be two inspector, because start.js is run as a child process.
20 * So need to handle the conflict of port.
21 */
22 const result = await Promise.all(
23 execArgv.map(async item => {
24 const matchResult = inspectRegExp.exec(item);
25 if (!matchResult) {
26 return item;
27 }
28 const [_, command, ip, port = 9229] = matchResult;
29 const nPort = +port;
30 const newPort = await detect(nPort);
31 return `--${command}=${ip ? `${ip}:` : ''}${newPort}`
32 })
33 );
34
35 /**
36 * Enable debugger by process argv, eg. npm run start --inspect
37 * Need to change it as an exec argv.
38 */
39 if (processArgv.inspect) {
40 const matchResult = /(?:([^:]+):)?(\d+)/.exec(rawArgv.inspect);
41 let [_, ip, port = 9229] = matchResult || [];
42 const newPort = await detect(port);
43 result.push(`--inspect=${ip ? `${ip}:` : ''}${newPort}`);
44 }
45
46 return result;
47}
48
49function restartProcess() {
50 (async () => {
51 // remove the inspect related argv when passing to child process to avoid port-in-use error
52 const execArgv = await modifyInspectArgv(process.execArgv, rawArgv);
53
54 // filter inspect in process argv, it has been comsumed
55 const nProcessArgv = process.argv.slice(2).filter((arg) => arg.indexOf('--inspect') === -1);
56 child = fork(scriptPath, nProcessArgv, { execArgv });
57 child.on('message', data => {
58 if (process.send) {
59 process.send(data);
60 }
61 });
62
63 child.on('exit', code => {
64 if (code) {
65 process.exit(code);
66 }
67 });
68 })();
69}
70
71const onUserChange = () => {
72 console.log('\n');
73 log.info('build.json has been changed');
74 log.info('restart dev server');
75 // add process env for mark restart dev process
76 process.env.RESTART_DEV = true;
77 child.kill();
78 restartProcess();
79};
80
81module.exports = () => {
82 restartProcess();
83
84 const watcher = chokidar.watch(configPath, {
85 ignoreInitial: true,
86 });
87
88 watcher.on('change', onUserChange);
89
90 watcher.on('error', error => {
91 log.error('fail to watch file', error);
92 process.exit(1);
93 });
94};