fix(js_binary): drop unused mandatory shell toolchain (#2926)
Fix #2347
### Changes are visible to end-users: no
### Test plan
- Covered by existing test cases
- New test cases added
diff --git a/.github/workflows/ci-workflows.yaml b/.github/workflows/ci-workflows.yaml
index 4a84f47..9833e59 100644
--- a/.github/workflows/ci-workflows.yaml
+++ b/.github/workflows/ci-workflows.yaml
@@ -67,6 +67,7 @@
e2e/js_image_oci
e2e/js_run_devserver
e2e/nextjs
+ e2e/no_shell_toolchain
e2e/npm_link_package
e2e/npm_link_package-rerooted
e2e/npm_translate_lock
diff --git a/e2e/no_shell_toolchain/.bazelrc b/e2e/no_shell_toolchain/.bazelrc
new file mode 100644
index 0000000..c7a0d3a
--- /dev/null
+++ b/e2e/no_shell_toolchain/.bazelrc
@@ -0,0 +1,8 @@
+import %workspace%/../../tools/preset.bazelrc
+import %workspace%/../e2e.bazelrc
+
+# Regression test for https://github.com/aspect-build/rules_js/issues/2347:
+# build every target for an iOS-like platform that has no shell toolchain (in
+# Bazel 8+ the built-in autodetecting sh toolchain was removed). js_binary must
+# not fail toolchain resolution on the shell toolchain it never uses.
+build --platforms=//:ios_like
diff --git a/e2e/no_shell_toolchain/BUILD.bazel b/e2e/no_shell_toolchain/BUILD.bazel
new file mode 100644
index 0000000..370f034
--- /dev/null
+++ b/e2e/no_shell_toolchain/BUILD.bazel
@@ -0,0 +1,48 @@
+load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_run_binary")
+load("@bazel_skylib//rules:build_test.bzl", "build_test")
+
+# js_binary declared @bazel_tools//tools/sh:toolchain_type as a mandatory
+# toolchain even though the rule never consumes it. Building for a platform with
+# no shell toolchain (e.g. Apple/iOS under Bazel 8+) therefore failed toolchain
+# resolution. The .bazelrc forces every target onto //:ios_like; this must build.
+js_binary(
+ name = "bin",
+ entry_point = "index.js",
+)
+
+# The #2347 scenario: js_binary used as a codegen tool. Building this runs the
+# tool, exercising the target-configured js_binary that failed to resolve the
+# shell toolchain.
+js_run_binary(
+ name = "run_bin",
+ stdout = "out.txt",
+ tool = ":bin",
+)
+
+build_test(
+ name = "build_test",
+ targets = [
+ ":bin",
+ ":run_bin",
+ ],
+)
+
+platform(
+ name = "ios_like",
+ constraint_values = [
+ "@platforms//os:ios",
+ "@platforms//cpu:arm64",
+ ],
+)
+
+# A Node.js runtime toolchain for the iOS platform, so the only toolchain missing
+# on //:ios_like is the shell toolchain -- isolating the regression.
+toolchain(
+ name = "nodejs_ios_arm64_toolchain",
+ target_compatible_with = [
+ "@platforms//os:ios",
+ "@platforms//cpu:arm64",
+ ],
+ toolchain = "@nodejs_linux_amd64//:toolchain",
+ toolchain_type = "@rules_nodejs//nodejs:runtime_toolchain_type",
+)
diff --git a/e2e/no_shell_toolchain/MODULE.bazel b/e2e/no_shell_toolchain/MODULE.bazel
new file mode 100644
index 0000000..b3e7bf8
--- /dev/null
+++ b/e2e/no_shell_toolchain/MODULE.bazel
@@ -0,0 +1,29 @@
+module(name = "no_shell_toolchain")
+
+bazel_dep(name = "aspect_rules_js", version = "0.0.0", dev_dependency = True)
+bazel_dep(name = "bazel_skylib", version = "1.8.1", dev_dependency = True)
+bazel_dep(name = "platforms", version = "0.0.11", dev_dependency = True)
+bazel_dep(name = "rules_nodejs", version = "6.6.0", dev_dependency = True)
+
+local_path_override(
+ module_name = "aspect_rules_js",
+ path = "../..",
+)
+
+# Bring in a Node.js repo so //:nodejs_ios_arm64_toolchain can alias its runtime
+# for the iOS platform. Any platform's Node.js works here: the js_binary is only
+# built (not run), so the runtime is never executed.
+node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node", dev_dependency = True)
+use_repo(node, "nodejs_linux_amd64")
+
+register_toolchains(
+ "//:nodejs_ios_arm64_toolchain",
+ dev_dependency = True,
+)
+
+# Registered so tests resolve @bazel_tools//tools/test:default_test_toolchain_type
+# for the iOS target platform under Bazel 9.
+register_execution_platforms(
+ "//:ios_like",
+ dev_dependency = True,
+)
diff --git a/e2e/no_shell_toolchain/index.js b/e2e/no_shell_toolchain/index.js
new file mode 100644
index 0000000..14c734e
--- /dev/null
+++ b/e2e/no_shell_toolchain/index.js
@@ -0,0 +1 @@
+console.log('hello from js_binary')
diff --git a/js/private/js_binary.bzl b/js/private/js_binary.bzl
index 3e864f8..2e42f49 100644
--- a/js/private/js_binary.bzl
+++ b/js/private/js_binary.bzl
@@ -578,8 +578,6 @@
create_launcher = _create_launcher,
implementation = _js_binary_impl,
toolchains = [
- # TODO: on Windows this toolchain is never referenced
- "@bazel_tools//tools/sh:toolchain_type",
"@rules_nodejs//nodejs:runtime_toolchain_type",
] + COPY_FILE_TO_BIN_TOOLCHAINS,
)