An example for rules_js + rules_docker

The js_image_layer rule returns tar artifacts, suitable to include in the tars attribute of the container_image rule from rules_docker. You can bazel run the target to get the image to load into your Docker daemon. See the rules_docker documentation

Like all lang_image rules in rules_docker, the nodejs_image rule has different behavior under bazel run where the container is booted and executes.

For an example using rules_oci rather than rules_docker, see the js_image_oci folder next to this one.

Fine-grained layering

js_image_layer is a macro that yields two tar files app.tar and node_modules.tar. While app.tar contains first-party sources, node_modules.tar contains all third-party dependencies.

This speeds up developer change-build-push cycle by allowing build and push of only what has changed.

For instance, when a new third-party dependency is added, then only node_modules.tar will change and one will only have to push changes to dependencies. On the other hand, if the application code is changed, then only app.tar will be updated and pushed.

dive

│ Layers ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Cmp   Size  Command
    118 MB  FROM 27d8bf01e7ea3c5
     78 MB  bazel build ...
     97 kB  bazel build ...
       0 B  #(nop) ADD file:64c455af1bb18ff2c202a244e058b6e5ac147b89410ed36edc5e29f4b6f02c5d in /

│ Image Details ├───────────────────────────────────────────────────────────────────────────────────────────

Image name: localhost/bazel:image
Total Image size: 196 MB
Potential wasted space: 0 B
Image efficiency score: 100 %

As seen in the dive output the largest layer is our base image which is 118 MB followed by 78 MB which is the dependencies and finally 97 kB which is the app itself. Additionally, we get a 100% efficiency score which means there are no duplicate or whiteout files to waste space.

Selecting the right NodeJS interpreter

By default js_binary gets the nodejs interpreter for the host platform. However, this is not the case when including the js_binary in container_image thanks to transitions. See #3373 and #1963 for how this works.

Toolchain selection is controlled by operating_system and architecture attribute on container_image which is linux/amd64 by default.

NodeJS interpreter for a different platform can be obtained by changing operating_system and architecture.

Here is what the final image looks like when the platform is linux/arm64

app
|-- main.sh
|-- main.sh.runfiles
|   |-- __main__
|   |   |-- main.sh
|   |   |-- node_modules
|   |   |   `-- chalk -> /app/main.sh.runfiles/__main__/node_modules/.aspect_rules_js/chalk@4.1.2/node_modules/chalk
|   |   `-- src
|   |       |-- ascii.art
|   |       `-- main.js
|   |-- aspect_rules_js
|   |   `-- js
|   |       `-- private
|   |           `-- node-patches
|   |               |-- fs.cjs
|   |               `-- register.cjs
|   |-- bazel_tools
|   |   `-- tools
|   |       `-- bash
|   |           `-- runfiles
|   |               `-- runfiles.bash
|   `-- nodejs_linux_arm64
|       `-- bin
|           `-- nodejs
|               `-- bin
|                   `-- node
`-- main_.sh

17 directories, 9 files