Search code examples
node.jstypescriptbazellernabazel-rules

Bazel using with lerna and yarn workspace


Many people are using lerna and/or yarn workspace.

I guess either migrating from them to Bazel, or just using them with Bazel together is good to be guided with an example project.

For example, currently, I have a directory structure like this, where foo is an express server and bar is a library consumed by foo, both based on typescript.

<project root>
├── jest.config.js
├── lerna.json
├── package.json
├── packages
│   ├── bar
│   │   ├── jest.config.js
│   │   ├── package.json
│   │   ├── src
│   │   │   └── index.ts
│   │   ├── test
│   │   │   └── unit
│   │   │       └── index.test.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   └── foo
│       ├── jest.config.js
│       ├── package.json
│       ├── src
│       │   ├── hello.ts
│       │   └── index.ts
│       ├── test
│       │   ├── integration
│       │   │   └── index.test.ts
│       │   └── unit
│       │       └── index.test.ts
│       ├── tsconfig.build.json
│       └── tsconfig.json
├── tsconfig.build.json
├── tsconfig.json
└── yarn.lock

How should I align it with Bazel, like you know, WORKSPACE, BUILD, and their contents?

Any tips or examples?

Thanks!


Solution

  • There are some examples of repo structures somewhat similar to this in the rules_nodejs examples directory. This shows (in this case an Angular app) having shared libs and consuming them, but the principle is the same here.

    Generally, you'd only have one WORKSPACE file in the root of your project. While it's possible to have multiple package.json files for different apps and libs, it adds some extra complexity to the ts_library rules which, for getting started, may be best avoided. This example repo shows multiple package.json files, but without Typescript.

    For BUILD (or BUILD.bazel) files, the minimum you'll need here is one in foo and one in bar (and one at the root). The more BUILD files you have, the more you split up the compilation units for your source, therefore increasing incrementality.

    Then add ts_library rules to those BUILD files, docs for which can be found here, they also show the differences between using tsc directly and ts_library. You can then define source dependencies between foo and bar, a quick example shown below:

    packages/foo/BUILD:

    ts_libaray(
      name = "foo",
      srcs = glob(["src/**/*.ts"]),
      deps = [
        "//packages/bar", <-- this is the source dep for bar
        "@npm//some-package",
      ],
    )
    

    packages/bar/BUILD:

    ts_libaray(
      name = "bar",
      srcs = glob(["src/**/*.ts"]),
      deps = [
        "@npm//some-other-package",
      ],
    )