Coder Social home page Coder Social logo

bazel-multiple-npm-packages-test's Introduction

bazel-multiple-npm-packages-test

A test of publishing multiple interdependent npm packages from a Bazel monorepo

Setup

To install dependencies, run yarn.

To demonstrate publishing to npm, this demo uses verdaccio, a private npm proxy. To install verdaccio, run:

yarn global add verdaccio

Then, run verdaccio and look for where its config file is loaded from (should be the first line logged). Edit the config to allow anyone to publish scoped packages and restart verdaccio:

config.yml
...
packages:
  '@*/*':
    # scoped packages                                                           
    access: $all
    publish: $anonymous
    unpublish: $anonymous
    proxy: npmjs
...

Examples

These examples mostly assume you're starting from scratch in a new repo (although they can apply to an existing repo given enough refactoring). Check the build_with_both directory for details on what I think is a good way to convert a package in a JS monorepo to use Bazel.

Bazel Primer

Bazel is an open-source build toolchain developed by Google. It uses BUILD files to define targets that can be built or run and dependencies between targets.

Compiling TypeScript

TypeScript is compiled by the ts_library rule. As an example, take a look at the foo_lib target in foo/BUILD.bazel:

ts_library(
    name = "foo_lib",
    module_name = "@test_scoped_repo/foo",
    visibility = ["//visibility:public"],
    srcs = [
        "foo.ts",
    ],
    deps = [
        "//foo/bla:bla_lib",
    ],
)

This target defines a TypeScript library named foo_lib that compiles the foo.ts source file and depends on the //foo/bla:bla_lib TypeScript library. It's publicly visible in the project and has the amd module name @test_scoped_reop/foo.

To compile this target, run bazel build //foo:foo_lib (or yarn bazel build //foo:foo_lib). If you look in the foo/ directory, you'll see that there are no new files created by building the target. That's because Bazel puts all of its outputs in an output directory somewhere else and places symlinks to that directory in the root of the project. In the case of this repo, the symlinks are located in dist/, but that can be configured by editing .bazelrc.

Take a look in dist/bin/foo/. That directory should contain the results of compiling foo.ts. It also contains the bla/ subdirectory, which has the results of compiling foo/bla/bla.ts, which foo.ts depends on. bla.ts was compiled because the foo_lib target listed bla_lib in its deps attribute. For more information on how to declare these dependencies, see the documentation on Bazel Labels and the ts_library documentation.

Writing Tests

rules_nodejs provides the jasmine_node_test rule for running jasmine tests. As an example, we'll look at how to test the foo_lib target.

Since foo_test.ts is written in TypeScript but jasmine_node_test requires JavaScript inputs, we first declare a ts_library target named foo_test_lib to compile it. since foo_test_lib depends on foo.ts, it needs the :foo_lib target in its deps attribute. It also needs jasmine typings, so we add @npm//@types/jasmine to its deps (rules_nodejs automatically generates targets for all installed npm packages. Note that we're actually using yarn, but the convention is to use the name npm for the generated workspace's name).

foo_test_lib now compiles to a .js file (dist/bin/foo/foo_test.js) that jasmine can run. Instead of running this file with jasmine, we'll use the jasmine_node_test rule to run it by creating a new target named foo_test and passing it the :foo_test_lib target as a source.

ts_library(
    name = "foo_test_lib",
    testonly = True,
    srcs = [
        "foo_test.ts",
    ],
    deps = [
        ":foo_lib",
        "@npm//@types/jasmine",
    ],
)

jasmine_node_test(
    name = "foo_test",
    srcs = [
        ":foo_test_lib",
    ],
)

To run the test target, run bazel run //foo:foo_test, or run bazel test //foo:foo_test. By default, bazel test shows minimal information about the test, just printing whether it passed or failed, and is best used for running multiple tests at once.

Publishing to npm

Alex Eagle has a great writeup on how to do this. This section covers how it's done in this repo.

rules_nodejs provides the pkg_npm rule for taring and publishing a package to npm, but there are a few caveats to keep in mind when doing this.

  1. The package needs its own package.json that declares its dependencies and name.
  2. The package name in package.json should be the same as the module_name in the root ts_library. All other importable ts_library targets should also set module_name to the corresponding path relative to where they appear in the filetree (take a look at foo/bla for an example). This makes sure imports look the same whether the module is loaded from bazel or from npm and is why the bar package works in bazel and in npm.

To publish foo and bar to npm (verdaccio), start verdaccio and run yarn publish-all in the root of the repo. This will run the following commands:

bazel run //foo:foo_pkg.publish -- --registry http://localhost:4873
bazel run //bar:bar_pkg.publish -- --registry http://localhost:4873

To simulate an external user consuming the packages, cd to external_package and run yarn install-local (to use verdaccio). Run yarn tsc to build and node dist/external_package.js to run the result.

bazel-multiple-npm-packages-test's People

Contributors

mattsoulanille avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.