Skip to content

Commit

Permalink
feat: add debug url output
Browse files Browse the repository at this point in the history
  • Loading branch information
czy88840616 committed Oct 16, 2024
1 parent be0b328 commit 3821ef9
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 0 deletions.
33 changes: 33 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ const path = require('path');
const { replaceTscAliasPaths } = require('tsc-alias');
const chokidar = require('chokidar');
const fs = require('fs');
const { startProxyServer } = require('./proxy');

function run() {
const { cmdPath, tscArgs, parentArgs, childArgs } = parseArgs(process.argv);
const cwd = process.cwd();

const isCleanDirectory = parentArgs.includes('--cleanOutDir');
// 是否显式声明 --inspect 或者 --inspect-brk
const isInspect =
parentArgs.includes('--inspect') || parentArgs.includes('--inspect-brk');

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

Expand Down Expand Up @@ -51,6 +55,7 @@ function run() {
let tsconfig;
let hasPaths = false;
let tsconfigPath;
let sourceRoot;

const projectIndex = tscArgs.findIndex(
arg => arg === '--project' || arg === '-p'
Expand All @@ -69,6 +74,8 @@ function run() {
// 解析出来的 tsconfig.json 中的 allowJs 优先级更高
allowJs = tsconfig.options.allowJs;
sourceDir = getRelativeDir(cwd, tsconfig.options.rootDir) || sourceDir;
// 读取 sourceRoot 的变量
sourceRoot = tsconfig.options.sourceRoot;
// 判断是否需要启动 tsc-alias
hasPaths = !!(
tsconfig.options.paths && Object.keys(tsconfig.options.paths).length > 0
Expand All @@ -86,6 +93,21 @@ function run() {

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

// sourceRoot 是否符合 http://localhost:7788 或者 http://127.0.0.1:7788 或者 http://127.1:7788 类似格式
if (
isInspect &&
sourceRoot &&
/^http:\/\/(?:localhost|127\.(?:0\.0\.1|1)):\d+\/?$/.test(sourceRoot)
) {
// get port from sourceRoot
const port = parseInt(sourceRoot.split(':')[2]);
if (Number.isInteger(port)) {
// 启动一个本地文件代理服务器
proxyServer = startProxyServer(path.join(cwd, sourceDir), port);
}
}

if (isCleanDirectory) {
/**
Expand All @@ -102,6 +124,7 @@ function run() {
debug(`allowJs: ${allowJs}`);
debug(`tsconfig: ${tsconfigPath}`);
debug(`hasPaths: ${hasPaths}`);
debug(`sourceRoot: ${sourceRoot}`);

let runChild;
const restart = debounce(async fileChangedList => {
Expand All @@ -124,6 +147,10 @@ function run() {
}

await Promise.all([runChild && runChild.kill(), aliasReplace()]);
// 清理代理文件缓存
if (proxyServer) {
proxyServer.clearCache();
}
debug('Fork new child process');
runChild && runChild.forkChild();
}, 1000);
Expand Down Expand Up @@ -242,6 +269,9 @@ function run() {
}
console.log('');
}
if (proxyServer) {
proxyServer.start();
}
triggerMessage('server-first-ready');
} else {
output('');
Expand Down Expand Up @@ -298,6 +328,9 @@ function run() {
if (runChild) {
await runChild.kill();
}
if (proxyServer) {
await proxyServer.close();
}
if (fileDeleteWatcher) {
await fileDeleteWatcher.close();
}
Expand Down
109 changes: 109 additions & 0 deletions lib/proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
const http = require('http');
const fs = require('fs');
const path = require('path');
const url = require('url');

/**
* 启动一个 HTTP 服务器来代理本地文件
* @param {number} port - 要监听的端口号
* @returns {Object} 包含控制服务器的方法
*/
function startProxyServer(root, port) {
let server;
const fileCache = {};

// 创建 HTTP 服务器
server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url);
// 获取文件路径
const filePath = path.join(root, parsedUrl.pathname);
// 设置跨域头
res.setHeader('Access-Control-Allow-Origin', '*');

// 检查缓存中是否存在文件
if (fileCache[filePath]) {
res.setHeader('Content-type', getMimeType(path.extname(filePath)) || 'text/plain');
res.end(fileCache[filePath]);
return;
}

// 检查文件是否存在
fs.exists(filePath, exists => {
if (!exists) {
res.statusCode = 404;
res.end(`File ${filePath} not found!`);
return;
}

// 读取文件并缓存
fs.readFile(filePath, (err, data) => {
if (err) {
res.statusCode = 500;
res.end(`Error getting the file: ${err}.`);
} else {
// 缓存文件内容
fileCache[filePath] = data;
// 设置适当的 Content-Type
const ext = path.parse(filePath).ext;
res.setHeader('Content-type', getMimeType(ext) || 'text/plain');
res.end(data);
}
});
});
});

// 返回控制方法
return {
start: () => {
return new Promise((resolve, reject) => {
server.listen(port, err => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
},
close: () => {
return new Promise((resolve, reject) => {
if (server) {
server.close(err => {
if (err) {
reject(err);
} else {
resolve();
}
});
} else {
resolve();
}
});
},
clearCache: () => {
Object.keys(fileCache).forEach(key => {
delete fileCache[key];
});
},
};
}

// 获取文件的 MIME 类型
function getMimeType(ext) {
const mimeTypes = {
'.js': 'application/javascript',
'.ts': 'application/typescript',
'.json': 'application/json',
'.map': 'application/json',
'.html': 'text/html',
'.css': 'text/css',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
};

return mimeTypes[ext];
}

module.exports = { startProxyServer };
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"devDependencies": {
"jest": "^29.7.0",
"mwts": "^1.3.0",
"node-fetch": "^2.7.0",
"typescript": "^5.4.5"
},
"engines": {
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/test_proxy/run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.send({ type: 'ready' });
1 change: 1 addition & 0 deletions test/fixtures/test_proxy/src/a.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class Test {}
17 changes: 17 additions & 0 deletions test/fixtures/test_proxy/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compileOnSave": true,
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"sourceRoot": "http://127.1:7788",
"outDir": "dist",
"rootDir": "src"
},
"exclude": [
"dist",
"node_modules",
"test"
]
}
37 changes: 37 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { unlink } = require('fs/promises');
const { existsSync, writeFileSync, readFileSync } = require('fs');
const { forkRun } = require('../lib/process');
const { execa, sleep, removeFile } = require('./util');
const fetch = require('node-fetch');

const mtscPath = join(__dirname, '../bin/mwtsc.js');

Expand Down Expand Up @@ -288,4 +289,40 @@ describe('/test/index.js', () => {
});
});
});

it.skip('should test sourcemap proxy server', async () => {
const runPath = join(__dirname, 'fixtures/test_proxy');
await removeFile([
join(runPath, 'dist/a.js'),
join(runPath, 'dist/a.js.map'),
]);

const cp = await execa('node', [mtscPath, '--watch', '--inspect', '--run', './run.js'], {
cwd: runPath,
});

await sleep(1000);

const res = await fetch('http://localhost:7788/a.ts');
expect(res.status).toBe(200);

const res1 = await fetch('http://localhost:7788/a.js.map');
expect(res1.status).toBe(200);

await new Promise((resolve, reject) => {
cp.on('exit', code => {
try {
expect(existsSync(join(runPath, 'dist/a.js'))).toBeTruthy();
expect(existsSync(join(runPath, 'dist/a.js.map'))).toBeTruthy();
resolve();
} catch (err) {
reject(err);
}
});

setTimeout(() => {
cp.kill();
}, 3000);
});
});
});

0 comments on commit 3821ef9

Please sign in to comment.