Skip to content

Commit

Permalink
feat: support inspect args
Browse files Browse the repository at this point in the history
  • Loading branch information
czy88840616 committed Oct 16, 2024
1 parent 16ad758 commit 821de2b
Show file tree
Hide file tree
Showing 4 changed files with 247 additions and 46 deletions.
22 changes: 14 additions & 8 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ const chokidar = require('chokidar');
const fs = require('fs');

function run() {
const [runCmd, tscArgs, runArgs, isCleanDirectory] = parseArgs(process.argv);
const { cmdPath, tscArgs, parentArgs, childArgs } = parseArgs(process.argv);
const cwd = process.cwd();

const isCleanDirectory = parentArgs.includes('--cleanOutDir');

debug(`main process running, pid = ${process.pid}`);

// 调试模式下
Expand All @@ -30,15 +32,18 @@ function run() {
}

// 添加 --listEmittedFiles 参数以便于获取编译后的文件列表
if (!tscArgs.includes('--listEmittedFiles') && !tscArgs.includes('--version')) {
if (
!tscArgs.includes('--listEmittedFiles') &&
!tscArgs.includes('--version')
) {
tscArgs.push('--listEmittedFiles');
}

debug(`cwd: ${cwd}`);
debug(`runCmd: ${runCmd}`);
debug(`cmdPath: ${cmdPath}`);
debug(`tscArgs: ${tscArgs}`);
debug(`runArgs: ${runArgs}`);
debug(`isCleanDirectory: ${isCleanDirectory}`);
debug(`parentArgs: ${parentArgs}`);
debug(`childArgs: ${childArgs}`);

let sourceDir = 'src';
let outDir;
Expand Down Expand Up @@ -80,7 +85,7 @@ function run() {
}

const baseDir = path.resolve(cwd, outDir);
runArgs.push('--baseDir', baseDir);
childArgs.push('--baseDir', baseDir);

if (isCleanDirectory) {
/**
Expand Down Expand Up @@ -189,9 +194,10 @@ function run() {
onFirstWatchCompileSuccess: () => {
runAfterTsc();
watchDeleteFile();
if (runCmd) {
runChild = forkRun(runCmd, runArgs, {
if (cmdPath) {
runChild = forkRun(cmdPath, childArgs, {
cwd,
parentArgs,
});
runChild.onServerReady(
async (serverReportOption, isFirstCallback, during) => {
Expand Down
34 changes: 31 additions & 3 deletions lib/process.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
const { fork, spawn } = require('child_process');
const { filterFileChangedText, debug, output, colors } = require('./util');
const {
filterFileChangedText,
debug,
output,
colors,
convertPosixToGnu,
} = require('./util');
const { CHILD_PROCESS_EXCEPTION_EXIT_CODE } = require('./constants');
const path = require('path');
const fs = require('fs');
Expand All @@ -20,7 +26,12 @@ const forkTsc = (tscArgs = [], options = {}) => {
let firstStarted = false;
let tscPath = isWin ? 'tsc.cmd' : 'tsc';

const localTscPath = path.join(process.cwd(), 'node_modules', '.bin', tscPath);
const localTscPath = path.join(
process.cwd(),
'node_modules',
'.bin',
tscPath
);
if (fs.existsSync(localTscPath)) {
tscPath = localTscPath;
}
Expand Down Expand Up @@ -99,6 +110,23 @@ const forkRun = (runCmdPath, runArgs = [], options = {}) => {

function innerFork(isFirstFork = false) {
const startTime = Date.now();

// 从 options.parentArgs 中获取需要的 execArgv,parentArgs 是 POSIX 风格,需要过滤后转成 GNU 风格
const filterExecArgv = ['--inspect', '--inspect-brk'];

// 先将所有 parentArgs 转换为 GNU 格式
const gnuStyleParentArgs = convertPosixToGnu(options.parentArgs);

// 过滤出需要的参数
const requiredExecArgv = gnuStyleParentArgs.filter(arg =>
filterExecArgv.some(filterArg => arg.startsWith(filterArg))
);

// 准备 execArgv
const execArgv = process.execArgv
.concat(['-r', 'source-map-support/register'])
.concat(requiredExecArgv);

runChild = fork('wrap.js', runArgs, {
stdio: 'inherit',
cwd: __dirname,
Expand All @@ -108,7 +136,7 @@ const forkRun = (runCmdPath, runArgs = [], options = {}) => {
MWTSC_DEVELOPMENT_ENVIRONMENT: 'true',
...process.env,
},
execArgv: process.execArgv.concat(['-r', 'source-map-support/register']),
execArgv: execArgv,
});
debug(`fork run process, pid = ${runChild.pid}`);
const onServerReady = async data => {
Expand Down
111 changes: 86 additions & 25 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,100 @@ const { run } = require('@midwayjs/glob');
const { debuglog } = require('util');
const debug = debuglog('midway:debug');

exports.parseArgs = argv => {
// 去除头两位参数
let pargs = argv.slice(2);

// 是否清理目录
let isCleanDirectory = false;
if (pargs.includes('--cleanOutDir')) {
isCleanDirectory = true;
// 移除 --cleanOutDir 命令
pargs.splice(
pargs.findIndex(arg => arg === '--cleanOutDir'),
1
);
/**
* 将 POSIX 风格的参数转换为 GNU 风格
* @param {string[]} args POSIX 风格的参数数组
* @return {string[]} GNU 风格的参数数组
*/
exports.convertPosixToGnu = (args) => {
const gnuArgs = [];
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg.startsWith('--') && i + 1 < args.length && !args[i + 1].startsWith('--')) {
// 如果当前参数以 -- 开头,且下一个参数不以 -- 开头,则将它们合并
gnuArgs.push(`${arg}=${args[i + 1]}`);
i++; // 跳过下一个参数,因为已经合并了
} else {
gnuArgs.push(arg);
}
}
return gnuArgs;
};

// 找到 --run 命令以及后面的所有参数
const runIndex = pargs.findIndex(arg => arg === '--run');
exports.parseArgs = argv => {
// 去除前两个参数(通常是 node 和脚本名)
const args = argv.slice(2);

const result = {
cmdPath: undefined,
tscArgs: [],
parentArgs: [],
childArgs: [],
};

if (runIndex === -1) {
return [undefined, pargs, [], isCleanDirectory];
}
const notTscArgPrefixes = ['--cleanOutDir', '--inspect', '--inspect-brk'];

// 分出 --run,后一个路径,以及剩余的其他参数
const runArgs = pargs.slice(runIndex + 1);
// 将 GNU 风格的参数转换为 POSIX 风格
const convertToPosixStyle = args => {
const posixArgs = [];
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg.includes('=') && arg.startsWith('--')) {
const [key, value] = arg.split('=');
posixArgs.push(key, value);
} else {
posixArgs.push(arg);
}
}
return posixArgs;
};

// 简单约定,--run 后面的参数都是给子进程的
const [runCmdPath, ...runChildArgs] = runArgs;
// 检查参数是否属于 notTscArgs
const isNotTscArg = arg => {
return notTscArgPrefixes.some(prefix => arg.startsWith(prefix));
};

// 处理转换后的参数
const processArgs = args => {
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (isNotTscArg(arg)) {
result.parentArgs.push(arg);
// 如果下一个参数不是以 -- 开头,认为它是当前参数的值
if (i + 1 < args.length && !args[i + 1].startsWith('--')) {
result.parentArgs.push(args[i + 1]);
i++;
}
} else if (
arg.startsWith('--') &&
i + 1 < args.length &&
!args[i + 1].startsWith('--')
) {
// 处理 key value 格式
result.tscArgs.push(arg, args[i + 1]);
i++; // 跳过下一个参数,因为它是当前参数的值
} else {
result.tscArgs.push(arg);
}
}
};

const posixArgs = convertToPosixStyle(args);
const runIndex = posixArgs.indexOf('--run');

// 从 pargs 中移除 --run 命令后面所有参数
if (runIndex !== -1) {
pargs = pargs.slice(0, runIndex);
// 提取 --run 后面的参数作为子进程参数
result.cmdPath = posixArgs[runIndex + 1];
result.childArgs = posixArgs.slice(runIndex + 2);

// 处理 --run 前面的参数
processArgs(posixArgs.slice(0, runIndex));
} else {
// 如果没有 --run,处理所有参数
processArgs(posixArgs);
}
return [runCmdPath, pargs, runChildArgs, isCleanDirectory];

return result;
};

exports.debounce = function (func, wait, immediate = false) {
Expand Down
126 changes: 116 additions & 10 deletions test/util.test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,123 @@
const { parseArgs, deleteFolderRecursive, copyFilesRecursive, readJSONCFile, filterFileChangedText } = require('../lib/util');
const { parseArgs, deleteFolderRecursive, copyFilesRecursive, readJSONCFile, filterFileChangedText, convertPosixToGnu } = require('../lib/util');
const fs = require('fs');
const path = require('path')

describe('test/util.test.js', () => {
it('should parse', () => {
expect(parseArgs(['node', 'tsc'])).toEqual([undefined, [], [], false]);
expect(parseArgs(['node', 'tsc', '--watch'])).toEqual([undefined, ['--watch'], [], false]);
expect(parseArgs(['node', 'tsc', '--watch', '--run', 'index.js'])).toEqual(['index.js', ['--watch'], [], false]);
expect(parseArgs(['node', 'tsc', '--watch', '--run', 'index.js', '--', '--port', '3000'])).toEqual(['index.js', ['--watch'], ['--', '--port', '3000'], false]);
expect(parseArgs(['node', 'tsc', '--watch', '--project', 'tsconfig.prod.json'])).toEqual([undefined, ['--watch', '--project', 'tsconfig.prod.json'], [], false]);
expect(parseArgs(['node', 'tsc', '--watch', '--run'])).toEqual([undefined, ['--watch'], [], false]);
expect(parseArgs(['node', 'tsc', '--cleanOutDir'])).toEqual([undefined, [], [], true]);
expect(parseArgs(['node', 'tsc', '--watch', '--cleanOutDir', '--build', '--run'])).toEqual([undefined, ['--watch', '--build'], [], true]);
describe('parseArgs', () => {
it('should correctly parse basic arguments', () => {
const result = parseArgs(['node', 'mwtsc', '--watch', '--project', 'tsconfig.production.json']);
expect(result).toEqual({
cmdPath: undefined,
tscArgs: ['--watch', '--project', 'tsconfig.production.json'],
parentArgs: [],
childArgs: []
});
});

it('should correctly parse arguments with --run', () => {
const result = parseArgs(['node', 'mwtsc', '--watch', '--project', 'tsconfig.production.json', '--run', './bootstrap.js', '--port', '3000']);
expect(result).toEqual({
cmdPath: './bootstrap.js',
tscArgs: ['--watch', '--project', 'tsconfig.production.json'],
parentArgs: [],
childArgs: ['--port', '3000']
});
});

it('should correctly handle notTscArgs', () => {
const result = parseArgs(['node', 'mwtsc', '--watch', '--cleanOutDir', '--inspect', '9229', '--project', 'tsconfig.json', '--run', './app.js']);
expect(result).toEqual({
cmdPath: './app.js',
tscArgs: ['--watch', '--project', 'tsconfig.json'],
parentArgs: ['--cleanOutDir', '--inspect', '9229'],
childArgs: []
});
});

it('should correctly handle GNU-style arguments', () => {
const result = parseArgs(['node', 'mwtsc', '--watch', '--port=3000', '--inspect-brk=9230', '--run', './app.js', '--env=production']);
expect(result).toEqual({
cmdPath: './app.js',
tscArgs: ['--watch', '--port', '3000'],
parentArgs: ['--inspect-brk', '9230'],
childArgs: ['--env', 'production']
});
});

it('should correctly handle POSIX-style arguments', () => {
const result = parseArgs(['node', 'mwtsc', '--watch', '--port', '3000', '--inspect-brk', '9230', '--run', './app.js', '--env', 'production']);
expect(result).toEqual({
cmdPath: './app.js',
tscArgs: ['--watch', '--port', '3000'],
parentArgs: ['--inspect-brk', '9230'],
childArgs: ['--env', 'production']
});
});

it('should correctly handle mixed-style arguments', () => {
const result = parseArgs(['node', 'mwtsc', '--watch', '--port', '3000', '--outDir=./dist', '--cleanOutDir', '--inspect=9229', '--run', './app.js']);
expect(result).toEqual({
cmdPath: './app.js',
tscArgs: ['--watch', '--port', '3000', '--outDir', './dist'],
parentArgs: ['--cleanOutDir', '--inspect', '9229'],
childArgs: []
});
});

it('should correctly handle Node.js inspect arguments without value', () => {
const result = parseArgs(['node', 'mwtsc', '--watch', '--inspect', '--run', './app.js']);
expect(result).toEqual({
cmdPath: './app.js',
tscArgs: ['--watch'],
parentArgs: ['--inspect'],
childArgs: []
});
});

it('should correctly handle Node.js inspect arguments with port', () => {
const result = parseArgs(['node', 'mwtsc', '--watch', '--inspect=9229', '--run', './app.js']);
expect(result).toEqual({
cmdPath: './app.js',
tscArgs: ['--watch'],
parentArgs: ['--inspect', '9229'],
childArgs: []
});
});

it('should correctly handle Node.js inspect-brk arguments', () => {
const result = parseArgs(['node', 'mwtsc', '--watch', '--inspect-brk=0.0.0.0:9229', '--run', './app.js']);
expect(result).toEqual({
cmdPath: './app.js',
tscArgs: ['--watch'],
parentArgs: ['--inspect-brk', '0.0.0.0:9229'],
childArgs: []
});
});
});

describe('convertPosixToGnu', () => {
it('should convert POSIX-style arguments to GNU-style', () => {
const posixArgs = ['--watch', '--port', '3000', '--inspect', '9229', '--outDir', './dist'];
const expectedGnuArgs = ['--watch', '--port=3000', '--inspect=9229', '--outDir=./dist'];
expect(convertPosixToGnu(posixArgs)).toEqual(expectedGnuArgs);
});

it('should handle arguments without values correctly', () => {
const posixArgs = ['--watch', '--cleanOutDir', '--port', '3000'];
const expectedGnuArgs = ['--watch', '--cleanOutDir', '--port=3000'];
expect(convertPosixToGnu(posixArgs)).toEqual(expectedGnuArgs);
});

it('should not change already GNU-style arguments', () => {
const gnuArgs = ['--watch', '--port=3000', '--inspect=9229'];
expect(convertPosixToGnu(gnuArgs)).toEqual(gnuArgs);
});

it('should handle mixed POSIX and GNU-style arguments', () => {
const mixedArgs = ['--watch', '--port', '3000', '--inspect=9229', '--outDir', './dist'];
const expectedGnuArgs = ['--watch', '--port=3000', '--inspect=9229', '--outDir=./dist'];
expect(convertPosixToGnu(mixedArgs)).toEqual(expectedGnuArgs);
});
});

describe('deleteFolderRecursive', () => {
Expand Down

0 comments on commit 821de2b

Please sign in to comment.