<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bazel</title>
    <description>The latest articles on DEV Community by Bazel (@bazel).</description>
    <link>https://dev.to/bazel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1315%2F386196b8-a560-4d74-83a6-aa8fae70822c.png</url>
      <title>DEV Community: Bazel</title>
      <link>https://dev.to/bazel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bazel"/>
    <language>en</language>
    <item>
      <title>Stamping Bazel builds with selective delivery</title>
      <dc:creator>Alex 🦅 Eagle</dc:creator>
      <pubDate>Fri, 22 Oct 2021 04:03:36 +0000</pubDate>
      <link>https://dev.to/bazel/stamping-bazel-builds-with-selective-delivery-56o3</link>
      <guid>https://dev.to/bazel/stamping-bazel-builds-with-selective-delivery-56o3</guid>
      <description>&lt;p&gt;The obvious next step after building a nice CI pipeline around Bazel is Continuous Deployment. So no surprise that one of the frequent questions on Bazel slack is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do I release the artifacts built by Bazel?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and the answer is really not well documented anywhere. Here's what I've learned.&lt;/p&gt;

&lt;h1&gt;
  
  
  Stamping
&lt;/h1&gt;

&lt;p&gt;Bazel is mostly unaware of version control, and that's good because coupling causes intended feature interactions. But sometimes you want the git SHA to appear in the binary so your monitoring system can tell which version is crash-looping. This is where stamping is used. Bazel keeps two files sitting in &lt;code&gt;bazel-out&lt;/code&gt; all the time, &lt;code&gt;stable-status.txt&lt;/code&gt; and &lt;code&gt;volatile-status.txt&lt;/code&gt;, which are populated from local environment info like the hostname, and can be inputs to build actions.&lt;/p&gt;

&lt;p&gt;The files are just sitting there in the output tree after any build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat bazel-out/stable-status.txt 
BUILD_EMBED_LABEL 
BUILD_HOST system76-pc
BUILD_USER alexeagle
$ cat bazel-out/volatile-status.txt 
BUILD_TIMESTAMP 1634865540
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You can fill in more values in this file by adding &lt;code&gt;--workspace_status_command=path/to/my_script.sh&lt;/code&gt; to your .bazelrc and writing a script that emits values, often by calling &lt;code&gt;git&lt;/code&gt;. Note that adding this flag to every build can mean slow git operations slowing down developers, so you might want to include this flag only on CI.&lt;br&gt;
As an aside, instead of just a git SHA let me recommend &lt;a href="https://twitter.com/jakeherringbone/status/1324871225898749953"&gt;https://twitter.com/jakeherringbone/status/1324871225898749953&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The "stable" statuses are meant to be relatively constant over rebuilds on your machine. So your username is stable. The stable status file is part of Bazel's cache key for actions. So if your value of &lt;code&gt;--embed_label&lt;/code&gt; changes, it will be reflected in the BUILD_EMBED_LABEL line of stable-status.txt and you'll get a cache miss for every stamped action. They will be re-run to find out the new value.&lt;/p&gt;

&lt;p&gt;The "volatile" statuses change all the time, like the timestamp. These are not part of an action key, as that would make the cache useless.&lt;/p&gt;

&lt;p&gt;Bazel only rebuilds an artifact if the stable stamp or one of the declared inputs changes. Otherwise you can get a cache hit, with a stale value of a volatile stamp.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Due to using a volatile stamp, we had a bug when we made Angular's release process. As a workaround, to make sure all the artifacts were versioned together, we had to do a clean build when releasing. I always felt bad for whoever was doing the push on their laptop and waiting.&lt;br&gt;
This was the wrong approach, it should have used stable stamping.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  When to stamp
&lt;/h1&gt;

&lt;p&gt;Bazel has a flag &lt;code&gt;--stamp&lt;/code&gt;. Very sadly, it is not exposed to Bazel rules in any consistent way, and so many rules have a fixed boolean attribute &lt;code&gt;stamp = True|False&lt;/code&gt;. This inconsistency is too bad, and causes a lot of friction around correct stamping.&lt;/p&gt;

&lt;p&gt;You should not enable &lt;code&gt;--stamp&lt;/code&gt; on your CI builds. When any stable status value changes, you'll bust the cache and re-do a lot of work. Even if you don't use stable status values, some ruleset you depend on might.&lt;/p&gt;

&lt;p&gt;This is also a key element of how we'll find the changed artifacts later. We don't want any stamp info in them at all, so their content hash is deterministic.&lt;/p&gt;

&lt;h1&gt;
  
  
  Finding the releasable artifacts
&lt;/h1&gt;

&lt;p&gt;Use a custom Bazel rule to describe your release artifacts. Delivery styles vary a lot, so I haven't seen one of these that works for everyone. The custom rule can produce a manifest file of whatever info your continuous delivery system needs to know.&lt;/p&gt;

&lt;p&gt;After a green CI build and test step, your pipeline should use bazel query to find all of the release artifacts.&lt;/p&gt;

&lt;h1&gt;
  
  
  Selective release
&lt;/h1&gt;

&lt;p&gt;We could release everything all the time, but &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we don't want to push duplicate artifacts&lt;/li&gt;
&lt;li&gt;stamped artifacts should always reflect the version info of the last change that affected them&lt;/li&gt;
&lt;li&gt;downstream systems will be confusing for users to operate since there are too many versions to pick from&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the recipe:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CI already ran without --stamp, so the release artifacts are deterministic from sources.&lt;/li&gt;
&lt;li&gt;Query for the release artifacts and loop over them&lt;/li&gt;
&lt;li&gt;for each artifact, compute the content hash (or just take the existing .digest output from sth like docker that supplies it)&lt;/li&gt;
&lt;li&gt;run a reliable key/value store to act like a bloom filter (Redis SETNX is good for this) which quickly tells you that the content hash is different than before&lt;/li&gt;
&lt;li&gt;loop over these newly-seen artifacts labels and run again with &lt;code&gt;bazel run --stamp thing.deploy&lt;/code&gt; or whatever you need to do to promote them to the next stage in the CD pipeline&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since most of the actions in the dependency graph shouldn't be stamp-aware, the last step here should still be fairly incremental.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Bazel can write to the source folder!</title>
      <dc:creator>Alex 🦅 Eagle</dc:creator>
      <pubDate>Thu, 21 Oct 2021 15:19:01 +0000</pubDate>
      <link>https://dev.to/bazel/bazel-can-write-to-the-source-folder-b9b</link>
      <guid>https://dev.to/bazel/bazel-can-write-to-the-source-folder-b9b</guid>
      <description>&lt;p&gt;Bazel is Google's open-sourced build tool. When used internally at Google, it comes along with a bunch of idioms which Googlers naturally take for granted, and associate with Bazel. These can accidentally become part of the accepted dogma around Bazel migration.&lt;/p&gt;

&lt;p&gt;Most frequently, the accident I see is a false perception "Bazel cannot write to the source folder, so you can no longer check in generated files, nor have them in the sources but ignored from VCS".&lt;/p&gt;

&lt;h2&gt;
  
  
  Typically you shouldn't do it
&lt;/h2&gt;

&lt;p&gt;Intermediate outputs in Bazel are meant to be used directly as inputs to another target in the build. For example, if you generate language-specific client stubs from a &lt;code&gt;.proto&lt;/code&gt; file, those stay in the &lt;code&gt;bazel-out&lt;/code&gt; folder and a later compiler step should be configured to read them from there.&lt;/p&gt;

&lt;p&gt;However there are plenty of cases where outputs do need to go in the source folder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workaround for an editor plugin that only knows to read in the source folder and can't be configured to look in bazel-out&lt;/li&gt;
&lt;li&gt;"golden" or "snapshot" files used for tests&lt;/li&gt;
&lt;li&gt;generated documentation that's checked in next to sources&lt;/li&gt;
&lt;li&gt;files that you need to be able to search or browse from your version control GUI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Yes you can do it
&lt;/h2&gt;

&lt;p&gt;If you restrict yourself to only &lt;code&gt;bazel build&lt;/code&gt; and &lt;code&gt;bazel test&lt;/code&gt;, then it's true that neither of these commands can mutate the source tree. Bazel is strictly a transform tool from the sources to its own bazel-out folder. However, &lt;code&gt;bazel run&lt;/code&gt; has no such limitation, and in fact always sets an environment variable &lt;code&gt;BUILD_WORKSPACE_DIRECTORY&lt;/code&gt; which makes it easy to find your sources and modify them.&lt;/p&gt;

&lt;p&gt;This leads us to the "Write to Sources" pattern for Bazel. We'll use &lt;code&gt;bazel run&lt;/code&gt; to make the updates, and &lt;code&gt;bazel test&lt;/code&gt; to make sure developers don't allow the file in the source folder to drift from what Bazel generates.&lt;/p&gt;

&lt;p&gt;Here's the basic recipe, which I've adapted to many scenarios. For example, many of the core Bazel rulesets now use this pattern to keep their generated API markdown files in sync with the sources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@bazel_skylib//rules:diff_test.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"diff_test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@bazel_skylib//rules:write_file.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"write_file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Config:
# Map from some source file to a target that produces it.
# This recipe assumes you already have some such targets.
&lt;/span&gt;&lt;span class="n"&gt;_GENERATED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"some-source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"//:generated.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Create a test target for each file that Bazel should
# write to the source tree.
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;diff_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"check_"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;# Make it trivial for devs to understand that if
&lt;/span&gt;        &lt;span class="c1"&gt;# this test fails, they just need to run the updater
&lt;/span&gt;        &lt;span class="c1"&gt;# Note, you need bazel-skylib version 1.1.1 or greater
&lt;/span&gt;        &lt;span class="c1"&gt;# to get the failure_message attribute
&lt;/span&gt;        &lt;span class="n"&gt;failure_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Please run:  bazel run //:update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;file1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;file2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_GENERATED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Generate the updater script so there's only one target for devs to run,
# even if many generated files are in the source folder.
&lt;/span&gt;&lt;span class="n"&gt;write_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gen_update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"update.sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;# This depends on bash, would need tweaks for Windows
&lt;/span&gt;        &lt;span class="s"&gt;"#!/usr/bin/env bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;# Bazel gives us a way to access the source folder!
&lt;/span&gt;        &lt;span class="s"&gt;"cd $BUILD_WORKSPACE_DIRECTORY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;# Paths are now relative to the workspace.
&lt;/span&gt;        &lt;span class="c1"&gt;# We can copy files from bazel-bin to the sources
&lt;/span&gt;        &lt;span class="s"&gt;"cp -fv bazel-bin/{1} {0}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;# Convert label to path
&lt;/span&gt;            &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_GENERATED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# This is what you can `bazel run` and it can write to the source folder
&lt;/span&gt;&lt;span class="n"&gt;sh_binary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;srcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"update.sh"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_GENERATED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may want to tweak the recipe, for example if the output files are markdown I'll append ".md" to the keys. If your files follow a convention you might be able to configure it with just a list rather than a dictionary.&lt;/p&gt;

&lt;p&gt;Note that this pattern does have one downside, compared with build tools that allow a build to directly output into the source tree. Until you run the tests, it's possible that you're working against an out-of-date file in the source folder. This could mean you spend some time developing, only to find on CI that the generated file needs to be updated, and then after updating it, you have to make some fixes to the code you wrote.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Angular ❤️ Bazel leaving Angular Labs</title>
      <dc:creator>Alex 🦅 Eagle</dc:creator>
      <pubDate>Fri, 29 May 2020 03:00:48 +0000</pubDate>
      <link>https://dev.to/bazel/angular-bazel-leaving-angular-labs-51ja</link>
      <guid>https://dev.to/bazel/angular-bazel-leaving-angular-labs-51ja</guid>
      <description>&lt;p&gt;With Angular 9.0 released, including the new Ivy compiler and runtime, it's a good time to ask "what's next for Angular?". You might even ask "is Bazel coming next?". The short answer is: we are spinning off the Bazel effort to be independent of Angular, and to work for ALL frontend frameworks or Node.js backends. However, Bazel will never be the default build tool in Angular CLI, and we expect that most applications will not switch.&lt;/p&gt;

&lt;h1&gt;
  
  
  What we've learned
&lt;/h1&gt;

&lt;p&gt;We've been working on Angular with Bazel for a few years. As a quick refresher, Bazel is Google's build tool which is incremental - a small change results in a small re-build/test. It also lets your build steps use a shared cache and execute remotely in parallel on a farm of machines. It's the key to Google's ability to write large applications with thousands of engineers in a massive monorepo. For Angular to be usable internally at Google, the team must maintain Angular+Bazel for Google engineers.&lt;/p&gt;

&lt;p&gt;Bazel has been available in Angular Labs as an opt-in preview for over a year, which gave us a chance to put some miles on it and learn from users. We do have several companies relying on this toolchain, and I've heard from a couple of them who plan to write up a case study about the benefits they've gotten.&lt;/p&gt;

&lt;p&gt;One thing we've learned is that most Angular applications don't have the problem Bazel solves. For these applications, we don't want to introduce another complex bit of build system machinery - no matter how well we encapsulate it in the Angular CLI, it's a leaky abstraction and you'll probably encounter Bazel as an end user. For this reason, we don't intend to ever make it the default for Angular CLI users.&lt;/p&gt;

&lt;p&gt;Another thing we've learned is that Bazel migration should happen in tiny steps. Any breaking change is a major obstacle for enterprise apps. Bazel can run any toolchain: while Bazel is responsible for calculating which build steps need to re-run, it doesn't care what those steps do. This means we have the option of migrating to Bazel while keeping the toolchain the same. For Angular developers, this means that every application which works with the CLI should work with Bazel.&lt;/p&gt;

&lt;p&gt;We have tried a few approaches for that migration. First, in Angular 4 we introduced support for Google's Closure Compiler. This produces the smallest bundles, but it's an expert tool that requires a lot of work to adopt. Then we introduced a hybrid toolchain, using Google's approach for compiling TypeScript, Angular, Sass, and so on, but with Rollup as the bundler. This is a lot more usable, but still not always a drop-in replacement; migrating to Google's tooling still has some cost.&lt;/p&gt;

&lt;h1&gt;
  
  
  Generalizing Bazel
&lt;/h1&gt;

&lt;p&gt;So essentially, we had hoped to export the Google-internal toolchain, but it has some incompatibilities and even the smallest incompatibility is unacceptable. So late last year, we released a 1.0 stable version of Bazel's JavaScript support (rules_nodejs) with a novel feature: run &lt;em&gt;any&lt;/em&gt; JS ecosystem tool under Bazel without any custom plugin code (Bazel calls these "rules").&lt;/p&gt;

&lt;p&gt;I wrote about this in &lt;a href="https://dev.to/bazel/layering-in-bazel-for-web-389h"&gt;Layering in Bazel for Web&lt;/a&gt;. The TL;DR of that article: if you install some JS tooling of your choice, say&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;mocha domino @babel/core @babel/cli @babel/preset-env http-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you can now configure Bazel to use that toolchain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@npm//@babel/cli:index.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"babel"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@npm//mocha:index.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"mocha_test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@npm//http-server:index.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http_server"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;babel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"compile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;outs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"app.es5.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;http_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s"&gt;"index.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"app.es5.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mocha_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"unit_tests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"*.spec.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does this mean for Angular developers? Well, since Bazel now runs any JS ecosystem tooling, it should be able to run exactly the tooling you're using today. To explain how we do that, we need to pick apart the Angular CLI a little.&lt;/p&gt;

&lt;p&gt;One simple model of Angular CLI is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ng&lt;/code&gt; command -&amp;gt; Builder -&amp;gt; webpack&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ng&lt;/code&gt; command reads your &lt;code&gt;angular.json&lt;/code&gt; file to find which Builder should be used. The Builder layer is internally called "Architect", so look in your &lt;code&gt;angular.json&lt;/code&gt; for a key "architect", and you'll see mappings for what builder to use. For example, say you run &lt;code&gt;ng build&lt;/code&gt;; the default builder is &lt;code&gt;@angular-devkit/build-angular:browser&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read more about Angular CLI builders in the &lt;a href="https://angular.io/guide/cli-builder"&gt;docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is actually a standalone program you could run outside of Angular CLI. The &lt;code&gt;@angular-devkit/architect-cli&lt;/code&gt; package provides a command-line tool called architect. So instead of &lt;code&gt;ng build&lt;/code&gt;, it's totally equivalent to peel off one layer of abstraction and run &lt;code&gt;npx architect frontend:build&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we can put the parts together. If Bazel runs arbitrary JS tooling, and we know how to run individual steps of your current Angular build using Architect, then we can have Bazel run the &lt;code&gt;architect&lt;/code&gt; CLI to exactly reproduce the build you're doing today. We have an &lt;a href="https://github.com/bazelbuild/rules_nodejs/blob/master/examples/angular_bazel_architect/"&gt;example app demonstrating this&lt;/a&gt; - if you look at the &lt;code&gt;BUILD.bazel&lt;/code&gt; file in the example you see that we just call the architect command when Bazel wants to build or test the Angular app.&lt;/p&gt;

&lt;h1&gt;
  
  
  What does this mean for me?
&lt;/h1&gt;

&lt;p&gt;First of all, if your team is satisfied with Angular CLI (or with Nx) then there is nothing for you to do. Bazel doesn't affect you and won't in the future.&lt;/p&gt;

&lt;p&gt;What if you do have a scaling problem with today's tooling? This is software engineering, so there are trade-offs. By making this build system 100% compatible with all existing Angular applications, we have lost some of the incrementality guarantees of Bazel. If we just run architect, the most granular our build can be is to have a bunch of Angular libraries, and an app that consumes them. Then only the affected libraries need to be re-built after a change. This is very similar to what Nx does.&lt;/p&gt;

&lt;p&gt;We think it's now possible to get the best possible on-ramp: first use Bazel to orchestrate your existing build steps, then customize the build graph to improve incrementality, starting from the slowest, most frequently-executed steps.&lt;/p&gt;

&lt;p&gt;There's another interesting consequence of this approach. Angular is not special, any frontend or Node.js backend code can be built by Bazel today without any work required from the team. For this reason, our plan is to migrate the Bazel-specific APIs (the &lt;code&gt;@angular/bazel&lt;/code&gt; package) out of Angular itself, and allow the Bazel effort to proceed totally decoupled from Angular teams goals. This gives the Bazel effort more autonomy, and means it immediately applies to React, Vue, Next.js, or any other framework/technology that provides a CLI.&lt;/p&gt;

&lt;p&gt;As for who supports what: I'm now working on rules_nodejs but no longer on the Angular team, so our layering is quite clear. Angular team supports the CLI builders, so any bugs you observe from using them can be reported to Angular. The orchestration of these builders is owned by rules_nodejs and we'll do our best to support you. Note that the latter is an all-volunteer OSS project.&lt;/p&gt;

&lt;p&gt;Here's a short summary of changes happening now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Angular is deprecating the &lt;code&gt;@angular/bazel&lt;/code&gt; package for v10, see &lt;a href="https://github.com/angular/angular/pull/37190"&gt;the Pull Request&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The Angular CLI builder is now in the &lt;a href="https://www.npmjs.com/package/@bazel/angular"&gt;&lt;code&gt;@bazel/angular&lt;/code&gt; package&lt;/a&gt; which is published from rules_nodejs&lt;/li&gt;
&lt;li&gt;There is no automatic Bazel configuration for now. We expect users will opt-in to using Bazel, so you'll have to configure it with WORKSPACE/BUILD files. There are a number of community-contributed tools for maintaining the config, such as &lt;a href="https://github.com/Evertz/bzlgen"&gt;Evertz/bzlgen&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;You no longer need the &lt;code&gt;ng_module&lt;/code&gt; Bazel rule which was in &lt;code&gt;@angular/bazel&lt;/code&gt;. The migration path is to use &lt;code&gt;ts_library&lt;/code&gt; with an Angular plugin. See &lt;a href="https://github.com/bazelbuild/rules_nodejs/tree/master/examples/angular"&gt;the canonical Angular example&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'll keep updating &lt;a href="https://github.com/bazelbuild/rules_nodejs/blob/master/docs/examples.md#angular"&gt;the docs&lt;/a&gt; and you can follow along with this effort in the #angular channel on &lt;a href="https://slack.bazel.build"&gt;https://slack.bazel.build&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm super excited to continue rolling out Bazel's unique capabilities to the frontend developer community! Thank you so much to all the contributors and users who have shaped this solution.&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
    <item>
      <title>Things a program must not do under Bazel</title>
      <dc:creator>Alex 🦅 Eagle</dc:creator>
      <pubDate>Thu, 24 Oct 2019 20:27:23 +0000</pubDate>
      <link>https://dev.to/bazel/things-a-program-must-not-do-under-bazel-38g9</link>
      <guid>https://dev.to/bazel/things-a-program-must-not-do-under-bazel-38g9</guid>
      <description>&lt;p&gt;Don't expect the environment to have implicit things like tools in the PATH. Bazel builds are meant to be portable so you can invoke them remotely or share cache hits with your coworkers. Be explicit about getting tools you need as inputs, or using Bazel's toolchain feature to locate them on the disk.&lt;/p&gt;

&lt;p&gt;Don't rely on the working directory to be next to the inputs. Bazel always sets the working directory in the root of the workspace, next to the WORKSPACE file. (Of course you can always chdir inside the process after Bazel starts it. In NodeJS, for example, you can do this with a &lt;a href="https://github.com/bazelbuild/rules_nodejs/issues/1840#issuecomment-619277667"&gt;&lt;code&gt;--require&lt;/code&gt; script&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Don't try to write to the sources. The input directory will be in a read-only filesystem by default. For example Angular CLI runs the &lt;code&gt;ngcc&lt;/code&gt; program which tries to edit &lt;code&gt;package.json&lt;/code&gt; files in the inputs:&lt;br&gt;
&lt;a href="https://github.com/angular/angular/pull/33366"&gt;https://github.com/angular/angular/pull/33366&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't try to write in a subdirectory of the sources either. Only write to the output directory.&lt;/p&gt;

&lt;p&gt;Don't resolve symlinks of the inputs. Node programs often try to read symlinks because of a common pattern of linking build outputs of one package to be dependencies of another. Bazel creates an execroot (for build actions) and a runfiles root (for test/run) filled with symlinks to sources or other outputs. Resolving the symlinks causes non-hermeticity by finding undeclared input files, or causes logic bugs in the program if it compares a symlink target path and expects them to be the same.&lt;/p&gt;

&lt;p&gt;Don't rely on stdin/stdout to communicate inputs and outputs. Bazel will sometimes use stdin for a protocol that communicates with the program, like worker mode or ibazel watch mode. It's possible to work around this with a genrule but that introduces a bash dependency.&lt;/p&gt;

&lt;p&gt;Don't rely on accepting all the configuration over command line arguments. You will likely run into argv length limits. Consider accepting a configuration file or params file with the CLI flags written into it.&lt;/p&gt;

&lt;p&gt;My earlier post about getting Nativescript tools to run under Bazel: &lt;a href="https://medium.com/@Jakeherringbone/running-tools-under-bazel-8aa416e7090c"&gt;https://medium.com/@Jakeherringbone/running-tools-under-bazel-8aa416e7090c&lt;/a&gt;&lt;/p&gt;

</description>
      <category>build</category>
    </item>
    <item>
      <title>Layering in Bazel for Web</title>
      <dc:creator>Alex 🦅 Eagle</dc:creator>
      <pubDate>Thu, 10 Oct 2019 13:59:58 +0000</pubDate>
      <link>https://dev.to/bazel/layering-in-bazel-for-web-389h</link>
      <guid>https://dev.to/bazel/layering-in-bazel-for-web-389h</guid>
      <description>&lt;h1&gt;
  
  
  Bazel is fast, general-purpose, and stable 1.0
&lt;/h1&gt;

&lt;p&gt;Bazel is a build tool that gives you a typical 10x improvement in your build and test times, using a deterministic dependency graph, a distributed cache of prior intermediate build results, and parallel execution over cloud workers.&lt;/p&gt;

&lt;p&gt;Bazel has &lt;a href="https://blog.bazel.build/2019/10/10/bazel-1.0.html"&gt;just released 1.0&lt;/a&gt; which is a huge deal. Congratulations to the Bazel team on this culmination of &lt;a href="https://blog.bazel.build/2015/03/27/Hello-World.html"&gt;over four years of hard work&lt;/a&gt;! Large companies cannot afford risks on beta software and need a guarantee of stability. Now that we have 1.0, Bazel is ready to use! But Bazel by itself is generally not sufficient.&lt;/p&gt;

&lt;p&gt;Bazel is like an execution engine. It's really the core of a build system, because it doesn't know how to build any particular language. You could use Bazel alone, in theory, using low-level primitives. But in practice you rely on a plugin to translate your higher-level build configuration into Actions, which are subprocesses Bazel spawns in a variety of ways like remote workers. So we see that Bazel is a layer beneath a variety of language-ecosystem-specific plugins.&lt;/p&gt;

&lt;p&gt;These plugins are called rules, and these are at a wide range of maturities. Some rules, like those for Java and C++, are distributed along with the Bazel core and are also mature. Some rules like .net and ruby are community contributed and not at a 1.0 quality.&lt;/p&gt;

&lt;h1&gt;
  
  
  Javascripters delight: Bazel can run almost any tool on npm
&lt;/h1&gt;

&lt;p&gt;The plugin I work on is for JavaScript/Node.js is getting close to 1.0 also, and is called rules_nodejs.&lt;/p&gt;

&lt;p&gt;Bazel just orchestrates the execution of the programs you tell it to run. &lt;em&gt;Any&lt;/em&gt; npm package that publishes a binary just works, without someone needing to write any Bazel plugin specific to that package. rules_nodejs has a "core" distribution that is just the stuff needed to teach Bazel how to run yarn/npm and consume the resulting packages. I'll get into more specifics about how we do it later, but let me first show you how it looks. You can skip to the final solution at &lt;a href="https://github.com/alexeagle/my_bazel_project"&gt;https://github.com/alexeagle/my_bazel_project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First you need Bazel with some accompanying config files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx @bazel/create my_bazel_project
&lt;span class="c"&gt;# If you used Bazel before, make sure you got @bazel/create version 0.38.2 or later so later steps will work&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my_bazel_project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;gives you a new workspace to play in.&lt;/p&gt;

&lt;p&gt;Now let's install some tools. For this example, we'll use Babel to transpile our JS, Mocha for running tests, and http-server to serve our app. This is just an arbitrary choice, you probably have some tools you already prefer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;mocha domino @babel/core @babel/cli @babel/preset-env http-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run these tools with Bazel. First we need to import them, using a &lt;code&gt;load&lt;/code&gt; statement.&lt;/p&gt;

&lt;p&gt;So edit &lt;code&gt;BUILD.bazel&lt;/code&gt; and add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@npm//@babel/cli:index.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"babel"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@npm//mocha:index.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"mocha_test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@npm//http-server:index.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http_server"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This shows us that rules_nodejs has told Bazel that a workspace named &lt;code&gt;@npm&lt;/code&gt; is available (think of the at-sign like a scoped package for Bazel). rules_nodejs will add &lt;code&gt;index.bzl&lt;/code&gt; files exposing all the binaries the package manager installed (same as the content of the &lt;code&gt;node_modules/.bin&lt;/code&gt; folder). The three tools we installed are in this &lt;code&gt;@npm&lt;/code&gt; scope and each has an index file with a &lt;code&gt;.bzl&lt;/code&gt; extension.&lt;/p&gt;

&lt;p&gt;Loading from these index files is just like importing symbols into your JavaScript file. Having made our &lt;code&gt;load()&lt;/code&gt;s we can now use them. Each of the symbols is a function that we call with some named parameter arguments.&lt;/p&gt;

&lt;p&gt;Now we write some JavaScript and some tests. To save time I won't go into that for this article.&lt;/p&gt;

&lt;p&gt;Okay, how will we build it? We need to think in terms of a graph of inputs, tools, and outputs, in order to express to Bazel what it needs to do to build a requested output, and how to cache the intermediate results.&lt;/p&gt;

&lt;p&gt;Add this to &lt;code&gt;BUILD.bazel&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;babel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"compile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s"&gt;"app.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"es5.babelrc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"@npm//@babel/preset-env"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;outs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"app.es5.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s"&gt;"app.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"--config-file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"$(location es5.babelrc)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"--out-file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"$(location app.es5.js)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This just calls the Babel CLI, so you can see their documentation for what arguments to pass. We use the &lt;code&gt;$(location)&lt;/code&gt; helper in Bazel so we don't need to hardcode paths to the inputs or outputs.&lt;/p&gt;

&lt;p&gt;We can try it already: &lt;code&gt;npm run build&lt;/code&gt;&lt;br&gt;
and we see the .js outputs from babel appear in the &lt;code&gt;dist/bin&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Let's serve the app to see how it looks, by adding to BUILD.bazel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;http_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s"&gt;"index.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"app.es5.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add to the &lt;code&gt;scripts&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;: &lt;code&gt;"serve": "ibazel run :server"&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ibazel is the watch mode for bazel.&lt;br&gt;
Note that on Windows, you need to pass &lt;code&gt;--enable_runfiles&lt;/code&gt; flag to Bazel. That's because Bazel creates a directory where inputs and outputs both appear together, for convenience.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we can serve the app: &lt;code&gt;npm run serve&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, let's run mocha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;mocha_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"unit_tests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"*.spec.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;"*.spec.js"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s"&gt;"@npm//domino"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"app.es5.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that we installed the domino package here so we could test the webapp including DOM interactions in node, which is faster than starting up a headless browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Run it:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ npm test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Without Bazel knowing anything about babel, http-server, or mocha, we just assembled a working, incremental, remote-executable toolchain for building our little app.&lt;/p&gt;

&lt;h2&gt;
  
  
  More examples
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Bazel running a React app written in TypeScript/Sass with Webpack: &lt;a href="https://github.com/bazelbuild/rules_nodejs/pull/1255"&gt;https://github.com/bazelbuild/rules_nodejs/pull/1255&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bazel running more mocha tests: &lt;a href="https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/webapp/BUILD.bazel#L34-L51"&gt;https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/webapp/BUILD.bazel#L34-L51&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bazel running TypeScript &lt;code&gt;tsc&lt;/code&gt;: &lt;a href="https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/app/BUILD.bazel#L51-L74"&gt;https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/app/BUILD.bazel#L51-L74&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bazel using Babel, then packing the resulting application into a Docker image: &lt;a href="https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/angular/src/BUILD.bazel#L131-L204"&gt;https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/angular/src/BUILD.bazel#L131-L204&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bazel runs Less and Stylus css preprocessors: &lt;a href="https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/app/styles/BUILD.bazel"&gt;https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/app/styles/BUILD.bazel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bazel using Google Closure Compiler for smallest bundle sizes: &lt;a href="https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/closure/BUILD.bazel#L4-L15"&gt;https://github.com/bazelbuild/rules_nodejs/blob/0.38.2/examples/closure/BUILD.bazel#L4-L15&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bazel running Nuxt.js build for server-side rendered Vue: &lt;a href="https://github.com/albttx/bazel-nuxt"&gt;https://github.com/albttx/bazel-nuxt&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Going further: custom rules and macros
&lt;/h1&gt;

&lt;p&gt;It's great that Bazel can run arbitrary npm tools, but this required that we know about the CLI arguments needed for these tools. It also wasn't very ergonomic (we had to use syntax like &lt;code&gt;$(location)&lt;/code&gt; to adapt to Bazel's paths), and we didn't take advantage of lots of Bazel features like workers (keep tools running in --watch mode), providers (let rules produce different outputs depending on what's requested) and a lot more.&lt;/p&gt;

&lt;p&gt;It also required too much learning and evaluating. Toolchain experts like the engineers on the Angular CLI team spend half their time understanding the capabilities and tradeoffs of the many available tools and choosing something good for you.&lt;/p&gt;

&lt;p&gt;As end-users we would get tired of assembling all our Bazel configuration out of individual tools, where our current experience is generally at a much higher level, and we expect a framework we use to provide a complete out-of-the-box build/serve/test toolchain. Bazel is perfect for toolchain experts to provide this developer experience.&lt;/p&gt;

&lt;p&gt;For example, Angular CLI has a "differential loading" feature where modern browsers can get smaller, modern JS without polyfills, in a way that doesn't break old browsers. This requires quite some tricks with the underlying tools.&lt;/p&gt;

&lt;p&gt;Angular CLI can make a differential loading toolchain using Bazel to compose the rules we saw above. Bazel has a high-level composition feature called macros. We can use a macro to simply wire together a series of tool CLI calls, and make that available to users. Let's say we want to let users call it this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@npm//http-server:index.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"http_server"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@cool-rules//:differential_loading.bzl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"differential_loading"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;differential_loading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;srcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;"*.ts"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="n"&gt;entry_point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"index.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;http_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;":app"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;templated_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we need a macro called &lt;code&gt;differential_loading&lt;/code&gt; that takes a bunch of TypeScript sources and an entry point for the app, and produces a directory that's ready to serve to both old and modern browsers.&lt;/p&gt;

&lt;p&gt;Here's what a toolchain vendor would write to implement differential loading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;differential_loading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entry_point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;srcs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"Common workflow to serve TypeScript to modern browsers"&lt;/span&gt;

    &lt;span class="n"&gt;ts_library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_lib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;srcs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;srcs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;rollup_bundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_chunks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_lib"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;sourcemap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"inline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;entry_points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;entry_point&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;output_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# For older browsers, we'll transform the output chunks to es5 + systemjs loader
&lt;/span&gt;    &lt;span class="n"&gt;babel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_chunks_es5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_chunks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"es5.babelrc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"@npm//@babel/preset-env"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;output_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s"&gt;"$(location %s_chunks)"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"--config-file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"$(location es5.babelrc)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"--out-dir"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"$@"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Run terser against both modern and legacy browser chunks
&lt;/span&gt;    &lt;span class="n"&gt;terser_minified&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_chunks_es5.min"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_chunks_es5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;terser_minified&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_chunks.min"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_chunks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;web_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;assets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s"&gt;"favicon.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_chunks.min"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"_chunks_es5.min"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;index_html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"index.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks long, but it's much simpler than what we've built in the current default for Angular CLI that uses pure Webpack. That's because the composition model here has clear separation of concerns between the different tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary: the layering
&lt;/h2&gt;

&lt;p&gt;Each layer can work on its own, but users prefer the higher level abstractions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Raw tool, like &lt;code&gt;babel&lt;/code&gt;: you can call this yourself to transpile JavaScript. These are written by lots of open-source contributors.&lt;/li&gt;
&lt;li&gt;Bazel: use low-level primitives to call &lt;code&gt;babel&lt;/code&gt; from a genrule, but tied to your machine. The Bazel team at Google supports this.&lt;/li&gt;
&lt;li&gt;Bazel + rules_nodejs: use the binary provided to load and run &lt;code&gt;babel&lt;/code&gt;. Written by the JavaScript build/serve team at Google.&lt;/li&gt;
&lt;li&gt;Bazel + custom rules/macros: use a higher level API to run a build without knowing the details. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I expect that more tooling vendors, such as CLI teams on various frameworks, will provide a high-level experience that uses Bazel under the covers. This lets them easily assemble toolchains from existing tools, using their standard CLI, and you get incremental, cacheable, and remote-parallelizable builds automatically.&lt;/p&gt;

</description>
      <category>bazel</category>
    </item>
  </channel>
</rss>
