Skip to content

Use fs.constants.F_OK in checkRequiredFiles - #17290

Open
TheGeekyM wants to merge 1 commit into
react:mainfrom
TheGeekyM:feat-support-current-node-releases-
Open

TheGeekyM wants to merge 1 commit into
react:mainfrom
TheGeekyM:feat-support-current-node-releases-

Conversation

@TheGeekyM

Copy link
Copy Markdown


Summary

This PR replaces the deprecated fs.F_OK alias with fs.constants.F_OK in react-dev-utils/checkRequiredFiles. It is a one-line change to the runtime code, plus a new unit test file for a utility that had no tests before. Refs #17131.

Motivation

checkRequiredFiles runs on every npm start and npm run build. Both packages/react-scripts/scripts/start.js:50 and packages/react-scripts/scripts/build.js:50 call it with [paths.appHtml, paths.appIndexJs] before doing anything else. Inside it, packages/react-dev-utils/checkRequiredFiles.js:19 called:

fs.accessSync(filePath, fs.F_OK);

The top-level fs.F_OK, fs.R_OK, fs.W_OK and fs.X_OK aliases are deprecated in Node.js (DEP0176). Current releases emit a deprecation warning when they are accessed, and Node has signaled it will remove them. Anyone running react-scripts on a recent Node version gets that warning every time they start the dev server or build. It doesn't come from their code and they can't fix it in their app. It also adds noise to CI logs and can make people think their project is broken.

fs.constants.F_OK has been the documented replacement since Node 6. Both react-dev-utils and react-scripts declare "node": ">=14" in engines, so every supported runtime has it.

What changed

  • packages/react-dev-utils/checkRequiredFiles.js: fs.accessSync(filePath, fs.F_OK) becomes fs.accessSync(filePath, fs.constants.F_OK). Nothing else in the function changes: the iteration, the return values and the "Could not find a required file." output are all the same.
  • packages/react-dev-utils/__tests__/checkRequiredFiles.test.js (new): unit tests covering the function's existing behavior and making sure it no longer depends on the deprecated alias. See Tests.

How it works

fs.constants.F_OK and the old fs.F_OK alias have the same value (0), so accessSync gets the same mode argument as before. The only difference is that the code no longer reads the deprecated property, so Node has no reason to warn.

Decisions and alternatives:

  • I kept the mode argument explicit instead of dropping it. F_OK is the default mode for fs.accessSync, so fs.accessSync(filePath) would behave the same. I kept it so the intent ("check that the file exists") is clear to readers and the diff stays minimal.
  • I didn't switch to fs.existsSync. That would also work, but it would change how the function is built (try/catch to boolean checks) for no real gain, and it would make the diff harder to review. The goal here is to remove the deprecated API usage without changing behavior.
  • I didn't add a broader cleanup. I know there is a larger effort to support current Node releases, including a CI matrix for Node 18–24 and removing other deprecated Node APIs. That work is intentionally out of scope here. This PR is a small, self-contained fix that can land on its own.

Tests

New file: packages/react-dev-utils/__tests__/checkRequiredFiles.test.js

Each test creates real files in a fresh temporary directory (fs.mkdtempSync), deletes it afterwards, and stubs console.log so the output can be checked without printing.

  • returns true when all files exist: two existing files give true, and nothing is logged.
  • returns true for an empty list: [] gives true, and nothing is logged.
  • returns false when a file is missing: one existing file plus one missing file gives false.
  • logs the name and directory of the first missing file: the output contains "Could not find a required file.", the missing file's basename and its directory. It does not mention a later missing file, which confirms the function stops at the first failure.
  • checks existence using fs.constants.F_OK: spies on fs.accessSync and checks it is called once per file with (file, fs.constants.F_OK), and that the mode is a number.
  • does not rely on the deprecated fs.F_OK alias: loads the module in isolation against an fs object whose F_OK getter returns undefined, simulating a runtime without the alias. It then checks that the function still returns true and that accessSync gets fs.constants.F_OK, not undefined. Recent Node versions define fs.F_OK as non-configurable, so the test builds a prototype-derived fs instead of patching the real module.

Run them with:

npx jest 'packages/react-dev-utils/__tests__/checkRequiredFiles.test.js'

Manual verification steps for reviewers:

  1. On Node 20 or newer, run npm start and npm run build in the monorepo. Confirm the DEP0176 warning about fs.F_OK no longer appears.
  2. Temporarily remove public/index.html from the app and run npm start again. Confirm it still prints Could not find a required file., followed by the Name: and Searched in: lines, and exits.

Compatibility & risk

  • Backwards compatibility: None of the public behavior changes. The function signature, return values and console output are the same. fs.constants.F_OK exists on every Node version allowed by the packages' engines field (>=14).
  • Performance: None. It reads a property from a different object.
  • Migration: None. Consumers of react-dev-utils and react-scripts don't need to do anything.
  • What to look at closely: The last test uses jest.isolateModules with jest.doMock('fs', ...) and calls jest.dontMock('fs') in a finally block. Please confirm this approach to mocking fs fits the repo's Jest setup and doesn't leak into other test files. The cleanup also uses fs.rmSync, which needs Node 14.14 or newer. That's fine for the repo's own test environment, but it is slightly above the >=14 floor in engines, which applies to the published packages.

---
<!--
Thank you for sending the PR!
@meta-cla meta-cla Bot added the CLA Signed label Nov 6, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant