bazelbuild / examples

Examples for Bazel
http://bazel.build
Apache License 2.0
824 stars 506 forks source link

frontend/react - Running js_run_devserver on windows not starting. #327

Closed duhruh closed 10 months ago

duhruh commented 1 year ago

When attempting to run the react app js_run_devserver target on my windows 10 machine I am unable to get it to start.

> bazel version
Bazelisk version: v1.16.0
Build label: 6.4.0rc1
Build target: bazel-out/x64_windows-opt/bin/src/main/java/com/google/devtools/build/lib/bazel/BazelServer_deploy.jar
Build time: Tue Sep 19 23:01:10 2023 (1695164470)
Build timestamp: 1695164470
Build timestamp as int: 1695164470
> bazel run react:start    
INFO: Analyzed target //react:start (0 packages loaded, 3 targets configured).
INFO: Found 1 target...
Target //react:start up-to-date:
  bazel-bin/react/start.bat
INFO: Elapsed time: 42.738s, Critical Path: 9.61s
INFO: 7 processes: 6 internal, 1 local.
INFO: Build completed successfully, 7 total actions
INFO: Running command line: bazel-bin/react/start.bat start

Starting js_run_devserver /react:start
Syncing...
21 files synced in 14 ms
Running 'node_modules/.bin/react-scripts start' in C:\Users\someone\AppData\Local\Temp\js_run_devserver-wUeRh5\_main

node:events:491
      throw er; // Unhandled 'error' event
      ^

Error: spawn node_modules/.bin/react-scripts ENOENT
    at onErrorNT (node:internal/child_process:485:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)
Emitted 'error' event on ChildProcess instance at:
    at onErrorNT (node:internal/child_process:485:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'spawn node_modules/.bin/react-scripts',
  path: 'node_modules/.bin/react-scripts',
  spawnargs: [ 'start' ]
}
alexeagle commented 11 months ago

Hm, @gregmagolan do you know offhand whether js_run_devserver is tested on windows anywhere?

xnerhu commented 11 months ago

Seems similar to my issue with next.js #354

xnerhu commented 11 months ago

it doesnt work on macos (arm) too

➜  frontend git:(main) ✗ bazel run //react:start
Starting local Bazel server and connecting to it...
INFO: Analyzed target //react:start (1298 packages loaded, 9340 targets configured).
INFO: Found 1 target...
Target //react:start up-to-date:
  bazel-bin/react/start.sh
INFO: Elapsed time: 67.477s, Critical Path: 3.13s
INFO: 4181 processes: 2928 internal, 5 darwin-sandbox, 1248 local.
INFO: Build completed successfully, 4181 total actions
INFO: Running command line: bazel-bin/react/start.sh start

Starting js_run_devserver //react:start
Syncing...
21 files synced in 7 ms
Running 'node_modules/.bin/react-scripts start' in /var/folders/3v/lhqprb9x61b7hg5nzxkzrfr80000gn/T/js_run_devserver-s8PWO3/_main

node:events:491
      throw er; // Unhandled 'error' event
      ^

Error: spawn node_modules/.bin/react-scripts ENOENT
    at Process.ChildProcess._handle.onexit (node:internal/child_process:285:19)
    at onErrorNT (node:internal/child_process:485:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)
Emitted 'error' event on ChildProcess instance at:
    at Process.ChildProcess._handle.onexit (node:internal/child_process:291:12)
    at onErrorNT (node:internal/child_process:485:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'spawn node_modules/.bin/react-scripts',
  path: 'node_modules/.bin/react-scripts',
  spawnargs: [ 'start' ]
}
➜  frontend git:(main) ✗ bazel info
bazel-bin: /private/var/tmp/_bazel_xnerhu/adb5be6efeeda41084131895cd3b79d4/execroot/_main/bazel-out/darwin_arm64-fastbuild/bin
bazel-genfiles: /private/var/tmp/_bazel_xnerhu/adb5be6efeeda41084131895cd3b79d4/execroot/_main/bazel-out/darwin_arm64-fastbuild/bin
bazel-testlogs: /private/var/tmp/_bazel_xnerhu/adb5be6efeeda41084131895cd3b79d4/execroot/_main/bazel-out/darwin_arm64-fastbuild/testlogs
character-encoding: file.encoding = ISO-8859-1, defaultCharset = ISO-8859-1
command_log: /private/var/tmp/_bazel_xnerhu/adb5be6efeeda41084131895cd3b79d4/command.log
committed-heap-size: 838MB
execution_root: /private/var/tmp/_bazel_xnerhu/adb5be6efeeda41084131895cd3b79d4/execroot/_main
gc-count: 31
gc-time: 428ms
install_base: /var/tmp/_bazel_xnerhu/install/ddd281a04e1ea09d877c10bb6de68ae9
java-home: /opt/homebrew/Cellar/openjdk@11/11.0.21/libexec/openjdk.jdk/Contents/Home
java-runtime: OpenJDK Runtime Environment (build 11.0.21+0) by Homebrew
java-vm: OpenJDK 64-Bit Server VM (build 11.0.21+0, mixed mode) by Homebrew
max-heap-size: 8589MB
output_base: /private/var/tmp/_bazel_xnerhu/adb5be6efeeda41084131895cd3b79d4
output_path: /private/var/tmp/_bazel_xnerhu/adb5be6efeeda41084131895cd3b79d4/execroot/_main/bazel-out
package_path: %workspace%
release: release 6.4.0-homebrew
repository_cache: /var/tmp/_bazel_xnerhu/cache/repos/v1
server_log: /private/var/tmp/_bazel_xnerhu/adb5be6efeeda41084131895cd3b79d4/java.log.mikoajs-macbook-pro.xnerhu.log.java.20231031-173031.947
server_pid: 947
used-heap-size: 320MB
workspace: /Users/xnerhu/examples/frontend
gregmagolan commented 11 months ago

It is not tested on Windows on rules_js CI so it may have regressed. Unfortunately it is too much effort to maintain the rule set for Windows for free since we don't use Windows ourselves and none of our clients or customers do either. Windows is the exception in the Bazel world. Google puts minimal KTL effort into Windows support for Bazel core as well. If you can use WSL2 on Windows you'll have a much better time with Bazel.

It should work on macos (arm) although the CI coverage is light for that as well so its possible something is broken.

alexeagle commented 11 months ago

Oh, actually I think there's a simpler answer, we needed this to make it work in the old location https://github.com/aspect-build/bazel-examples/blob/27cb0187f975a1402b4789ca33afd9fda3004d15/react-cra/WORKSPACE#L56-L60 and I broke this when porting to this examples repo.

https://docs.aspect.build/rulesets/aspect_rules_js/docs/npm_translate_lock/#bins isn't very clear about what either of the keys or the value mean. Porting exactly the same thing doesn't seem to work, but I imagine that's because we're now in a subfolder rather than the root. Need a bit more hand-holding @gregmagolan

jeraymond commented 10 months ago

I was troubleshooting this. The two issues I see are:

  1. The server is being started from wrong directory. It's up one level from ./react subdirectory in the output.
  2. ./react/node_modules/.bin/react-scripts does not exist in the output

For 1) using chdir gets to the right place:

js_run_devserver(
    name = "start",
    args = ["start"],
    command = "node_modules/.bin/react-scripts",
    data = CRA_DEPS,
    chdir="react",
)

I.e. this gets us to from /var/folders/.../T/js_run_devserver-DhFiQ0/_main to `/var/folders/.../T/js_run_devserver-DhFiQ0/_main/react as the run directory.

For 2) not sure what to do. I see node_modules in the react folder but no .bin. Not sure how this gets created.

jeremy@tron:/var/folders/vk/c3kwmld547z3pd2h7ls9g8txf9hfbk/T/js_run_devserver-DhFiQ0/_main/react$ ls
node_modules package.json public       src
jeremy@tron:/var/folders/vk/c3kwmld547z3pd2h7ls9g8txf9hfbk/T/js_run_devserver-DhFiQ0/_main/react$ ls .bin
ls: .bin: No such file or directory

The rest of the node_modules content seems match what's in the original example.

I  went back to the react-cra example at c8ba84f just before the port here and it works. The content is in .../_main (since there is no react sub-directory) and node_modules/.bin/react-scripts exists.

duhruh commented 10 months ago

Okay so I'm still investigating this and @jeraymond I think you're right, any change I make to bins just doesn't seem to work or affect the output build directory at all.

I made the following change

diff --git a/frontend/MODULE.bazel b/frontend/MODULE.bazel
index f85954d..9996391 100644
--- a/frontend/MODULE.bazel
+++ b/frontend/MODULE.bazel
@@ -13,6 +13,11 @@ npm.npm_translate_lock(
     name = "npm",
     npmrc = "//:.npmrc",
     pnpm_lock = "//:pnpm-lock.yaml",
+    bins = {
+        "@react/react-scripts": {
+            'react': "bin/react-scripts.js",
+        },
+    },

this at least allowed the code to build, but no bin folder was found. @alexeagle I think you're right the solution is probably just some combinations of values added to that bins object, but it's slightly different since we're in a subdirectory. I suppose there could also be a bug in the symlinking of the values in bins once the build directory is created.

As an aside, since the node_modules directory is correctly symlinked during the build i tried to change the command to the following just to see if I could get the server started:

diff --git a/frontend/react/BUILD.bazel b/frontend/react/BUILD.bazel
index 34ea2e7..32c4e61 100644
--- a/frontend/react/BUILD.bazel
+++ b/frontend/react/BUILD.bazel
@@ -39,7 +39,8 @@ js_test(
 js_run_devserver(
     name = "start",
     args = ["start"],
-    command = "node_modules/.bin/react-scripts",
+    chdir = package_name(),
+    command = "./node_modules/react-scripts/bin/react-scripts.js",
     data = CRA_DEPS,
 )

this unsurprisingly didn't work, but did produce me a different error.

> bazel run react:start
Starting local Bazel server and connecting to it...
INFO: Analyzed target //react:start (1301 packages loaded, 8679 targets configured).
INFO: Found 1 target...
Target //react:start up-to-date:
  bazel-bin/react/start.bat
INFO: Elapsed time: 176.312s, Critical Path: 29.74s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Running command line: bazel-bin/react/start.bat start

Starting js_run_devserver /react:start
Syncing...
21 files synced in 10 ms
Running './node_modules/react-scripts/bin/react-scripts.js start' in C:\Users\me\AppData\Local\Temp\js_run_devserver-UFxACh\_main\react

Error: spawn UNKNOWN
    at ChildProcess.spawn (node:internal/child_process:420:11)
    at Module.spawn (node:child_process:733:9)
    at file:///C:/Users/me/_bazel_me/lyqzba65/execroot/_main/bazel-out/x64_windows-fastbuild/bin/react/start.bat.runfiles/aspect_rules_js~1.32.2/js/private/js_run_devserver.mjs:221:36
    at new Promise (<anonymous>)
    at main (file:///C:/Users/me/_bazel_me/lyqzba65/execroot/_main/bazel-out/x64_windows-fastbuild/bin/react/start.bat.runfiles/aspect_rules_js~1.32.2/js/private/js_run_devserver.mjs:186:12)
    at async file:///C:/Users/me/_bazel_me/lyqzba65/execroot/_main/bazel-out/x64_windows-fastbuild/bin/react/start.bat.runfiles/aspect_rules_js~1.32.2/js/private/js_run_devserver.mjs:278:9 {
  errno: -4094,
  code: 'UNKNOWN',
  syscall: 'spawn'
}
duhruh commented 10 months ago

Sorry to bring this back up, but at least from my testing this doesn't seem to be fixed for a couple of reasons.

  1. https://github.com/aspect-build/rules_js/blob/main/npm/private/npm_link_package_store.bzl#L69 this wont work on windows boxes unless run from a shell like terminal. The official recommendation from the bazel team seems to be to expect a either cmd or powershell

i wrote this very rough ps1 script as an approximate translation

$basedir = Split-Path -Parent $MyInvocation.MyCommand.Path
$package = "{package_path}"
$bin = "{bin_path}"
$realPath = (Get-Item -Path "$basedir\\..\\$package").Target
& node "$realPath\\bin\\$bin" @args

i had to format in a couple of new variables but with this i was able get a working ps1 script (i am no powershell expert)

  1. since i switched it to powershell as far as I could tell you cannot just execute the script like we did before here https://github.com/aspect-build/rules_js/blob/main/js/private/js_run_devserver.mjs#L221 so i patched in
 const isWindows = os.platform() === 'win32';
 if (isWindows){
   toolArgs = ["-executionpolicy", "unrestricted", "-File", tool + ".ps1", ...toolArgs];
   tool = "powershell"
}

I made a lot of progress with this as the build was actually succeeding and getting up to the point of actually running react-scripts start

The part that i'm currently stuck on is some Error: EPERM: operation not permitted, error from the node process.

I have an idea why, and it boils down to symlinks. The node react-scripts start command is run from the temp directory created during the build, the node_modules/$PACKAGE directories are all symlinked here however I think node is having issues resolving those symlinks, i've checked and they are all indeed valid and point to the correct locations in runfiles but i feel there's something wrong with them.

The reason I think there's something wrong with these symlinks is that when i run the node_modules\bin\react-scripts.ps1 start command manually from the runfiles directory the server actually starts!

So maybe it's something to do with how we're declaring the symlinks I'm not sure, I'm no expert in how bazel handles symlinks on windows so any help here would be very much appreciated @alexeagle @gregmagolan

if it helps here what my build directories look like

The temp directory (node node_modules\react-scripts\bin\react-scripts.js start fails) image

Runfiles (node node_modules\react-scripts\bin\react-scripts.js start succeeds) image