Bazel for client

See Bazel at Sourcegraph for general bazel info/setup. See Overview of the Bazel configuration for client for in-depth configuration overview.

Tools

The sourcegraph client projects are setup to compile, bundle and test with Bazel. The tools used within Bazel include:

  • Esbuild for bundling
  • Vitest, Mocha for testing
  • Node tools such as graphql-codegen for generating graphql schema types

The Bazel rulesets used to support these include:

See Aspect rules docs for more information on the Bazel rulesets used.

Targets

The primary Bazel targets have been configured roughly aligning with the pnpm workspace projects, while often composed of many sub-targets. The primary targets for client/* pnpm projects are generated using bazel configure. The primary targets include:

  • :{name}_pkg for the npm package representing the pnpm project
  • :test for the Vitest unit tests of the project
  • :{name}_lib for compiling non-test *.ts\[x\] files
  • :{name}_tests for compiling unit test *.ts\[x\] files

Other targets may be configured per project such as sass compilation, graphql schema generation etc. See client/*/BUILD.bazel files for more details and examples.

The srcs and deps attributes of the prmiary targets are generated by bazel configure and any manual changes to those attributes will normally be overriden. If manual files/deps must be specified they must end with a # keep comment to ensure bazel configure does not remove them. Currently typescript type-only imports are not supported by bazel configure and must be manually added to the deps attribute, see https://github.com/aspect-build/aspect-cli/issues/404.

Additional BUILD.bazel files may exist throughout subdirectories and is encouraged to create many smaller independently cacheable targets.

Testing

All client tests (of all types such as Vitest and mocha) can be invoked by bazel test //client/... or individual tests can be specified such as bazel test //client/common:test or bazel test //client/web/src/end-to-end:e2e. Vitest tests can be debugged using bazel run --config=debug //client/common:test.

Bundling

The primary client/web bundle target is //client/web:bundle. See client/web/BUILD.bazel.

Rule configuration

Most rules used throughout client/* are macros defined in dev/*.bzl to provide a consistent configuration used throughout the repo.

FAQ

I encountered "bazel configure" failures on CI, and I'm not sure how to debug and fix the issue. What steps should I follow to resolve this?

  1. Examine the Bazel output logs: Scroll through and parse the Bazel output logs to find any reported errors, particularly missing modules or type declarations.
  2. Compare local and CI environments: Run the same failing test locally (e.g., bazel test //client/web:web_lib_typecheck_test) and compare the results with those on CI. This can help identify discrepancies between the two environments.
  3. Check for missing types: If you see errors related to missing types or modules in the Bazel logs, it's possible that some required dependencies are missing from your Bazel build file. To fix this, manually add the missing dependencies to the deps attribute in your primary target and include a # keep comment to prevent bazel configure from removing them. Be aware that bazel configure currently does not support TypeScript type-only imports, and these dependencies need to be added manually (see https://github.com/aspect-build/aspect-cli/issues/404).
  4. Update the Bazel configuration: Run bazel configure to update your Bazel build configuration. Note that the srcs and deps attributes of the primary targets are generated by bazel configure, and any manual changes to those attributes without the # keep comment will be overridden.
  5. Leverage additional BUILD.bazel files: You can create additional BUILD.bazel files in subdirectories to break down your project into smaller, independently cacheable targets. This can help improve build performance and simplify your build configuration.

I want to execute a js binary with bazel. How do I do that?

Lets say I want to execute a js binary called rawr . rules_js generates Starlark APIs for all dependencies defined in package.json, so to import the generated api for rawr we can do:

load("@npm//:rawr/package_json.bzl", my_alias = "bin")

With the above statement rules_js generated the following targets for rawr:

See the generated macro implementation here for more details.

Cool? I mean we technically have rawr now available but HTF do we use this? To create a build target using rawr we can now do:

my_alias.rawr (
  # js_binary attributes
  name = "rawr_event"
  srcs = ["earth.js],
  args = ["-event", "asteroid"],
)

To create a test target using rawr we can do (note the _test suffix):

my_alias.rawr_test (
  # js_test attributes
  name = "rawr_event_test"
  srcs = ["earth.js],
  args = ["-event", "asteroid", "-test"],
)

So now we have two targets that will execute the rawr js binary with different arguments:

bazel build //:rawr_event
bazel test //:rawr_event_test

An example of a js binary being executed as a bazel test target is graphql-schema-linter, whose definition can be found in cmd/frontend/graphqlbackend/BUILD.bazel.

How do I build/test Bazel targets of a specific type for all client packages?

Using Bazel, you can build or test specific targets across all client packages. This can be done by leveraging Bazel's query and test commands. The test command is used to build and run all test targets. However, with the help of query, we can filter out the specific targets we want to build and test.

For example, to check all Typescript types across all client packages locally, use:

bazel test `bazel query 'attr("name", ".*_typecheck_test", //...)'`
  1. bazel test: Commands Bazel to build and run specified test targets.
  2. bazel query 'attr("name", ".*_typecheck_test", //...)': Sub-command that specifies the targets for test. It queries for all targets whose name ends with _typecheck_test in all packages (//...).

If you want to run tests for a specific package, replace //... with the package path like //client/vscode....

bazel test `bazel query 'attr("name", ".*_typecheck_test", //client/vscode...)'`

How do I run ESLint on a client package?

Similar to the above, we can use bazel query to find all target names ending with _eslint and test them:

bazel test `bazel query 'attr("name", ".*_eslint$", //client/wildcard/...)'`