bazel rules_nodejs can't resolve modules using custom package.json location

1.7k views Asked by At

Bazel rules_nodejs can't resolve modules using custom package.json location.
Can someone help explain how to fix it?
Ideally I'd like to use a single tsconfig.json in third_party/npm instead.

bazel build //demo/node:bin

Gives error:

demo/node/src/lib.ts(1,19): error TS2307: Cannot find module 'chalk' or its corresponding type declarations.

Gist: https://gist.github.com/sbussard/9110d1bdcc784ca0a9303d4393e82f49

Folder structure

(repo root)
↳ WORKSPACE
↳ third_party
  ↳ npm
    ↳ package.json
    ↳ yarn.lock
↳ demo
  ↳ node
    ↳ BUILD
    ↳ tsconfig.json
    ↳ src
      ↳ lib.ts

WORKSPACE

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "build_bazel_rules_nodejs",
    sha256 = "2b2004784358655f334925e7eadc7ba80f701144363df949b3293e1ae7a2fb7b",
    urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.4.0/rules_nodejs-5.4.0.tar.gz"],
)

load("@build_bazel_rules_nodejs//:repositories.bzl", "build_bazel_rules_nodejs_dependencies")

build_bazel_rules_nodejs_dependencies()

load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories", "yarn_install")

node_repositories()

yarn_install(
    name = "npm",
    package_json = "//third_party/npm:package.json",
    yarn_lock = "//third_party/npm:yarn.lock",
)

BUILD

load("@npm//@bazel/typescript:index.bzl", "ts_project")
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")

ts_project(
    name = "lib",
    srcs = glob(["src/*.ts"]),
    deps = [
        "@npm//@types/chalk",
        "@npm//@types/node",
        "@npm//chalk",
    ],
)

nodejs_binary(
    name = "bin",
    data = [":lib"],
    entry_point = "src/lib.js",
)

lib.ts

import chalk from 'chalk';

const { blue, red, green, yellow } = chalk;
const colors = [blue, red, yellow, blue, green, red];

console.log(
  'Google'
    .split('')
    .map((c, i) => colors[i % colors.length](c))
    .join('')
);

package.json (inside dependencies)

"@types/chalk": "^2.2.0",
"chalk": "^5.0.1",

tsconfig.json

{
  "include": ["src", "types"],
  "compilerOptions": {
    "module": "es2020",
    "target": "esnext",
    "moduleResolution": "node",
    "baseUrl": "./",
    "rootDir": "./",
    "paths": {
      "src/*": ["src/*"]
    },
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "importsNotUsedAsValues": "error"
  }
}
3

There are 3 answers

7
Edwin On

TL;DR

1. chalk package

Run

npm uninstall chalk

and

npm install chalk@"<5"

to down grade the chalk package.

2. BUILD file

Remove this line "@npm//@types/chalk", under ts_project -> deps -> []


1. chalk package issue

I have faced the same issue with my Webpack setup.

This was a problem caused by TypeScript and chalk.

From NPM: chalk:

IMPORTANT: Chalk 5 is ESM. If you want to use Chalk with TypeScript or a build tool, you will probably want to use Chalk 4 for now. Read more.

Following the above warning, we can find that

You are currently using:

"chalk": "^5.0.1",

Please re-install and replace it:

"chalk": "<5",

And here is an example NPM script:

npm uninstall chalk

npm install chalk@"<5"

Currently, the latest version smaller than 5 is v4.1.2.

2. BUILD file

Hover on the TS icon of the chalk package in NPM: chalk. It will show the following message:

This package contains built-in TypeScript declarations

Which means it does not need @type/chalk package. And that's why it caused BUILD file not found in directory '@types/chalk' error.

So that, go to BUILD file and delete this line "@npm//@types/chalk", under ts_project -> deps -> []

new BUILD file

load("@npm//@bazel/typescript:index.bzl", "ts_project")
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")

ts_project(
    name = "lib",
    srcs = glob(["src/*.ts"]),
    deps = [
        "@npm//@types/node",
        "@npm//chalk",
    ],
)

nodejs_binary(
    name = "bin",
    data = [":lib"],
    entry_point = "src/lib.js",
)

After the above, you script will works fine.

4
Arnav Thorat On

According to Chalk:

IMPORTANT: Chalk 5 is ESM. If you want to use Chalk with TypeScript or a build tool, you will probably want to use Chalk 4 for now. Read more.

There are a few fixes for this issue.


1. Use Chalk 4 (recommended for TypeScript)

The first solution is to use Chalk 4. You will not be missing out on many features by downgrading to Chalk 4.

To do this, you need to first change your versions in package.json. Change them to this.

{
  "dependencies": {
    "chalk": "4.1.2"
  }
}

Note: TypeScript types (@types/chalk) aren't required, as Chalk has built-in TypeScript declarations.

After that, you can delete the node_modules folder to remove all of the packages.

Then, we can run the installation command again to reinstall chalk, as well as the other packages that you have.

$ npm install

Then, as Chalk 4 doesn't use import, you need to change your import to use require().

const chalk = require("chalk");

This should correctly install Chalk 4.


2. Change type to module

The second solution is to change the type to module in package.json. This will allow ESM imports in your files.

{
  "type": "module"
}

You do not need to change anything else in your files. However, you can't use CommonJS imports (e.g. require()) with this set.


3. Use the import() function

Another solution is to use the import() function, without adding the type: module in the package.json file.

To do this, you first need to make sure that this line of code isn't in your package.json file.

{
  "type": "module"
}

Then, you need to change the import statement for chalk to the following.

const chalk = await import("chalk");

This function allows both the CommonJS module setting set, as well as an ESM-like import statement. You just need to make sure that you are using the LTS version of Node.js, which supports top-level await.


In conclusion, these solutions should help solve your issue. However, the first solution is recommended for TypeScript.

0
piarston On

I faced the same kind of error when package.json wasn't at the root of the folder.

Setting package_path = "/" in yarn_install fixed the problem.