Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Cannot find module" error at runtime when trying to run a nodejs_binary with simple local module dependency #2388

Closed
nioann opened this issue Jan 7, 2021 · 8 comments
Labels
Can Close? We will close this in 30 days if there is no further activity

Comments

@nioann
Copy link

nioann commented Jan 7, 2021

🐞 bug report

Affected Rule

The issue is caused by the rule: nodejs_binary (with bazelisk run)

Is this a regression?

Not sure.

Description

The nodejs_binary target compiles without errors with bazelisk build, but when trying to run the target, the resulting js cannot resolve the required local module.

🔬 Minimal Reproduction

Github repository: https://github.com/nioann/bazel_ts_simple_dep

Very simple dependency between two ts files: One nodejs_binary target, with one dependency containing both files (bin1), and another where there's a transient dependency so each ts file has it's own rule.

The following two targets build without errors:

bazelisk build main:bin1

bazelisk build main:bin2

But they do not run:

bazelisk build main:bin1

bazelisk build main:bin2

🔥 Exception or Error

# Error:


INFO: Invocation ID: 3d33bdc6-92bf-4340-9eb8-3b577e842ae0
INFO: Build option --define has changed, discarding analysis cache.
INFO: Analyzed target //main:bin1 (0 packages loaded, 845 targets configured).
INFO: Found 1 target...
Target //main:bin1 up-to-date:
  /Users/nioan/code/bazel-output/bin/main/bin1.sh
  /Users/nioan/code/bazel-output/bin/main/bin1_loader.js
  /Users/nioan/code/bazel-output/bin/main/bin1_require_patch.js
INFO: Elapsed time: 0.269s, Critical Path: 0.02s
INFO: 4 processes: 1 remote cache hit, 3 internal.
INFO: Build completed successfully, 4 total actions
INFO: Build completed successfully, 4 total actions
internal/modules/cjs/loader.js:797
    throw err;
    ^

Error: Cannot find module 'bazel_ts_simple_dep/main/buz'
Require stack:
- /private/var/tmp/_bazel_nioan/a4bf1dcee6be69ce9b0d5b9c3f190dcf/execroot/bazel_ts_simple_dep/bazel-out/darwin-fastbuild/bin/main/bin1.sh.runfiles/bazel_ts_simple_dep/main/main.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:794:15)
    at Function.Module._load (internal/modules/cjs/loader.js:687:27)
    at Module.require (internal/modules/cjs/loader.js:849:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at /private/var/tmp/_bazel_nioan/a4bf1dcee6be69ce9b0d5b9c3f190dcf/execroot/bazel_ts_simple_dep/bazel-out/darwin-fastbuild/bin/main/bin1.sh.runfiles/bazel_ts_simple_dep/main/main.js:12:17
    at /private/var/tmp/_bazel_nioan/a4bf1dcee6be69ce9b0d5b9c3f190dcf/execroot/bazel_ts_simple_dep/bazel-out/darwin-fastbuild/bin/main/bin1.sh.runfiles/bazel_ts_simple_dep/main/main.js:3:17
    at Object. (/private/var/tmp/_bazel_nioan/a4bf1dcee6be69ce9b0d5b9c3f190dcf/execroot/bazel_ts_simple_dep/bazel-out/darwin-fastbuild/bin/main/bin1.sh.runfiles/bazel_ts_simple_dep/main/main.js:9:3)
    at Module._compile (internal/modules/cjs/loader.js:956:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
    at Module.load (internal/modules/cjs/loader.js:812:32) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/private/var/tmp/_bazel_nioan/a4bf1dcee6be69ce9b0d5b9c3f190dcf/execroot/bazel_ts_simple_dep/bazel-out/darwin-fastbuild/bin/main/bin1.sh.runfiles/bazel_ts_simple_dep/main/main.js'
  ]
}

🌍 Your Environment

Operating System:

  
macOS mojave
10.14.6
  

Output of bazelisk version:

  
Bazelisk version: v1.7.3
Starting local Bazel server and connecting to it...
Build label: 3.6.0
Build target: bazel-out/darwin-opt/bin/src/main/java/com/google/devtools/build/lib/bazel/BazelServer_deploy.jar
Build time: Tue Oct 6 13:16:23 2020 (1601990183)
Build timestamp: 1601990183
Build timestamp as int: 1601990183
  

Output of bazel version:

  
Starting local Bazel server and connecting to it...
Build label: 1.2.1
Build target: bazel-out/darwin-opt/bin/src/main/java/com/google/devtools/build/lib/bazel/BazelServer_deploy.jar
Build time: Tue Nov 26 15:27:31 2019 (1574782051)
Build timestamp: 1574782051
Build timestamp as int: 1574782051
  

Rules_nodejs version:

(Please check that you have matching versions between WORKSPACE file and @bazel/* npm packages.)

  
3.0.0
  

Anything else relevant?
The generate code looks like this:


(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define("bazel_ts_simple_dep/main/main", ["require", "exports", "bazel_ts_simple_dep/main/buz"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const buz = require("bazel_ts_simple_dep/main/buz");
    console.log(buz.bar);
});

if the path in the require statement in line 12 is changed to a relative path (./buz), then the script works (through bin.sh or node). If I use relative paths for imports in my ts files, they will always turn to absolute paths. This seems to be intentional though (#1121).

@mattem
Copy link
Collaborator

mattem commented Jan 7, 2021

Thanks for the repro 🙏
This is a side affect of flipping the default of --bazel_patch_module_resolver to false.

To unblock you, add templated_args = ["--bazel_patch_module_resolver"] or link_workspace_root = True to the nodejs_binary rules. I agree though, it seems strange dx to add flags to run the default output of ts_library 🤔

@nioann
Copy link
Author

nioann commented Jan 7, 2021

Thank you Matt!

Both solutions work - I updated the repo, which now builds.

@nioann
Copy link
Author

nioann commented Jan 7, 2021

One more piece of information:
I wanted to see what's the difference in the .js generated code, so I removed the parameter and run the target again. However the bug does not manifest again.

After I run the target successfully once, even if I run bazel clean -expunge, the code compiles without either of the workarounds you suggest.

Addition: Actually just adding it in one of the targets, makes all other pass from then on, at least in the same machine, which doesn't seem correct.

@dgp1130
Copy link
Contributor

dgp1130 commented Jan 10, 2021

I am also encountering this while upgrading a project to rules_nodejs 3.0.0, all import statements seem to throw this error. Can anyone elaborate on what exactly the problem is here? All the documentation I can find just says: "If this breaks you, add --bazel_patch_module_resolver" without saying why I would encounter a problem in the first place. The most I've found is a few places which say I should "rely on the linker" instead, but I have no idea what that means or what I might be doing wrong? I would assume nodejs_binary() would invoke the "linker" for me, but is this a separate step I need to run/configure somehow?

I understand that --bazel_patch_module_resolver monkey patches Node's require() at runtime to resolve things a little differently to be compatible with Bazel runfiles, but if that feature has been turned off, then presumably I'm supposed to do something else instead? Without this information, I have no means of meaningfully fixing/improving my project, only working around the problem by adding an extra flag everywhere.

Can someone kindly explain/document what use cases might encounter a problem here and what we should be doing instead as a proper fix beyond just "revert the flag"?

dgp1130 added a commit to dgp1130/rules_prerender that referenced this issue Jan 10, 2021
In the upcoming `rules_nodejs` v3 release, this flag will be disabled by default, however it is still necessary to import modules in NodeJS. The easiest solution is to just explicitly enable the flag, which is a no-op in v2, but will prevent the breaking change in v3.

Unfortunately I have no idea how to actually fix the underlying breakage, only work around it. I found [an issue](bazel-contrib/rules_nodejs#2388) which seems to represent this particular problem, will keep an eye on it and update this later with a real fix that does not require this flag.
@github-actions
Copy link

This issue has been automatically marked as stale because it has not had any activity for 90 days. It will be closed if no further activity occurs in two weeks. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs!

@github-actions github-actions bot added the Can Close? We will close this in 30 days if there is no further activity label Apr 15, 2021
@github-actions
Copy link

This issue was automatically closed because it went two weeks without a reply since it was labeled "Can Close?"

@refi64
Copy link

refi64 commented Apr 20, 2022

Not sure if @dgp1130 solved this, but this is a top search result, so I'm adding the details here:

Can someone kindly explain/document what use cases might encounter a problem here and what we should be doing instead as a proper fix beyond just "revert the flag"?

The trick is that you should be using run_node instead of ctx.actions.run. e.g. instead of:

ctx.actions.run(
  # ...
  executable = ctx.executable.tool,
  # ...
)

You want:

load("@build_bazel_rules_nodejs//:providers.bzl", "run_node")

# ...

run_node(
  ctx = ctx,
  # ...
  # Notice that instead of `ctx.executable.tool`, I just pass the name of the attribute on `ctx.executable`!
  executable = "tool",
  # ...
)

@jaybhanushali3166
Copy link

jaybhanushali3166 commented Dec 6, 2023

Hi @refi64, in this case what does :providers.bzl represents? or is it just an example?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Can Close? We will close this in 30 days if there is no further activity
Projects
None yet
Development

No branches or pull requests

5 participants