Home

Awesome

Closure Rules for Bazel (αlpha) Bazel CI build status

JavaScriptTemplatingStylesheetsMiscellaneous
closure_js_libraryclosure_css_libraryclosure_js_proto_library
closure_js_binaryclosure_css_binaryphantomjs_test
closure_js_testclosure_proto_library (Experimental)
closure_grpc_web_library (Experimental)

Overview

Closure Rules provides a polished JavaScript build system for Bazel that emphasizes type safety, strictness, testability, and optimization. These rules are built with the Closure Tools, which are what Google used to create websites like Google.com and Gmail. The goal of this project is to take the frontend development methodology that Google actually uses internally, and make it easily available to outside developers.

Closure Rules is an abstract build system. This is what sets it apart from Grunt, Gulp, Webpacker, Brunch, Broccoli, etc. These projects all provide a concrete framework for explaining how to build your project. Closure Rules instead provides a framework for declaring what your project is. Closure Rules is then able to use this abstract definition to infer an optimal build strategy.

Closure Rules is also an austere build system. The Closure Compiler doesn't play games. It enforces a type system that can be stricter than Java. From a stylistic perspective, Closure is verbose like Java; there's no cryptic symbols or implicit behavior; the code says exactly what it's doing. This sets Closure apart from traditional JavaScript development, where terseness was favored over readability, because minifiers weren't very good.

What's Included

Closure Rules bundles the following tools and makes them "just work."

Mailing Lists

Caveat Emptor

Closure Rules is production ready, but its design is not yet finalized. Breaking changes will be introduced. However they will be well-documented in the release notes.

Setup

First you must install Bazel. Then you add the following to your WORKSPACE file:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "io_bazel_rules_closure",
    sha256 = "9498e57368efb82b985db1ed426a767cbf1ba0398fd7aed632fc3908654e1b1e",
    strip_prefix = "rules_closure-0.12.0",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/0.12.0.tar.gz",
        "https://github.com/bazelbuild/rules_closure/archive/0.12.0.tar.gz",
    ],
)

load("@io_bazel_rules_closure//closure:repositories.bzl", "rules_closure_dependencies", "rules_closure_toolchains")
rules_closure_dependencies()
rules_closure_toolchains()

# Only needed if you want to run your tests on headless Chrome
load("@io_bazel_rules_closure//closure:defs.bzl", "setup_web_test_repositories")
setup_web_test_repositories(
    chromium = True,
)

You are not required to install the Closure Tools, PhantomJS, or anything else for that matter; they will be fetched automatically by Bazel.

Overriding Dependency Versions

When you call rules_closure_dependencies() in your WORKSPACE file, it causes a few dozen external dependencies to be added to your project, e.g. Guava, Guice, JSR305, etc. You might need to customize this behavior.

To override the version of any dependency, modify your WORKSPACE file to pass omit_<dependency_name>=True to rules_closure_dependencies(). Next define your custom dependency version. A full list of dependencies is available from repositories.bzl. For example, to override the version of Guava:

load("@io_bazel_rules_closure//closure:repositories.bzl", "rules_closure_dependencies", "rules_closure_toolchains")
rules_closure_dependencies(
    omit_com_google_guava=True,
)
rules_closure_toolchains()

load("@bazel_tools//tools/build_defs/repo:java.bzl", "java_import_external")
java_import_external(
    name = "com_google_guava",
    licenses = ["notice"],  # Apache 2.0
    jar_urls = [
        "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/guava/guava/24.1-jre/guava-24.1-jre.jar",
        "https://repo1.maven.org/maven2/com/google/guava/guava/24.1-jre/guava-24.1-jre.jar",
    ],
    jar_sha256 = "31bfe27bdf9cba00cb4f3691136d3bc7847dfc87bfe772ca7a9eb68ff31d79f5",
    exports = [
        "@com_google_code_findbugs_jsr305",
        "@com_google_errorprone_error_prone_annotations",
    ],
)

Examples

Please see the test directories within this project for concrete examples of usage:

Reference

closure_js_library

load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_library")
closure_js_library(name, srcs, data, deps, exports, suppress, convention,
                   no_closure_library)

Defines a set of JavaScript sources.

The purpose of this rule is to define an abstract graph of JavaScript sources. It must be used in conjunction with closure_js_binary to output a minified file.

This rule will perform syntax checking and linting on your files. This can be tuned with the suppress attribute. To learn more about what the linter wants, read the Google JavaScript Style Guide.

Strict dependency checking is performed on the sources listed in each library target. See the documentation of the deps attribute for further information.

Rule Polymorphism

This rule can be referenced as though it were the following:

Arguments

closure_js_binary

load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_binary")
closure_js_binary(name, deps, css, debug, language, entry_points,
                  dependency_mode, compilation_level, formatting,
                  output_wrapper, property_renaming_report, defs)

Turns JavaScript libraries into a minified optimized blob of code.

This rule must be used in conjunction with closure_js_library.

Implicit Output Targets

Rule Polymorphism

This rule can be referenced as though it were the following:

Arguments

Support for AngularJS

When compiling AngularJS applications, you need to pass custom flags to the Closure Compiler. This can be accomplished by adding the following to your closure_js_binary rule:

closure_js_binary(
    # ...
    defs = [
        "--angular_pass",
        "--export_local_property_definitions",
    ],
)

closure_js_test

load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_test")
closure_js_test(name, srcs, data, deps, css, html, language, suppress,
                compilation_level, entry_points, defs)

Runs JavaScript unit tests inside a headless web browser.

This is a build macro that composes closure_js_library, closure_js_binary, and phantomjs_test.

A test is defined as any function in the global namespace that begins with test, setUp, or tearDown. You are not required to @export these functions. If you don't have a global namespace, because you're using goog.module or goog.scope, then you must register your test functions with goog.testing.testSuite.

Each test file should require goog.testing.jsunit and goog.testing.asserts because they run the tests and provide useful testing functions such as assertEquals().

Any JavaScript file related to testing is strongly recommended to contain a goog.setTestOnly() statement in the file. However this is not required, because some projects might not want to directly reference Closure Library functions.

No Network Access

Your test will run within a hermetically sealed environment. You are not allowed to send HTTP requests to any external servers. It is expected that you'll use Closure Library mocks for things like XHR. However a local HTTP server is started up on a random port that allows to request runfiles under the /filez/WORKSPACE_NAME/ path.

Rule Polymorphism

This rule can be referenced as though it were the following:

Arguments

phantomjs_test

load("@io_bazel_rules_closure//closure:defs.bzl", "phantomjs_test")
phantomjs_test(name, data, deps, html, harness, runner)

Runs PhantomJS (QtWebKit) for unit testing purposes.

This is a low level rule. Please use the closure_js_test macro if possible.

Rule Polymorphism

This rule can be referenced as though it were the following:

Arguments

closure_css_library

load("@io_bazel_rules_closure//closure:defs.bzl", "closure_css_library")
closure_css_library(name, srcs, data, deps)

Defines a set of CSS stylesheets.

This rule does not compile your stylesheets; it is used in conjunction with closure_css_binary which produces the minified CSS file.

This rule should be referenced by any closure_js_library rule whose sources contain a goog.getCssName('foo') call if foo is a CSS class name defined by this rule.

Rule Polymorphism

This rule can be referenced as though it were the following:

Arguments

closure_css_binary

load("@io_bazel_rules_closure//closure:defs.bzl", "closure_css_binary")
closure_css_binary(name, deps, renaming, debug, defs)

Turns stylesheets defined by closure_css_library rules into a single minified CSS file.

Closure-specific syntax such as variables, functions, conditionals, and mixins will be evaluated and turned into normal CSS. The documentation on using these features can be found here.

Unlike most CSS minifiers, this will minify class names by default. So this rule can be referenced by the css flag of closure_js_binary, in order to let the Closure Compiler know how to substitute the minified class names. See the renaming documentation below for more information.

Implicit Output Targets

Rule Polymorphism

This rule can be referenced as though it were the following:

Arguments

closure_js_proto_library

load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_proto_library")
closure_js_proto_library(name, srcs, add_require_for_enums, binary,
                         import_style)

Defines a set of Protocol Buffer files.

Documentation

Implicit Output Targets

Rule Polymorphism

This rule can be referenced as though it were the following:

Arguments

closure_proto_library

load("@io_bazel_rules_closure//closure:defs.bzl", "closure_proto_library")
closure_proto_library(name, deps)

closure_proto_library generates JS code from .proto files.

deps must point to proto_library rules.

Rule Polymorphism

This rule can be referenced as though it were the following: