blob: f0b74810a47232ffb6167d621fcd06f7528555dc [file] [log] [blame] [edit]
<!DOCTYPE html>
<html itemscope itemtype="https://schema.org/WebPage" lang="en">
<head>
<meta charset="utf-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1" name="viewport">
<link href="/rules_nodejs/stamping.html" rel="canonical">
<link href="" rel="shortcut icon" type="image/png">
<title>rules_nodejs - Home</title>
<!-- Webfont -->
<link href="//fonts.googleapis.com/css?family=Source+Code+Pro:400,500,700|Open+Sans:400,600,700,800" rel="stylesheet">
<!-- Bootstrap -->
<link crossorigin="anonymous" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" rel="stylesheet">
<!-- Font Awesome -->
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- Custom stylesheet -->
<link href="/rules_nodejs/css/main.css" rel="stylesheet">
<!-- metadata -->
<meta content="rules_nodejs" name="og:title"/>
<meta content="JavaScript and NodeJS rules for Bazel" name="og:description"/>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top" id="common-nav">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button class="navbar-toggle collapsed" data-target="#bs-example-navbar-collapse-1" data-toggle="collapse"
type="button">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/rules_nodejs/">
<img class="navbar-logo" src="/rules_nodejs/images/bazel-navbar.svg">
</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<form class="navbar-form navbar-right" action="/rules_nodejs/search.html" id="cse-search-box">
<div class="form-group">
<input type="hidden" name="cx" value="2735dc72dd157bd19">
<input type="search" name="q" id="q" class="form-control input-sm" placeholder="Search">
</div>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="https://github.com/bazelbuild/rules_nodejs">GitHub</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container vpad">
<div class="row">
<div class="col-md-2">
<a aria-controls="sidebar-nav"
aria-expanded="false" class="btn btn-default btn-lg btn-block sidebar-toggle" data-toggle="collapse"
href="#sidebar-nav">
<i class="glyphicon glyphicon-menu-hamburger"></i> Navigation
</a>
<nav class="sidebar collapse" id="sidebar-nav">
<h3>rules_nodejs</h3>
<ul class="sidebar-nav">
<li><a href="/rules_nodejs/">Introduction</a></li>
<li><a href="install.html">Installation</a></li>
<li><a href="repositories.html">Repositories</a></li>
<li><a href="dependencies.html">Dependencies</a></li>
<li><a href="debugging.html">Debugging</a></li>
<li><a href="stamping.html">Stamping</a></li>
<li><a href="changing-rules.html">Making changes to rules_nodejs</a></li>
<li><a href="examples.html">Examples</a></li>
</ul>
<h3>Rules</h3>
<ul class="sidebar-nav">
<li><a href="/rules_nodejs/Built-ins.html">Built-ins</a></li>
<li><a href="/rules_nodejs/Cypress.html">Cypress</a></li>
<li><a href="/rules_nodejs/Jasmine.html">Jasmine</a></li>
<li><a href="/rules_nodejs/Karma.html">Karma</a></li>
<li><a href="/rules_nodejs/Labs.html">Labs</a></li>
<li><a href="/rules_nodejs/Protractor.html">Protractor</a></li>
<li><a href="/rules_nodejs/Rollup.html">Rollup</a></li>
<li><a href="/rules_nodejs/Terser.html">Terser</a></li>
<li><a href="/rules_nodejs/TypeScript.html">TypeScript</a></li>
</ul>
<h3>Community</h3>
<ul class="sidebar-nav">
<li><a href="https://github.com/bazelbuild/rules_nodejs/blob/master/CONTRIBUTING.md">Contribute to
rules_nodejs</a></li>
<li><a href="https://slack.bazel.build">Join #javascript on Slack</a></li>
<li><a href="https://github.com/bazelbuild/rules_nodejs/issues">Issue Tracker</a></li>
<li><a href="https://github.com/bazelbuild/rules_nodejs">Github</a></li>
</ul>
</nav>
</div>
<div class="col-md-8">
<div class="content">
<h1 id="stamping">Stamping</h1>
<p>Bazel is generally only a build tool, and is unaware of your version control system.
However, when publishing releases, you may want to embed version information in the resulting distribution.
Bazel supports this with the concept of a “Workspace status” which is evaluated before each build.
See <a href="https://docs.bazel.build/versions/master/user-manual.html#workspace_status">the Bazel workspace status docs</a></p>
<p>To stamp a build, you must pass the <code class="language-plaintext highlighter-rouge">--stamp</code> argument to Bazel.</p>
<p>Stamping is typically performed on a later action in the graph, like on a packaging rule (<code class="language-plaintext highlighter-rouge">pkg_*</code>). This means that
a changed status variable only causes re-packaging, not re-compilation and thus does not cause cascading re-builds.</p>
<p>Bazel provides a couple of statuses by default, such as <code class="language-plaintext highlighter-rouge">BUILD_EMBED_LABEL</code> which is the value of the <code class="language-plaintext highlighter-rouge">--embed_label</code>
argument, as well as <code class="language-plaintext highlighter-rouge">BUILD_HOST</code> and <code class="language-plaintext highlighter-rouge">BUILD_USER</code>. You can supply more with the workspace status script, see below.</p>
<p>Some rules accept an attribute that uses the status variables.</p>
<h2 id="substitutions-attribute">Substitutions attribute</h2>
<p>In a <code class="language-plaintext highlighter-rouge">pkg_npm</code> or <code class="language-plaintext highlighter-rouge">pkg_web</code> you can use the <code class="language-plaintext highlighter-rouge">substitutions</code> attribute like:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pkg_npm</span><span class="p">(</span>
<span class="n">name</span> <span class="o">=</span> <span class="s">"npm_package"</span><span class="p">,</span>
<span class="n">substitutions</span> <span class="o">=</span> <span class="p">{</span><span class="s">"0.0.0-PLACEHOLDER"</span><span class="p">:</span> <span class="s">"{STABLE_GIT_COMMIT}"</span><span class="p">},</span>
<span class="p">)</span>
</code></pre></div></div>
<p>In a <code class="language-plaintext highlighter-rouge">--stamp</code> build, this will replace the string “0.0.0-PLACEHOLDER” in any file included in the package with the current value of the <code class="language-plaintext highlighter-rouge">STABLE_GIT_COMMIT</code> variable.
However without stamping the placeholder will be left as-is.</p>
<h2 id="read-the-status-files">Read the status files</h2>
<p>The <code class="language-plaintext highlighter-rouge">rollup_bundle</code> rule just exposes the Bazel status files so that your custom <code class="language-plaintext highlighter-rouge">rollup.config.js</code> can read it.
See <a href="Rollup">Rollup</a>.</p>
<h2 id="stamping-with-a-workspace-status-script">Stamping with a Workspace status script</h2>
<p>To define additional statuses, pass the <code class="language-plaintext highlighter-rouge">--workspace_status_command</code> argument to <code class="language-plaintext highlighter-rouge">bazel</code>.
The value of this flag is a path to a script that prints space-separated key/value pairs, one per line, such as</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="nb">echo </span>STABLE_GIT_COMMIT <span class="si">$(</span>git rev-parse HEAD<span class="si">)</span>
</code></pre></div></div>
<blockquote>
<p>For a more full-featured script, take a look at the <a href="https://github.com/angular/angular/blob/master/tools/bazel_stamp_vars.sh">bazel_stamp_vars in Angular</a></p>
</blockquote>
<p>Make sure you set the executable bit, eg. <code class="language-plaintext highlighter-rouge">chmod 755 tools/bazel_stamp_vars.sh</code>.</p>
<blockquote>
<p><strong>NOTE</strong> keys start start with <code class="language-plaintext highlighter-rouge">STABLE_</code> will cause a re-build when they change.
Other keys will NOT cause a re-build, so stale values can appear in your app.
Non-stable (volatile) keys should typically be things like timestamps that always vary between builds.</p>
</blockquote>
<p>You might like to encode your setup using an entry in <code class="language-plaintext highlighter-rouge">.bazelrc</code> such as:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># This tells Bazel how to interact with the version control system</span>
<span class="c"># Enable this with --config=release</span>
build:release <span class="nt">--stamp</span> <span class="nt">--workspace_status_command</span><span class="o">=</span>./tools/bazel_stamp_vars.sh
</code></pre></div></div>
<h2 id="release-script">Release script</h2>
<p>If you publish more than one package from your workspace, you might want a release script around Bazel.
A nice pattern is to do a <code class="language-plaintext highlighter-rouge">bazel query</code> to find publishable targets, build them in parallel, then publish in a loop.
Here is a template to get you started:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="nb">set</span> <span class="nt">-u</span> <span class="nt">-e</span> <span class="nt">-o</span> pipefail
<span class="c"># Call the script with argument "pack" or "publish"</span>
<span class="nb">readonly </span><span class="nv">NPM_COMMAND</span><span class="o">=</span><span class="k">${</span><span class="nv">1</span><span class="k">:-</span><span class="nv">publish</span><span class="k">}</span>
<span class="c"># Don't rely on $PATH to have the right version</span>
<span class="nb">readonly </span><span class="nv">BAZEL</span><span class="o">=</span>./node_modules/.bin/bazel
<span class="c"># Find all the npm packages in the repo</span>
<span class="nb">readonly </span><span class="nv">PKG_NPM_LABELS</span><span class="o">=</span><span class="sb">`</span><span class="nv">$BAZEL</span> query <span class="nt">--output</span><span class="o">=</span>label <span class="s1">'kind("pkg_npm", //...)'</span><span class="sb">`</span>
<span class="c"># Build them in one command to maximize parallelism</span>
<span class="nv">$BAZEL</span> build <span class="nt">--config</span><span class="o">=</span>release <span class="nv">$PKG_NPM_LABELS</span>
<span class="c"># publish one package at a time to make it easier to spot any errors or warnings</span>
<span class="k">for </span>pkg <span class="k">in</span> <span class="nv">$PKG_NPM_LABELS</span> <span class="p">;</span> <span class="k">do</span>
<span class="nv">$BAZEL</span> run <span class="nt">--config</span><span class="o">=</span>release <span class="nt">--</span> <span class="k">${</span><span class="nv">pkg</span><span class="k">}</span>.<span class="k">${</span><span class="nv">NPM_COMMAND</span><span class="k">}</span> <span class="nt">--access</span> public <span class="nt">--tag</span> latest
<span class="k">done</span>
</code></pre></div></div>
<p>See https://www.kchodorow.com/blog/2017/03/27/stamping-your-builds/ for more background.
Make sure you use a “STABLE_” status key, or else Bazel may use a cached npm artifact rather than
building a new one with your current version info.</p>
</div>
</div>
<div class="col-md-2 sticky-sidebar">
<div class="right-sidebar">
<ul class="gh-links">
<li>
<i class="fa fa-github"></i>
<a href="https://github.com/bazelbuild/rules_nodejs/issues/new?title=Documentation issue: Home&labels=question/docs">Create
issue</a>
</li>
<li>
<i class="fa fa-pencil"></i>
<a class="gh-edit" href="https://github.com/bazelbuild/rules_nodejs/tree/stable/docs/stamping.md">Edit
this page</a>
</li>
</ul>
<ul class="section-nav">
<li class="toc-entry toc-h2"><a href="#substitutions-attribute">Substitutions attribute</a></li>
<li class="toc-entry toc-h2"><a href="#read-the-status-files">Read the status files</a></li>
<li class="toc-entry toc-h2"><a href="#stamping-with-a-workspace-status-script">Stamping with a Workspace status script</a></li>
<li class="toc-entry toc-h2"><a href="#release-script">Release script</a></li>
</ul>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<div class="row">
<div class="col-lg-8">
<p class="text-muted">&copy; 2020 The rules_nodejs authors</p>
</div>
</div>
</div>
</footer>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script crossorigin="anonymous"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- Anchor JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/3.2.0/anchor.min.js" type="text/javascript"></script>
<script>
// Automatically add anchors and links to all header elements that don't already have them.
anchors.options = { placement: 'left' };
anchors.add();
</script>
<script>
var shiftWindow = function () {
if (location.hash.length !== 0) {
window.scrollBy(0, -50);
}
};
window.addEventListener("hashchange", shiftWindow);
var highlightCurrentSidebarNav = function () {
var href = location.pathname;
var item = $('#sidebar-nav [href$="' + href + '"]');
if (item) {
var li = item.parent();
li.addClass("active");
if (li.parent() && li.parent().is("ul")) {
do {
var ul = li.parent();
if (ul.hasClass("collapse")) {
ul.collapse("show");
}
li = ul.parent();
} while (li && li.is("li"));
}
}
};
$(document).ready(function () {
// Scroll to anchor of location hash, adjusted for fixed navbar.
window.setTimeout(function () {
shiftWindow();
}, 1);
// Flip the caret when submenu toggles are clicked.
$(".sidebar-submenu").on("show.bs.collapse", function () {
var toggle = $('[href$="#' + $(this).attr('id') + '"]');
if (toggle) {
toggle.addClass("dropup");
}
});
$(".sidebar-submenu").on("hide.bs.collapse", function () {
var toggle = $('[href$="#' + $(this).attr('id') + '"]');
if (toggle) {
toggle.removeClass("dropup");
}
});
// Highlight the current page on the sidebar nav.
highlightCurrentSidebarNav();
});
</script>
</body>
</html>