In this case we use Vite to build a TypeScript React app, and Bazel to build the app and run tests.
The approach in this example also works with local development through pnpm
as developers are used to.
We use rules_js to handle the JavaScript ecosystem in Bazel.
Bazel only handles packages from the pnpm-lock.yaml
at the workspace root, so when you make changes to package.json remember to run pnpm install
afterward.
To see the setup for pnpm, check the npm_translate_lock function in MODULE.bazel at root.
In the BUILD.bazel
file for this case, there are some new concepts:
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@npm//workshop/case5:typescript/package_json.bzl", typescript_bin = "bin")
npm_link_all_packages(name = "node_modules")
The @npm//
namespace is generated by the npm_translate_lock
function in the root MODULE.bazel
.
This namespace contains generated Starlark targets for all packages in the pnpm-lock.yaml
file.
The typescript_bin = "bin"
in the load
statement is a reference to the bin
field in the package.json
for the typescript
package.
This makes it possible to run the tsc
directly in Bazel with typescript_bin.tsc
. There are also some other targets which are generated, like typescript_bin.tsc_test
for running the tsc
binary as a test instead.
You can also run typescript_bin.tsc_binary
which is a binary target for the tsc
binary if you need to run sideeffects.
See more about these features at the rules_js docs
To make your IDE happy when using local workspace packages, you have to extra paths to the Bazel output in your tsconfig.json
:
{
"compilerOptions": {
"paths": {
"openapi_typescript/*": [
"../../bazel-bin/workshop/case3/pkg/*"
]
}
}
}
See more about this in the rules_js FAQ in this case.
bazel build //workshop/case5:build
bazel run //workshop/case5:dev
- note that this does not notice changed files in the workspace, so you have to restart the command to see changes.
To get hot reloading through Bazel you need to use ibazel, see bazel-watcher.
Then you can run ibazel run //workshop/case5:dev
or npx @bazel/ibazel run //workshop/case5:dev
instead.
Dev mode also works through cd workshop/case5 && pnpm i && pnpm run dev
, which goes outside of Bazel
bazel run //workshop/case5:tarball
builds an OCI compatible image and loads it into your Docker context.
Afterwards, you can run the application with docker run --rm -it -p80:80 case5:latest
http://localhost
You can run bazel cquery //workshop/case5:<target> --output=files
to get the files output for a given target.
If you run bazel cquery //workshop/case5:tar --output=files
you will get the tar layer for application code.
You can then inspect the tar by running tar -tvf bazel-bin/workshop/case5/tar.tar
:
drwxr-xr-x 0 0 0 0 1 jan 2000 usr/
drwxr-xr-x 0 0 0 0 1 jan 2000 usr/share/
drwxr-xr-x 0 0 0 0 1 jan 2000 usr/share/nginx/
drwxr-xr-x 0 0 0 0 1 jan 2000 usr/share/nginx/html/
drwxr-xr-x 0 0 0 0 1 jan 2000 usr/share/nginx/html/assets/
-rw-r--r-- 0 0 0 142531 1 jan 2000 usr/share/nginx/html/assets/index-DDIbAWc_.js
-rw-r--r-- 0 0 0 334 1 jan 2000 usr/share/nginx/html/index.html
Can you include the greeting-component in the app?
Check out rules_swc for an example on how to transpile TypeScript to JavaScript with Bazel. This could be useful if you want to reuse the JavaScript in tests to avoid multiple transpilations.