Rules_nodejs: Shared javascript provider

Created on 22 Nov 2017  路  10Comments  路  Source: bazelbuild/rules_nodejs

(Not sure which repo this belongs in, please redirect if there's somewhere better.)

To handle more compile-to-js languages, we will need a shared provider that they can all use. This is alluded to in this repo in a comment.

enhancement builtin

Most helpful comment

We just had a good discussion at BazelCon. We need to look at the interactions between existing JS consumers and producers - rules_kotlin, rules_nodejs, pubref/rules_node, dropbox/rules_node, rules_typescript, rules_closure, some presumed CoffeeScript rules from @kamalmarhubi and the protobuf rules. We'll have a new Provider (NodeModuleInfo is only intended for npm packages that are interop-ed into a Bazel build).
Maybe we'll put it in a generic repo like bazelbuild/rules_javascript so it's not layered along with one of the existing repos.
We have an OKR on the Angular Tooling team this quarter to design this - expect a design doc draft posted to this issue.

All 10 comments

/cc @shicks @blickly

Any news on this? Is something like NodeModuleInfo going to be made public? Or is the recommended way to interop by creating an aspect similar to the module_mapping_aspect?

We just had a good discussion at BazelCon. We need to look at the interactions between existing JS consumers and producers - rules_kotlin, rules_nodejs, pubref/rules_node, dropbox/rules_node, rules_typescript, rules_closure, some presumed CoffeeScript rules from @kamalmarhubi and the protobuf rules. We'll have a new Provider (NodeModuleInfo is only intended for npm packages that are interop-ed into a Bazel build).
Maybe we'll put it in a generic repo like bazelbuild/rules_javascript so it's not layered along with one of the existing repos.
We have an OKR on the Angular Tooling team this quarter to design this - expect a design doc draft posted to this issue.

Success criteria:

  • third parties can write rules and they compose with ours
  • An example of TS to serving pipeline working (ts_library -> rollup_bundle -> terser_minified -> web_package (with differential loading) -> history-server)

I'm worried that "javascript" is too big a target for a single provider.
If a rule can only handle dependencies, for example, in ES2017 with named AMD modules, then I think that should be a encoded as a unique provider (JS_ES2017_NamedAMD or something similar), rather than the rule saying it needs "javascript" and then hoping that it is the correct type of javascript.

We tossed around the idea of having a larger set of very specific providers but for a set of shared JS providers that becomes too fine grained for the general case. A large number of specific providers would make interop between rules more difficult as potentially every provider type would have to be checked for in consuming rules that can handle a wide variety of javascript modules formats & language levels.

We settled on a small set (JSModuleInfo, JSEcmaScriptModuleInfo, JSNamedModuleInfo) for the general cases described here https://docs.google.com/document/d/1ggkY5RqUkVL4aQLYm7esRW978LgX3GUCnQirrk5E1C0/edit#.

JSEcmaScriptModuleInfo is landing here https://github.com/bazelbuild/rules_nodejs/pull/1201 and it allows ts_library outputs to be consumed by the new @bazel/rollup rollup_bundle which will replace the legacy rollup_bundle.

As a rule author you can add as many JS providers on top of the set of shared ones as you need for your own purposes and maybe some rules in the ecosystem will require very specific ones.

JSModuleInfo which hasn't landed yet and may still be change a bit will likely have the module_format field that can be used by consuming rules to look for specific module formats.

JSModuleInfo = provider(
    doc = """JavaScript files and sourcemaps.""",
    fields = {
        "module_format": "a string like [amd, cjs, esm, iife, umd] or \"mixed\" if the sources are of mixed formats",
        "sources": "depset of direct and transitive JavaScript files and sourcemaps",
    },
)

Makes one wish providers had some sort of inheritance/polymorphism aspect....

I suppose we'll just end up writing an aspect that produces the JS (for example JS_ES2017_NamedAMD), and give that aspect the ability to view the JSModuleInfo and JS_ES2017_NamedAMD on the target and if it can find the JS to just pass it through in the expected JS_ES2017_NamedAMD provider.

I'm just uncertain what the behavior will be if a rule wants to return two providers of JsModuleInfo with different values for module_format.

Lots of providers also can mean lots of actions run if a consumer requests all of them. A combinatorial explosion of them will slow down builds.

A few update on this:
JSEcmaScriptModuleInfo landed in: https://github.com/bazelbuild/rules_nodejs/pull/1201
JSNamedModuleInfo landed in: https://github.com/bazelbuild/rules_nodejs/pull/1215
These are both in providers.bzl: https://github.com/bazelbuild/rules_nodejs/blob/master/providers.bzl

A typescript specific provider DeclarationInfo was also added: https://github.com/bazelbuild/rules_nodejs/blob/master/declaration_provider.bzl

The last provider that we had planned is JSModuleInfo which is still pending here: https://github.com/bazelbuild/rules_nodejs/pull/1040

We think we can cover all the use cases with the existing providers. The new one in #1040 is useful in theory as a way to get only direct and not transitive .js outputs from some rule, without relying on ESModule output. But we only needed that in one place and there was an easy workaround.
Might revisit #1040 after 1.0.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gmishkin picture gmishkin  路  5Comments

pauldraper picture pauldraper  路  6Comments

joeljeske picture joeljeske  路  6Comments

nimerritt picture nimerritt  路  7Comments

samertm picture samertm  路  7Comments