See bazel.md for general bazel info/setup.
The sourcegraph client projects are setup to compile, bundle and test with Bazel. The tools used within Bazel include:
- Babel for ts[x] transpilation
- Webpack for bundling
- Jest, Mocha for testing
- esbuild for experimental bundling as well as internal tooling
- 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.
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}_pkgfor the npm package representing the pnpm project:testfor the Jest unit tests of the project:{name}_libfor compiling non-test*.ts\[x\]files:{name}_testsfor 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.
All client tests (of all types such as jest 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. Jest tests can be debugged using bazel run --config=debug //client/common:test.
Currently, it's impossible to use features that Babel will transpile, creating helper methods inside Puppeteer driver.page.evaluate calls. E.g., the for-of syntax transpiled by Babel creates a helper in the module's top-level scope and uses it in the evaluate call. But since the contents of the evaluate call are passed to the eval function inside Puppeteer, it doesn't have the reference to the created helper and fails in the runtime. This is caused by the fact that we uniformly transform all TS files to JS using Babel in Bazel. We will develop an approach that would allow skipping the Babel transpilation step for files executed only in the node environment.
The primary client/web bundle targets are:
//client/web:bundle//client/web:bundle-dev//client/web:bundle-enterpriseSeeclient/web/BUILD.
The client/web devserver can be run using bazel run //client/web:devserver
Most rules used throughout client/* are macros defined in tools/*.bzl to provide a consistent configuration used throughout the repo.
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?
- Examine the Bazel output logs: Scroll through and parse the Bazel output logs to find any reported errors, particularly missing modules or type declarations.
- 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. - 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
depsattribute in your primary target and include a# keepcomment to preventbazel configurefrom removing them. Be aware thatbazel configurecurrently 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). - Update the Bazel configuration: Run
bazel configureto update your Bazel build configuration. Note that thesrcsanddepsattributes of the primary targets are generated bybazel configure, and any manual changes to those attributes without the # keep comment will be overridden. - Leverage additional BUILD.bazel files: You can create additional
BUILD.bazelfiles in subdirectories to break down your project into smaller, independently cacheable targets. This can help improve build performance and simplify your build configuration.
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:
rawrfor use withbazel build(js_binary + js_run_binary internally)rawr_binaryfor use withbazel run(js_binary internally)rawr_testfor use withbazel test(js_test internally)
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.