Skip to content

Commit 76c8f7d

Browse files
committed
Added more documentation
1 parent 2752cda commit 76c8f7d

2 files changed

Lines changed: 78 additions & 8 deletions

File tree

docs/use_execroot_entry_point.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# use_execroot_entry_point
2+
3+
This page describes the `use_execroot_entry_point` option on `js_run_binary` and
4+
`js_run_devserver`, and provides guidance on when to use each value.
5+
6+
## Background
7+
8+
When a `js_binary` is used as a tool in `js_run_binary`, Bazel runs it as a
9+
build action on the exec platform. The execroot is the root of the build
10+
sandbox; beneath it sits `bazel-out/`, which contains output directories for
11+
both the exec and target configurations. The tool's sources can therefore appear
12+
in up to three places:
13+
14+
- **Exec-platform bin** (`bazel-out/<exec-cfg>/bin/`): where build artifacts for
15+
the exec platform land.
16+
- **Runfiles tree** (`bazel-out/<exec-cfg>/bin/path/to/my_binary.runfiles/`):
17+
where the tool's runtime dependencies (including `node_modules`) are
18+
symlinked and made available to the build action.
19+
- **Target-platform bin** (`bazel-out/<target-cfg>/bin/`): where the `srcs` of
20+
the `js_run_binary` action land.
21+
22+
When Node.js resolves `require()`, it walks up the directory tree looking for
23+
`node_modules`. If the working directory is somewhere that can see
24+
`node_modules` from both the exec output tree and the runfiles tree, the same
25+
package can resolve from two different paths, which can cause subtle bugs.
26+
27+
## What `use_execroot_entry_point` does
28+
29+
**`use_execroot_entry_point = True` (the current default):**
30+
The tool's runfiles are hoisted into `srcs`, which causes them to be rebuilt in
31+
the target configuration and land in the target-platform bin directory. The
32+
entry point used is the one in that output tree (the "execroot entry point"),
33+
rather than the copy inside the runfiles symlink tree. With everything
34+
consolidated in `bazel-out/<target-cfg>/bin/`, Node.js sees a single
35+
`node_modules` tree. This is the right choice for Next.js for two reasons:
36+
Next.js expects its inputs and outputs to be in the same directory tree, and it
37+
performs pre-rendering during the build, which involves running target-platform
38+
code on the exec platform.
39+
40+
The tradeoff is that if the exec platform differs from the target platform (for
41+
example, cross-compiling from macOS to Linux), target-platform artifacts such as
42+
native Node.js addons are rebuilt for the target and may fail to run on the exec
43+
platform.
44+
45+
**`use_execroot_entry_point = False`:**
46+
The entry point used is the one from the runfiles tree. All code executed during
47+
the build action runs from the runfiles tree, which avoids cross-platform
48+
issues. However, you must ensure that any code executed during the build (for
49+
example, JavaScript config files for tools like Webpack or Rspack) is a declared
50+
dependency of the `js_binary` tool, not merely a source file passed to
51+
`js_run_binary`. Config files in the `js_run_binary`'s `srcs` will land in the
52+
target-platform bin directory and will therefore not be visible to the tool's
53+
runfiles resolution.
54+
55+
## Recommendation
56+
57+
We recommend setting `use_execroot_entry_point = False` wherever possible and
58+
ensuring that all code executed during the build is declared as a dep of the
59+
`js_binary`. The main exception is Next.js and similar frameworks that expect
60+
inputs and outputs in the same directory tree or that execute target-platform
61+
code during the build, in which case `True` is required.
62+
63+
To disable `use_execroot_entry_point` globally, pass the build flag:
64+
65+
```
66+
--@aspect_rules_js//js:use_execroot_entry_point=False
67+
```
68+
69+
Individual targets can still override the flag by explicitly setting
70+
`use_execroot_entry_point = True` or `use_execroot_entry_point = False`.
71+
72+
In a future major version, we will likely disable the `use_execroot_entry_point`
73+
behavior by default.

js/private/js_run_binary.bzl

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,17 @@ def js_run_binary(
137137
use_execroot_entry_point: Use the `entry_point` script of the `js_binary` `tool` that is in the execroot output tree
138138
instead of the copy that is in runfiles.
139139
140+
If `None` (the default), the behavior is controlled by the `//js:use_execroot_entry_point` build flag,
141+
which defaults to `True`.
142+
140143
Runfiles of `tool` are all hoisted to `srcs` of the underlying `run_binary` so they are included as execroot
141144
inputs to the action.
142145
143-
Using the entry point script that is in the execroot output tree means that there will be no conflicting
144-
runfiles `node_modules` in the node_modules resolution path which can confuse npm packages such as next and
145-
react that don't like being resolved in multiple node_modules trees. This more closely emulates the
146-
environment that tools such as Next.js see when they are run outside of Bazel.
147-
148-
When True, the `js_binary` tool must have `copy_data_to_bin` set to True (the default) so that all data files
146+
When enabled, the `js_binary` tool must have `copy_data_to_bin` set to True (the default) so that all data files
149147
needed by the binary are available in the execroot output tree. This requirement can be turned off with by
150148
setting `allow_execroot_entry_point_with_no_copy_data_to_bin` to True.
151149
152-
If `None` (the default), the behavior is controlled by the `//js:use_execroot_entry_point` build flag,
153-
which defaults to `True`.
150+
See docs/use_execroot_entry_point.md for more information.
154151
155152
copy_srcs_to_bin: When True, all srcs files are copied to the output tree that are not already there.
156153

0 commit comments

Comments
 (0)