Skip to content

fix(unplugin): prevent file handle leaks in Vitest (#1533)#1534

Open
lecstor wants to merge 1 commit intofacebook:mainfrom
lecstor:fix/issue-1533-unplugin-file-handle-leak
Open

fix(unplugin): prevent file handle leaks in Vitest (#1533)#1534
lecstor wants to merge 1 commit intofacebook:mainfrom
lecstor:fix/issue-1533-unplugin-file-handle-leak

Conversation

@lecstor
Copy link

@lecstor lecstor commented Mar 20, 2026

What changed / motivation ?

This PR fixes two resource-leak issues in @stylexjs/unplugin that cause
Vitest's hanging-process reporter to detect ~581 leaked FILEHANDLE
operations
and 1 leaked Timeout, preventing clean process exit.

Linked PR/Issues

Fixes #1533

Additional Context

Root Cause

1. Babel config-file discovery — FILEHANDLE ×581

runBabelTransform() passes babelrc: false but does not set configFile.
When configFile is not explicitly set to false, Babel proceeds with root
config file discovery, triggering up to 7 parallel file-system probes for config
file variants (babel.config.{js,cjs,mjs,json,cts,mts,ts}) on every
transformAsync() invocation. In async mode, these use callback-based
fs.readFile/fs.stat operations whose handles are tracked as async resources
by Vitest's reporter. In a project with ~80 StyleX modules, this produces ~581
leaked handle operations.

2. Unreferenced polling timer — Timeout ×1

The configureServer() hook starts a setInterval(..., 150) to poll the shared
CSS-rules version counter. It attaches a cleanup listener to
server.httpServer?.once('close', ...), but in Vitest's middleware mode
httpServer is null. The interval therefore runs forever, keeping the Node.js
event loop alive.

Pre-flight checklist

  • I have read the contributing guidelines
    Contribution Guidelines
  • Performed a self-review of my code
  • Both changes are minimal, targeted, one-line fixes
  • babelrc: false was already set — adding configFile: false is the
    symmetric completion of "don't look for external config"
  • interval.unref() is the standard Node.js pattern for optional timers
    (used in Vite core itself)
  • No new dependencies added
  • No changes to public API or user-facing behavior
  • The server.httpServer?.once('close', ...) cleanup listener is preserved
    as a belt-and-suspenders safeguard for non-middleware environments
  • Tested with vitest run --reporter=hanging-process — zero leaked
    resources
Disable Babel config-file discovery (configFile: false) in runBabelTransform() to stop leaked FILEHANDLE operations during test run, and unref() the setInterval polling timer in configureServer() so it does not block process exit in middleware mode.
@meta-cla
Copy link

meta-cla bot commented Mar 20, 2026

Hi @lecstor!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks!

@vercel
Copy link

vercel bot commented Mar 20, 2026

@lecstor is attempting to deploy a commit to the Meta Open Source Team on Vercel.

A member of the Team first needs to authorize it.

@meta-cla
Copy link

meta-cla bot commented Mar 20, 2026

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

1 participant