Dev server ignores Ctrl+C when stdin was paused before it started (raw mode without resume)
Maintainer thường phản hồi trong vòng 2 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 82/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- node.js, react-native, typescript, webpack
- Lĩnh vực
- cli, developer-experience
Hướng nghiên cứu
Issue xác định setupInteractions.js và phần thiết lập chế độ raw là điểm bắt đầu. Đọc tệp đó và theo dõi cách stdin được cấu hình trước khi listener keypress xử lý Ctrl+C và các phím tắt r/d/j/a. Xác nhận hành vi khi stdin đã bị tạm dừng trước lúc khởi động, sau đó kiểm tra rằng các phím tắt và Ctrl+C hoạt động sau khi thay đổi.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Describe the bug
When process.stdin has been paused before the dev server starts (which is what a CLI prompt framework's teardown does: input.unpipe() makes Node's Readable.unpipe() call pause() on its source), Ctrl+C does nothing: the server keeps running, Ctrl+Z will not suspend it, and only an external signal stops the process.
setupInteractions switches the terminal to raw mode and then reads Ctrl+C from a keypress listener. Raw mode clears the TTY's ISIG flag, so the kernel stops converting Ctrl+C into a real SIGINT — the 0x03 byte is now deliverable only as stream data, and a paused stream delivers nothing. The keypress listener never fires, so the process.on('SIGINT') handler right next to it is unreachable. Nothing in the start path resumes stdin.
CLI prompt before the bundler starts
|
v
prompt close(): input.unpipe() -> Readable.pause()
v
process.stdin [ PAUSED ]
|
v
setupInteractions()
stdin.setRawMode(true) <-- clears ISIG: kernel SIGINT gone
stdin.on('keypress', ...) <-- never fires: stream paused
process.on('SIGINT', ...) <-- never runs
The same CLI flow works with Metro, which calls process.stdin.resume() immediately after entering raw mode. The r / d / j / a shortcuts are dead in the same session, which is the same paused stream.
Reproduction
Inline, self-contained, no repository needed — repro.mjs in a project with @callstack/repack and react-native installed. It recreates a prompt framework's teardown (pipe stdin, then unpipe) and starts the dev server interactively:
import { Writable } from 'node:stream';
import { createRequire } from 'node:module';
const req = createRequire(import.meta.url);
// what a prompt framework's close() does: pipe stdin, then unpipe it
const sink = new Writable({ write(_c, _e, cb) { cb(); } });
process.stdin.pipe(sink);
await new Promise((r) => setTimeout(r, 200));
process.stdin.unpipe(sink); // <- leaves stdin paused
const commands = (await import('@callstack/repack/commands')).default;
const start = commands.find((c) => c.name === 'start').func;
await start([],
{ root: process.cwd(), reactNativePath: req.resolve('react-native'), platforms: { ios: {}, android: {} } },
{ port: 8081, interactive: true });
Steps to reproduce
node repro.mjsin an interactive terminal.- Wait for
Server listening. - Press Ctrl+C.
All measurements below were taken in a pseudo-terminal with a real Ctrl+C byte injected.
| variant | result |
|---|---|
| as written | hangs; Ctrl+Z and Ctrl+\ also ignored; external SIGTERM kills it |
delete the unpipe() line |
exits in 0.0s |
add process.stdin.resume() before start |
exits in 0.0s, and the r reload shortcut works again |
Reached the same state through real usage as well: any prompt shown before the bundler starts (device selection, port-in-use confirmation) leaves stdin paused, and the dev server then cannot be interrupted.
System Info
System:
OS: macOS 26.5.2
CPU: (10) arm64 Apple M1 Pro
Memory: 439.89 MB / 32.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 26.7.0
path: /opt/homebrew/bin/node
Yarn:
version: 1.22.19
path: /opt/homebrew/bin/yarn
npm:
version: 11.19.0
path: /opt/homebrew/bin/npm
Watchman: Not Found
Managers:
CocoaPods:
version: 1.16.2
path: ~/.rbenv/shims/pod
IDEs:
Xcode:
version: 26.6/17F113
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.9
path: /usr/bin/javac
npmPackages:
"@react-native-community/cli":
installed: 20.1.0
wanted: 20.1.0
react:
installed: 19.2.3
wanted: 19.2.3
react-native:
installed: 0.86.0
wanted: 0.86.0
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: false
Tested on macOS with the rspack engine. The webpack engine uses the same setupInteractions file, so it should behave identically; Linux and Windows untested.
Re.Pack Version
5.4.1 — and setupInteractions.js is byte-identical in 5.4.2 and the current canary, so upgrading does not help.
Proposed fix
One line, where raw mode is entered:
readline.emitKeypressEvents(process.stdin);
process.stdin.setRawMode(true);
+ // Raw mode clears the TTY's ISIG flag, so Ctrl+C reaches us only as stream
+ // data. A prior unpipe() (e.g. from a CLI prompt framework) leaves the stream
+ // paused, which would silently swallow the keypress.
+ process.stdin.resume();
resume() rather than an additional SIGINT listener: raw mode is what removed the kernel signal, and a listener registered on a paused stream is equally unreachable. The caller that pauses stdin is not at fault — unpipe() pausing its source is documented Node behaviour, and every consumer that later takes over raw-mode input has to resume it.
Also worth hardening on the calling side: a CLI that starts the dev server in-process after showing its own prompts should resume stdin before handing over, so the failure cannot be reintroduced by a bundler plugin.
Context from the consuming project: https://github.com/Expensify/App/issues/105422
- Ngôn ngữ chính
- TypeScript
- Star
- 1.9k
- Fork
- 177
- Merge trung bình
- 2 ngày 10 giờ
- Pull request đã merge (30 ngày)
- 23
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của callstack/repack
-
status:new type:feature
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 50/100
Maintainer thường phản hồi trong vòng 2 ngày
-
ScriptManager caches the rejected promise when a resolver throws, so loadScript/prefetchScript never retryCó thể đã có người làm @linhh-phv đã nhận 15 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 35/100
Maintainer thường phản hồi trong vòng 2 ngày
-
Inlined assets with fractional scales resolve to the wrong variantCó thể đã có người làm @RaphaelFakhri đã nhận 16 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 25/100
Maintainer thường phản hồi trong vòng 2 ngày
-
json as string in JS bundleCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
callstack/repack#1461 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
area:repack type:feature
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 42/100
callstack/repack#1423 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
Tất cả issue của callstack/repack
Issue tương tự
-
[Text] Add Reading Time & Word Count Estimator for Reflection Notes in src/lib/text/reading-time.tsĐang mởarea:core beginner-friendly community contributions-welcome difficulty:easy enhancement good first issue
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[fullsend] E2E: scorecard — filecheck GitLab entity metrics unavailable due to initialDelay timingĐang mởe2e-failure ready-to-code
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
redhat-developer/rhdh-plugin-export-overlays#4698 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
devswha/herdr-web-ui#2884 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
b:minor bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
software-mansion/argent#1771 ·
Maintainer thường phản hồi trong vòng 1 ngày