V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
oyps
V2EX  ›  程序员

遇到一个神奇的 Bug

  •  
  •   oyps ·
    oyps · 98 天前 · 1463 次点击
    这是一个创建于 98 天前的主题,其中的信息可能已经有所发展或是发生改变。

    首先安装 3 个东西:

    npm i concurrently tsx mysql2
    

    现在创建 xxx.ts 或者 xxx.js:

    import { Charsets } from 'mysql2'
    // 从 mysql2 里面任意导入一个对象
    console.log(Charsets == null)
    

    发生了如下现象:

    • [正常]    运行 tsx xxx.ts,正常输出 false
    • [正常]    运行 tsx watch xxx.ts,正常输出 false
    • [正常]    运行 concurrently "tsx xxx.ts",正常输出 [0] false
    • [错误]    运行 concurrently "tsx watch xxx.ts",卡死了,无任何输出

    也就是说,concurrently + tsx watch + mysql2 == 卡死?

    有没有大佬知道这是怎么回事的。

    非常好复现的 Bug ,请看小视频演示: https://files.imdodo.com/dodo/b1c472301aaff11ad9966242d9e5aac4.mp4


    翻了下 concurrently 的官方文档,发现启用 --raw 参数,输出原始的打印内容,就不会卡住。

    所以应该是 tsx watch 模式下,并且是以任意方式导入了 mysql2 这个包,tsx 就会输出某些让 concurrently 无法解析并令其卡住的内容。

    所以,大佬们觉得,这到底是什么原理,真的很迷糊。

    3 条回复
    oyps
        1
    oyps  
    OP
       97 天前
    下面的代码,通过 concurrently "tsx watch xxx.ts" 执行:

    ------------------------------------------------------------------------------------
    [卡住无输出] import { createConnection } from 'mysql2/promise'
    [卡住无输出] import { createConnection } from 'mysql2'

    ------------------------------------------------------------------------------------
    [正常输出] import { createConnection } from 'mysql'
    oyps
        2
    oyps  
    OP
       97 天前
    [卡住无输出] concurrently "tsx watch main.ts"

    [正常输出] concurrently "bun --hot main.ts"


    1. 为什么 bun --hot 正常,tsx watch 不正常,是 tsx 的问题?
    2. 为什么 concurrently 加 --raw 正常,不加不正常,是 concurrently 还是 tsx 问题?
    3. 为什么 mysql2 不正常,但是 mysql 却正常,是 mysql2 的问题?
    4. 我尝试将 tsx watch 的输出转发到文件,然后用 Hex 查看,发现不管有没有 mysql2 ,输出内容都是一样的
    5. 猜测:mysql2 包对程序的输出方式做了某种改变,这种改变,经过 tsx watch 输出后无法被 concurrently 等待到输出,而 bun --hot 则应该是同一了输出方式,而无视 mysql2 对终端输出方式的改变
    oyps
        3
    oyps  
    OP
       97 天前
    我大致解决了这个问题,首先 concurrently 是基于 child_process.spawn 的,我测试发现,在 Windows 环境下,spawn 方法执行 tsx watch xxx.ts ( ts 文件导入了 mysql2 包)无法监听到 stdout 和 stderr 的任何输出,原因是 tsx watch 是基于类似 Scanner 实现的,也就是在每次 TS 文件刷新后,通过等待用户输入来使终端不结束,而 spawn 或者说 concurrently 默认情况不会将子进程( tsx watch )的输入输出进行 ignore ,所以只要在 spawn 调用时,将子进程的 stdio 数组中的第一项设置为 ignore 就可以解决该问题。

    所以这算是谁的问题呢,我认为应该算是 tsx 的问题,tsx watch 处于等待文件更新状态时,终端看上去是出于阻塞状态的,但是此时直接输入字符串,按下回车,是会触发交互的( vite 就不会,终端阻塞后,后续输入字符串,按下回车不会有反应)。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2853 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 11:57 · PVG 19:57 · LAX 03:57 · JFK 06:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.