Skip to content

Commit 50ba91b

Browse files
acozzetteclaude
andcommitted
feat: add flag controlling the default for use_execroot_entry_point
This change introduces the flag `--@aspect_rules_js//js:use_execroot_entry_point`, which controls the default behavior of the `use_execroot_entry_point` option on `js_run_binary` and `js_run_devserver`. We could like to recommend moving away from enabling `use_execroot_entry_point`, and this flag provides an easy way to do that at a global level, while still making it possible to override that on specific targets if necessary. I also added CI test runs with `--@aspect_rules_js//js:use_execroot_entry_point=False` so that we have good test coverage of both modes. This required explicitly setting `use_execroot_entry_point` on some targets that only work with one more or the other. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent eb8c7ff commit 50ba91b

9 files changed

Lines changed: 170 additions & 10 deletions

File tree

.aspect/workflows/config.yaml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ workspaces:
9494
without: true
9595
- bazel-9:
9696
without: true
97+
- bazel-9-no-execroot-entry-point:
98+
without: true
9799
e2e/pnpm_lockfiles:
98100
icon: pnpm
99101
tasks: *e2e_tasks
@@ -117,7 +119,17 @@ workspaces:
117119
tasks: *e2e_tasks
118120
e2e/repo_mapping:
119121
icon: js
120-
tasks: *e2e_tasks
122+
tasks:
123+
- test:
124+
queue: aspect-medium
125+
- format:
126+
without: true
127+
- buildifier:
128+
without: true
129+
# aspect_rules_js is given a different name in this repo, so we
130+
# cannot use a flag beginning with --@aspect_rules_js//.
131+
- bazel-9-no-execroot-entry-point:
132+
without: true
121133
e2e/output_paths:
122134
icon: js
123135
tasks: *e2e_tasks
@@ -167,6 +179,13 @@ tasks:
167179
# TODO: change this back to 9.x once this bug is fixed:
168180
# https://github.com/bazelbuild/bazel/issues/29393
169181
USE_BAZEL_VERSION: '9.0.2'
182+
- test:
183+
name: Bazel 9 (no execroot entry point)
184+
id: bazel-9-no-execroot-entry-point
185+
bazel:
186+
flags: ['--test_tag_filters=-skip-on-bazel9', '--@aspect_rules_js//js:use_execroot_entry_point=False']
187+
env:
188+
USE_BAZEL_VERSION: '9.0.2'
170189
- format:
171190
queue: aspect-medium
172191
- buildifier:

contrib/nextjs/defs.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ def nextjs_build(name, config, srcs, next_js_binary, data = [], **kwargs):
202202
chdir = native.package_name(),
203203
mnemonic = "NextJs",
204204
progress_message = "Compile Next.js app %{label}",
205+
use_execroot_entry_point = True,
205206
**kwargs
206207
)
207208

@@ -327,6 +328,7 @@ def nextjs_standalone_build(name, config, srcs, next_js_binary, data = [], **kwa
327328
chdir = native.package_name(),
328329
mnemonic = "NextJs",
329330
progress_message = "Compile Next.js standalone app %{label}",
331+
use_execroot_entry_point = True,
330332
**kwargs
331333
)
332334

js/BUILD.bazel

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
"Public API"
22

33
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
4+
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
5+
6+
# This flag controls the default behavior of the use_execroot_entry_point flag
7+
# on js_run_binary.
8+
bool_flag(
9+
name = "use_execroot_entry_point",
10+
build_setting_default = True,
11+
visibility = ["//visibility:public"],
12+
)
13+
14+
config_setting(
15+
name = "_use_execroot_entry_point_true",
16+
flag_values = {"use_execroot_entry_point": "True"},
17+
)
418

519
bzl_library(
620
name = "defs",

js/private/js_run_binary.bzl

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def js_run_binary(
3030
stderr = None,
3131
exit_code_out = None,
3232
silent_on_success = True,
33-
use_execroot_entry_point = True,
33+
use_execroot_entry_point = None,
3434
copy_srcs_to_bin = True,
3535
include_sources = True,
3636
include_types = False,
@@ -149,6 +149,9 @@ def js_run_binary(
149149
needed by the binary are available in the execroot output tree. This requirement can be turned off with by
150150
setting `allow_execroot_entry_point_with_no_copy_data_to_bin` to True.
151151
152+
If `None` (the default), the behavior is controlled by the `//js:use_execroot_entry_point` build flag,
153+
which defaults to `True`.
154+
152155
copy_srcs_to_bin: When True, all srcs files are copied to the output tree that are not already there.
153156
154157
include_sources: see `js_info_files` documentation
@@ -356,10 +359,10 @@ See https://github.com/aspect-build/rules_js/tree/main/docs#using-binaries-publi
356359
name = bazel_lib_utils.to_label(name),
357360
))
358361

359-
# Configure run from execroot
360-
if use_execroot_entry_point:
361-
fixed_env["JS_BINARY__USE_EXECROOT_ENTRY_POINT"] = "1"
362-
362+
# Configure run from execroot.
363+
# When use_execroot_entry_point is None, behavior is controlled by the //js:use_execroot_entry_point flag.
364+
execroot_extra_srcs = []
365+
if use_execroot_entry_point != False:
363366
# hoist all runfiles to srcs when running from execroot
364367
js_runfiles_lib_name = "{}_runfiles_lib".format(name)
365368
_js_library(
@@ -380,16 +383,33 @@ See https://github.com/aspect-build/rules_js/tree/main/docs#using-binaries-publi
380383
# Always propagate the testonly attribute
381384
testonly = kwargs.get("testonly", False),
382385
)
383-
extra_srcs.append(":{}".format(js_runfiles_name))
386+
387+
if use_execroot_entry_point == True:
388+
fixed_env["JS_BINARY__USE_EXECROOT_ENTRY_POINT"] = "1"
389+
execroot_extra_srcs = [":{}".format(js_runfiles_name)]
390+
else:
391+
# None: use the flag to decide at analysis time
392+
execroot_extra_srcs = select({
393+
Label("//js:_use_execroot_entry_point_true"): [":{}".format(js_runfiles_name)],
394+
"//conditions:default": [],
395+
})
384396

385397
if allow_execroot_entry_point_with_no_copy_data_to_bin:
386398
fixed_env["JS_BINARY__ALLOW_EXECROOT_ENTRY_POINT_WITH_NO_COPY_DATA_TO_BIN"] = "1"
387399

400+
# When use_execroot_entry_point is None, the env var is resolved at analysis time via the flag.
401+
# We use a select() only for the conditional portion and merge with | outside of it, so that
402+
# a user-supplied env that is itself a select() remains valid on the right-hand side.
403+
execroot_env = select({
404+
Label("//js:_use_execroot_entry_point_true"): {"JS_BINARY__USE_EXECROOT_ENTRY_POINT": "1"},
405+
"//conditions:default": {},
406+
}) if use_execroot_entry_point == None else {}
407+
388408
_run_binary(
389409
name = name,
390410
tool = tool,
391-
env = fixed_env | env,
392-
srcs = srcs + extra_srcs,
411+
env = fixed_env | execroot_env | env,
412+
srcs = srcs + extra_srcs + execroot_extra_srcs,
393413
outs = outs + extra_outs,
394414
out_dirs = out_dirs,
395415
args = args,

js/private/js_run_devserver.bzl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def js_run_devserver(
135135
tool = None,
136136
command = None,
137137
grant_sandbox_write_permissions = False,
138-
use_execroot_entry_point = True,
138+
use_execroot_entry_point = None,
139139
allow_execroot_entry_point_with_no_copy_data_to_bin = False,
140140
**kwargs):
141141
"""Runs a devserver via binary target or command.
@@ -253,6 +253,9 @@ def js_run_devserver(
253253
needed by the binary are available in the execroot output tree. This requirement can be turned off with by
254254
setting `allow_execroot_entry_point_with_no_copy_data_to_bin` to True.
255255
256+
If `None` (the default), the behavior is controlled by the `//js:use_execroot_entry_point` build flag,
257+
which defaults to `True`.
258+
256259
allow_execroot_entry_point_with_no_copy_data_to_bin: Turn off validation that the `js_binary` tool
257260
has `copy_data_to_bin` set to True when `use_execroot_entry_point` is set to True.
258261
@@ -267,6 +270,12 @@ def js_run_devserver(
267270
if kwargs.get("entry_point", None):
268271
fail("`entry_point` is set implicitly by `js_run_devserver` and cannot be overridden.")
269272

273+
if use_execroot_entry_point == None:
274+
use_execroot_entry_point = select({
275+
Label("//js:_use_execroot_entry_point_true"): True,
276+
"//conditions:default": False,
277+
})
278+
270279
# Allow the js_run_devserver rule to execute to be overridden for tests
271280
rule_to_execute = kwargs.pop("rule_to_execute", _js_run_devserver)
272281

js/private/test/data/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ js_test(
153153
# TEST: js_test(data = js_run_binary(srcs)) ---------------
154154
js_run_binary(
155155
name = "run-write-srcs",
156+
srcs = ["data.json"],
156157
outs = ["rb0.json"],
157158
args = [
158159
"rb0.json",
@@ -178,6 +179,7 @@ js_test(
178179
# TEST: js_test(data = js_run_binary(srcs = js_library(srcs))) ----------------
179180
js_run_binary(
180181
name = "run-write-js_library-srcs",
182+
srcs = ["data.json"],
181183
outs = ["rb1.json"],
182184
args = [
183185
"rb1.json",
@@ -210,6 +212,7 @@ js_binary(
210212

211213
js_run_binary(
212214
name = "run-write-js_library-data",
215+
srcs = ["data.json"],
213216
outs = ["rb2.json"],
214217
args = [
215218
"rb2.json",
@@ -235,6 +238,7 @@ js_test(
235238
# TEST: js_test(data = js_run_binary(srcs = genrule())) -----------------------
236239
js_run_binary(
237240
name = "run-write-generated",
241+
srcs = ["data-generated.json"],
238242
outs = ["rb3.json"],
239243
args = [
240244
"rb3.json",
@@ -260,6 +264,7 @@ js_test(
260264
# TEST: js_test(data = js_run_binary(srcs = genrule(srcs = filegroup))) -------
261265
js_run_binary(
262266
name = "run-write-generated-copied",
267+
srcs = ["data-copied.json"],
263268
outs = ["rb4.json"],
264269
args = [
265270
"rb4.json",
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
load("@bazel_lib//lib:testing.bzl", "assert_contains")
2+
load("@bazel_lib//lib:transitions.bzl", "platform_transition_filegroup")
3+
load("@bazel_skylib//rules:write_file.bzl", "write_file")
4+
load("//js:defs.bzl", "js_binary", "js_run_binary")
5+
6+
# Verify that dependencies passed via the srcs parameter are always built for
7+
# the target platform, unlike the tool parameter and its dependencies.
8+
# We use a select() on the OS to produce a platform-specific file, then
9+
# transition to three different target platforms and assert the contents match.
10+
write_file(
11+
name = "gen_os_name",
12+
out = "os_name.txt",
13+
content = select({
14+
"@platforms//os:linux": ["linux"],
15+
"@platforms//os:macos": ["macos"],
16+
"@platforms//os:windows": ["windows"],
17+
"//conditions:default": ["other"],
18+
}),
19+
tags = ["manual"],
20+
)
21+
22+
platform(
23+
name = "linux",
24+
constraint_values = ["@platforms//os:linux"],
25+
)
26+
27+
platform(
28+
name = "macos",
29+
constraint_values = ["@platforms//os:macos"],
30+
)
31+
32+
platform(
33+
name = "windows",
34+
constraint_values = ["@platforms//os:windows"],
35+
)
36+
37+
js_binary(
38+
name = "read_file",
39+
entry_point = "read_file.mjs",
40+
)
41+
42+
js_run_binary(
43+
name = "gen_target_os",
44+
srcs = [":os_name.txt"],
45+
args = ["$(rootpath :os_name.txt)"],
46+
stdout = "target_os.txt",
47+
tags = ["manual"],
48+
tool = ":read_file",
49+
use_execroot_entry_point = False,
50+
)
51+
52+
platform_transition_filegroup(
53+
name = "target_os_linux",
54+
srcs = [":gen_target_os"],
55+
target_platform = ":linux",
56+
)
57+
58+
platform_transition_filegroup(
59+
name = "target_os_macos",
60+
srcs = [":gen_target_os"],
61+
target_platform = ":macos",
62+
)
63+
64+
platform_transition_filegroup(
65+
name = "target_os_windows",
66+
srcs = [":gen_target_os"],
67+
target_platform = ":windows",
68+
)
69+
70+
assert_contains(
71+
name = "linux_target_platform_test",
72+
actual = ":target_os_linux",
73+
expected = "linux",
74+
)
75+
76+
assert_contains(
77+
name = "macos_target_platform_test",
78+
actual = ":target_os_macos",
79+
expected = "macos",
80+
)
81+
82+
assert_contains(
83+
name = "windows_target_platform_test",
84+
actual = ":target_os_windows",
85+
expected = "windows",
86+
)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import fs from 'fs'
2+
3+
const content = fs.readFileSync(process.argv[2], 'utf8').trim()
4+
process.stdout.write(content + '\n')

js/private/test/js_run_devserver/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ js_run_devserver_test(
2828
"no-remote-exec",
2929
],
3030
tool = ":jasmine",
31+
use_execroot_entry_point = True,
3132
)
3233

3334
jasmine_bin.jasmine_binary(

0 commit comments

Comments
 (0)