aspect-build / rules_js

High-performance Bazel rules for running Node.js tools and building JavaScript projects
https://docs.aspect.build/rules/aspect_rules_js
Apache License 2.0
302 stars 105 forks source link

[Bug]: `genrule` using `$(NODE_PATH)` doesn't install/resolve correctly when using `container_image` on mac #801

Open snapbug opened 1 year ago

snapbug commented 1 year ago

What happened?

I'm using a genrule rule, similar to the example to run tailwind cli for my project.

I then want to include the output into a container image, using rules_docker's container_image, which includes transitions to linux host on macOS (totally expected because of the way docker works on Mac).

This transition causes the nodejs toolchain, and therefore $(NODE_PATH) to resolve to the linux toolchain, which won't execute on Mac:

...
external/nodejs_linux_amd64/bin/nodejs/bin/node: cannot execute binary file
...

It's specifically the container_image transition, as container_layer using the genrule output succeeds as well.

Version

Development (host) and target OS/architectures: host: Mac amd64 target: linux amd64 (via docker_rules transition)

Output of bazel --version: Bazel 6.0.0

Version of the Aspect rules, or other relevant rules from your WORKSPACE or MODULE.bazel file: rules_docker: 0.25.0 rules_js: 1.11.1

Language(s) and/or frameworks involved: n/a

How to reproduce

Steps are above, but I've created a [repro repo here](https://github.com/snapbug/js_docker_repro), which has the various rules and which fails and why in the README.md

Any other information?

No response

Fund our work

gregmagolan commented 1 year ago

The resolved_toolchain code is in the rules_nodejs core: https://github.com/bazelbuild/rules_nodejs/blob/e5c7a3d0013d257fec4db5c3a01a2050a9a7c6d1/nodejs/private/toolchains_repo.bzl#L65.

Interestingly the comment the says the toolchain is the "result of Bazel resolving the toolchain for the execution or target platform.". Seems it is resolving to the target platform and not the execution platform.

@alexeagle any idea how to get the toolchain for the execution platform in this context?

genrule(
    name = "tailwind",
    srcs = [
        "//:tailwind.config.js",
        "//:package.json",
        "//:index.html",
        "//:node_modules",
        "//:node_modules/tailwindcss",
        "//:node_modules/tailwindcss/dir",
    ],
    outs = ["tailwind.css"],
    cmd = " ".join([
        "$(NODE_PATH)",
        "./$(execpath //:node_modules/tailwindcss/dir)/lib/cli.js",
        "-o $(OUTS)",
        "-c $(location :tailwind.config.js)",
    ]),
    toolchains = ["@nodejs_toolchains//:resolved_toolchain"],
    tools = ["@nodejs_toolchains//:resolved_toolchain"],
)

container_layer(
    name = "tailwind_layer",
    files = [
        ":tailwind",
    ],
)

container_image(
    name = "tailwind_image",
    layers = [
        ":tailwind_layer",
    ],
)
nekinie commented 6 months ago

Leaving some notes on how I hooked up Tailwind v4 alpha 10 to Bazel. You will need to add a pnpm dependency for both @tailwindcss/cli and tailwindcss. Bazel needs to be executed with the --spawn_strategy=local due to Tailwind not detecting template files when sandboxed (still looking into this).

Hope this helps someone :)

load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
load("@npm//zavix/website:@tailwindcss/cli/package_json.bzl", tailwind_bin = "bin")

copy_to_directory(
    name = "template",
    replace_prefixes = {
        "zavix/template": ""
    },
    srcs = [
        "//zavix/website/template/partial",
        "//zavix/website/template/view",
    ],
)

tailwind_bin.tailwindcss(
    name = "css",
    chdir = package_name(),
    outs = ["output.css"],
    visibility = ["//zavix/website/public:__pkg__"],
    args = [
        "-i",
        "input.css",
        "-o",
        "output.css",
    ],
    srcs = [
        "input.css",
        ":template",
        "//zavix/website:node_modules/tailwindcss",
    ],
)