Skip to content

Commit 912e1a5

Browse files
committed
fix: resolve npm_install rule path resolution issue with hermetic npm wrapper
Fixed npm binary dependency issue where npm script couldn't find node binary in Bazel sandbox. Created hermetic npm wrapper script similar to jco wrapper that directly invokes node with npm. This resolves CI failures and enables successful JavaScript component npm dependency management. - Fixed npm_install script output directory creation - Working single-file JavaScript components (simple_js_component) - Multi-file components still have module resolution limitations (documented)
1 parent 7350e73 commit 912e1a5

File tree

4 files changed

+78
-24
lines changed

4 files changed

+78
-24
lines changed

MODULE.bazel.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/defs.bzl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,14 @@ def _npm_install_impl(ctx):
358358
"# Copy package.json to workspace",
359359
"cp \"{}\" \"$WORK_DIR/package.json\"".format(package_json.path),
360360
"",
361-
"# Change to workspace and run npm install",
361+
"# Save original directory and change to workspace",
362+
"ORIGINAL_DIR=\"$(pwd)\"",
362363
"cd \"$WORK_DIR\"",
363-
"\"$PWD/{}\" install".format(npm.path),
364+
"\"$ORIGINAL_DIR/{}\" install".format(npm.path),
364365
"",
365-
"# Copy node_modules to output",
366-
"cp -r node_modules \"{}\"".format(node_modules.path),
366+
"# Copy node_modules to output directory",
367+
"mkdir -p \"$(dirname \\\"$ORIGINAL_DIR/{}\\\")\"".format(node_modules.path),
368+
"cp -r node_modules \"$ORIGINAL_DIR/{}\"".format(node_modules.path),
367369
"",
368370
"echo \"NPM install complete\"",
369371
]

toolchains/jco_toolchain.bzl

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,28 @@ exec "{node}" "{workspace}/node_modules/@bytecodealliance/jco/src/jco.js" "$@"
269269
)
270270
repository_ctx.file("jco", wrapper_content, executable = True)
271271

272-
# Create symlinks for Node.js and npm binaries for the toolchain
272+
# Create wrapper script for npm (similar to jco) because npm is a node script
273+
if platform.startswith("windows"):
274+
npm_wrapper_content = """@echo off
275+
"{node}" "{npm}" %*
276+
""".format(
277+
node = node_binary.realpath,
278+
npm = npm_binary.realpath,
279+
)
280+
repository_ctx.file("npm_wrapper.cmd", npm_wrapper_content, executable = True)
281+
repository_ctx.symlink("npm_wrapper.cmd", "npm_wrapper")
282+
else:
283+
npm_wrapper_content = """#!/bin/bash
284+
exec "{node}" "{npm}" "$@"
285+
""".format(
286+
node = node_binary.realpath,
287+
npm = npm_binary.realpath,
288+
)
289+
repository_ctx.file("npm_wrapper", npm_wrapper_content, executable = True)
290+
291+
# Create symlinks for Node.js binary and use wrapper for npm
273292
repository_ctx.symlink(node_binary, "node")
274-
repository_ctx.symlink(npm_binary, "npm")
293+
repository_ctx.symlink("npm_wrapper", "npm")
275294

276295
print("Hermetic jco toolchain setup complete")
277296

tools/bazel_helpers/file_ops_actions.bzl

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -315,25 +315,58 @@ def setup_js_workspace_action(ctx, sources, package_json = None, npm_deps = None
315315
if npm_deps:
316316
all_inputs.append(npm_deps)
317317

318-
# Use a simpler direct shell approach
319-
cp_commands = ["mkdir -p {}".format(workspace_dir.path)]
318+
# Create a shell script that properly copies files (not symlinks)
319+
setup_script = ctx.actions.declare_file(ctx.label.name + "_setup_workspace.sh")
320+
321+
script_lines = [
322+
"#!/bin/bash",
323+
"set -euo pipefail",
324+
"",
325+
"WORKSPACE_DIR=\"$1\"",
326+
"shift",
327+
"",
328+
"# Create workspace directory",
329+
"mkdir -p \"$WORKSPACE_DIR\"",
330+
"echo \"Setting up JavaScript workspace: $WORKSPACE_DIR\"",
331+
"",
332+
]
320333

321334
# Copy source files to workspace root (flatten structure)
322335
for src in sources:
323-
cp_commands.append("cp {} {}/{}".format(src.path, workspace_dir.path, src.basename))
336+
script_lines.extend([
337+
"echo \"Copying {} to $WORKSPACE_DIR/{}\"".format(src.path, src.basename),
338+
"cp \"{}\" \"$WORKSPACE_DIR/{}\"".format(src.path, src.basename),
339+
])
324340

325341
if package_json:
326-
cp_commands.append("cp {} {}/package.json".format(package_json.path, workspace_dir.path))
342+
script_lines.extend([
343+
"echo \"Copying package.json\"",
344+
"cp \"{}\" \"$WORKSPACE_DIR/package.json\"".format(package_json.path),
345+
])
327346

328347
if npm_deps:
329-
cp_commands.append("cp -r {} {}/node_modules".format(npm_deps.path, workspace_dir.path))
348+
script_lines.extend([
349+
"echo \"Copying npm dependencies\"",
350+
"cp -r \"{}\" \"$WORKSPACE_DIR/node_modules\"".format(npm_deps.path),
351+
])
330352

331-
# Add debugging
332-
cp_commands.append("echo 'JavaScript workspace files:'")
333-
cp_commands.append("ls -la {}".format(workspace_dir.path))
353+
script_lines.extend([
354+
"",
355+
"echo \"JavaScript workspace setup complete\"",
356+
"echo \"Files in workspace:\"",
357+
"ls -la \"$WORKSPACE_DIR\"",
358+
])
334359

335-
ctx.actions.run_shell(
336-
command = " && ".join(cp_commands),
360+
ctx.actions.write(
361+
output = setup_script,
362+
content = "\n".join(script_lines),
363+
is_executable = True,
364+
)
365+
366+
# Run the setup script
367+
ctx.actions.run(
368+
executable = setup_script,
369+
arguments = [workspace_dir.path],
337370
inputs = all_inputs,
338371
outputs = [workspace_dir],
339372
mnemonic = "SetupJSWorkspace",

0 commit comments

Comments
 (0)