Skip to content

refactor: share one node and npm wrapper across targets - #2971

Merged
acozzette merged 15 commits into
mainfrom
wrappers
Aug 14, 2026
Merged

refactor: share one node and npm wrapper across targets#2971
acozzette merged 15 commits into
mainfrom
wrappers

Conversation

@acozzette

@acozzette acozzette commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Both of these wrappers were being stamped out from templates, one per js_binary target. Since each instantiation is identical to all the others, let's just have a single global copy.

This change also removes js/private/test/image/custom_layers_test_app.listing, which appears to be unreferenced.


Changes are visible to end-users: no

Test plan

  • Covered by existing test cases
  • New test cases added

acozzette and others added 3 commits August 13, 2026 11:05
Both of these wrappers were being stamped out from templates, but each
instantiation was identical to all the others.

The npm wrapper did nothing but exec the npm binary and pass along all
command-line arguments, so this commit drops that wrapper altogether. As long
as we put the npm binary on the `PATH`, we can just call it directly instead.

The node wrapper is still useful because it adds an important `--require` flag,
but this commit sets up a global wrapper instead of having every `js_binary`
stamp out its own copy.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@acozzette
acozzette marked this pull request as ready for review August 13, 2026 18:24
Comment thread .github/workflows/ci-workflows.yaml
@acozzette
acozzette requested a review from jbedard August 13, 2026 18:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8269b5962b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread js/private/js_binary.sh.tpl
acozzette and others added 5 commits August 13, 2026 13:48
The launcher puts the directory holding JS_BINARY__NODE_WRAPPER on the PATH so children
resolve `node` to the fs-patched wrapper. That only holds if the directory contains a
single PATH-resolvable `node`: a POSIX shell picks the extensionless file, cmd.exe picks
node.bat/.cmd/.exe via PATHEXT.

Under runfiles only the selected wrapper is a runfile, so this passes. In the
JS_BINARY__NO_RUNFILES configuration the launcher resolves the wrapper from the source
directory in the execroot, which holds both `node` and `node.bat`, and the test fails.

The existing spawn tests cannot cover this on Windows: they assert
`which node == process.execPath`, but bootstrap.cjs skips the process.execPath override
on win32, so they fail there for unrelated pre-existing reasons.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Runs //js/private/test/node_bin:node_bin_path_test on windows-latest, once with
--noenable_runfiles (expected to FAIL: this is the reproduction) and once with
--enable_runfiles (expected to PASS, isolating the failure to the no-runfiles path).

Runs the single target rather than //... because the root workspace is excluded from the
smoke matrix on Windows due to broad pre-existing failures. Deliberately left out of the
`conclusion` needs list so an intentionally-red diagnostic does not block the merge gate.

Drop this commit, along with the temporary smoke gate removal, before merging.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The launcher puts the wrapper's directory on the PATH. Under JS_BINARY__NO_RUNFILES
(Windows with enable_runfiles False) that directory is the source directory in the
execroot, which holds every file in the package -- so a shared directory made both `node`
and `node.bat` resolvable as `node`, and a POSIX-shell child could resolve the
extensionless wrapper while the launcher had selected node.bat.

Reproduced on CI before the fix, with node_bin_path_test under --noenable_runfiles:

    node wrapper:    D:/_bazel/execroot/_main/js/private/node_bin/node.bat
    PATH directory:  D:/_bazel/execroot/_main/js/private/node_bin
    node candidates: ["node","node.bat"]

Only the runfiles case was safe, since just the selected wrapper is a runfile there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
custom_layers_test_app.listing has no target: the js_image_layer it belonged to was
renamed to custom_layers_nomatch, and it is missing the _node / _node_modules /
_package_store_* siblings every other listing group has. Nothing asserts against it, so
it had silently gone stale.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Putting the Node.js toolchain's bin directory on the PATH avoided the per-target wrapper
action, but it put more than npm there. Restore the wrapper as a shared source file, the
same way the node wrapper works, which keeps the action saving (TemplateExpand actions
across //examples/... stay at 142, down from 240 before this branch) while fixing:

* PATH pollution. nodeinfo.npm may be an absolute path from a custom node_toolchain, so a
  js_binary using a non-hermetic npm was prepending e.g. /usr/local/bin ahead of
  everything the caller had on the PATH, for the binary and its whole child-process tree.
  The wrapper directory holds only the wrapper.

* An unpatched node on the PATH. The toolchain's bin directory also holds its own node
  launcher, which does not apply the fs patches. That made the order of the two PATH
  prepends load-bearing; it no longer is, since neither directory can shadow the other.

Each wrapper keeps its own directory for the reason the node wrappers were split: under
JS_BINARY__NO_RUNFILES the directory on the PATH is the source directory in the execroot,
so anything sharing it is on the PATH too. A shared directory would put `npm` on the PATH
even without include_npm.

node_bin_path_test now checks both wrappers and gains an include_npm variant.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@acozzette acozzette changed the title refactor: drop the npm wrapper and share one node wrapper across targets refactor: share one node and npm wrapper across targets Aug 13, 2026
acozzette and others added 6 commits August 13, 2026 16:41
The launcher's JS_BINARY__NO_RUNFILES branch resolves the node and npm wrappers from the
source directory in the execroot rather than from runfiles, which is how both wrappers
ended up PATH-resolvable as `node` in the same directory. Nothing covered it: the tests
that would catch it live in the root workspace, which is excluded from the smoke matrix
on Windows because of broad pre-existing failures there.

Give the matrix workspace entries `flags` and `targets`, so a Windows entry can run just
//js/private/test/node_bin:all from the root workspace under --noenable_runfiles instead
of the whole //... . The temporary standalone job that reproduced the bug is removed,
since this supersedes it.

Matrix jobs are now named by slug rather than path, so the new entry does not render as
`smoke (., windows-latest)` -- the combination the exclude above it removes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restores .github/workflows/ci-workflows.yaml to its state on main: the smoke job's
branch gate is back, along with its original job naming and matrix, and the temporary
Windows job is gone. Drops the plan to cover the JS_BINARY__NO_RUNFILES launcher path on
Windows from CI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This test is not particularly useful because it covers a Windows issue that we
can't easily cover in CI.
@acozzette
acozzette merged commit 06aa560 into main Aug 14, 2026
186 checks passed
@acozzette
acozzette deleted the wrappers branch August 14, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants