Skip to content

Commit

Permalink
feat: add JSModuleInfo provider
Browse files Browse the repository at this point in the history
BREAKING CHANGE:

Adds JSModuleInfo provider as the common provider for passing & consuming javascript sources and related files such as .js.map, .json, etc.

For 1.0 we added JSNamedModuleInfo and JSEcmaScriptModuleInfo which were provided by ts_library and consumed by rules that needed to differentiate between the two default flavors of ts_library outputs (named-UMD & esm). We left out JSModuleInfo as its use case was unclear at the time.

For 2.0 we're adding JSModuleInfo as generic javascript provided for the rules_nodejs ecosystem. It is not currently opinionated about the module format of the sources or the language level. Consumers of JSModuleInfo should be aware of what module format & language level is being produced if necessary.

The following rules provide JSModuleInfo:

* ts_library (devmode named-UMD .js output flavor)
* ts_proto_library (devmode named-UMD .js output flavor)
* node_module_library (this is a behind the scenes rule used by yarn_install & npm_install)
* js_library (.js, .js.map & . json files)
* rollup_bundle
* terser_minfied
* ts_project

The following rules consume JSModuleInfo:

* nodejs_binary & nodejs_test (along with derivate macros such as jasmine_node_test); these rules no longer consume JSNamedModuleInfo
* npm_package_bin
* pkg_npm; no longer consumes JSNamedModuleInfo
* karma_web_test (for config file instead of JSNamedModuleInfo; JSNamedModuleInfo still used for test files)
* protractor_web_test (for config & on_prepare files instead of JSModuleInfo; JSNamedModuleInfo still used for test files)
* rollup_bundle (if JSEcmaScriptModuleInfo not provided)
* terser_minified
  • Loading branch information
gregmagolan authored and alexeagle committed Jun 23, 2020
1 parent c60f776 commit d3fcf85
Show file tree
Hide file tree
Showing 22 changed files with 183 additions and 48 deletions.
8 changes: 7 additions & 1 deletion internal/js_library/js_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
DO NOT USE - this is not fully designed, and exists only to enable testing within this repo.
"""

load("//:providers.bzl", "LinkablePackageInfo", "declaration_info")
load("//:providers.bzl", "LinkablePackageInfo", "declaration_info", "js_module_info")
load("//third_party/github.com/bazelbuild/bazel-skylib:rules/private/copy_file_private.bzl", "copy_bash", "copy_cmd")

_AMD_NAMES_DOC = """Mapping from require module names to global variables.
Expand Down Expand Up @@ -52,6 +52,7 @@ def write_amd_names_shim(actions, amd_names_shim, targets):
def _impl(ctx):
files = []
typings = []
js_files = []

for src in ctx.files.srcs:
if src.is_source and not src.path.startswith("external/"):
Expand All @@ -69,6 +70,10 @@ def _impl(ctx):
else:
files.append(src)

for p in files:
if p.basename.endswith(".js") or p.basename.endswith(".js.map") or p.basename.endswith(".json"):
js_files.append(p)

files_depset = depset(files)

providers = [
Expand All @@ -77,6 +82,7 @@ def _impl(ctx):
runfiles = ctx.runfiles(files = ctx.files.srcs),
),
AmdNamesInfo(names = ctx.attr.amd_names),
js_module_info(depset(js_files)),
]

if ctx.attr.package_name:
Expand Down
7 changes: 3 additions & 4 deletions internal/node/node.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ They support module mapping: any targets in the transitive dependencies with
a `module_name` attribute can be `require`d by that name.
"""

load("//:providers.bzl", "JSNamedModuleInfo", "NodeRuntimeDepsInfo", "NpmPackageInfo", "node_modules_aspect")
load("//:providers.bzl", "JSModuleInfo", "NodeRuntimeDepsInfo", "NpmPackageInfo", "node_modules_aspect")
load("//internal/common:expand_into_runfiles.bzl", "expand_location_into_runfiles")
load("//internal/common:module_mappings.bzl", "module_mappings_runtime_aspect")
load("//internal/common:path_utils.bzl", "strip_external")
Expand Down Expand Up @@ -165,9 +165,8 @@ def _nodejs_binary_impl(ctx):
sources_depsets = []

for d in ctx.attr.data:
# TODO: switch to JSModuleInfo when it is available
if JSNamedModuleInfo in d:
sources_depsets.append(d[JSNamedModuleInfo].sources)
if JSModuleInfo in d:
sources_depsets.append(d[JSModuleInfo].sources)
if hasattr(d, "files"):
sources_depsets.append(d.files)
sources = depset(transitive = sources_depsets)
Expand Down
4 changes: 3 additions & 1 deletion internal/node/npm_package_bin.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"A generic rule to run a tool that appears in node_modules/.bin"

load("//:providers.bzl", "NpmPackageInfo", "node_modules_aspect", "run_node")
load("//:providers.bzl", "JSModuleInfo", "NpmPackageInfo", "node_modules_aspect", "run_node")
load("//internal/common:expand_variables.bzl", "expand_variables")
load("//internal/linker:link_node_modules.bzl", "module_mappings_aspect")

Expand Down Expand Up @@ -35,6 +35,8 @@ def _inputs(ctx):
for d in ctx.attr.data:
if NpmPackageInfo in d:
inputs_depsets.append(d[NpmPackageInfo].sources)
if JSModuleInfo in d:
inputs_depsets.append(d[JSModuleInfo].sources)
return depset(ctx.files.data, transitive = inputs_depsets).to_list()

def _impl(ctx):
Expand Down
6 changes: 5 additions & 1 deletion internal/npm_install/node_module_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"""Contains the node_module_library which is used by yarn_install & npm_install.
"""

load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "NpmPackageInfo", "js_named_module_info")
load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "NpmPackageInfo", "js_module_info", "js_named_module_info")

def _node_module_library_impl(ctx):
workspace_name = ctx.label.workspace_name if ctx.label.workspace_name else ctx.workspace_name
Expand Down Expand Up @@ -71,6 +71,10 @@ def _node_module_library_impl(ctx):
transitive_declarations = transitive_declarations,
type_blacklisted_declarations = depset([]),
),
js_module_info(
sources = direct_sources,
deps = ctx.attr.deps,
),
js_named_module_info(
sources = depset(ctx.files.named_module_srcs),
deps = ctx.attr.deps,
Expand Down
7 changes: 3 additions & 4 deletions internal/pkg_npm/pkg_npm.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ If all users of your library code use Bazel, they should just add your library
to the `deps` of one of their targets.
"""

load("//:providers.bzl", "DeclarationInfo", "JSNamedModuleInfo", "LinkablePackageInfo", "NodeContextInfo")
load("//:providers.bzl", "DeclarationInfo", "JSModuleInfo", "LinkablePackageInfo", "NodeContextInfo")

_DOC = """The pkg_npm rule creates a directory containing a publishable npm artifact.
Expand Down Expand Up @@ -253,9 +253,8 @@ def _pkg_npm(ctx):
deps_files_depsets.append(dep.files)

# All direct & transitive JavaScript-producing deps
# TODO: switch to JSModuleInfo when it is available
if JSNamedModuleInfo in dep:
deps_files_depsets.append(dep[JSNamedModuleInfo].sources)
if JSModuleInfo in dep:
deps_files_depsets.append(dep[JSModuleInfo].sources)

# Include all transitive declerations
if DeclarationInfo in dep:
Expand Down
23 changes: 23 additions & 0 deletions internal/providers/js_providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@ If users really need to produce both in a single build, they'll need two rules w
differing 'debug' attributes.
"""

JSModuleInfo = provider(
doc = """JavaScript files and sourcemaps.""",
fields = {
"direct_sources": "Depset of direct JavaScript files and sourcemaps",
"sources": "Depset of direct and transitive JavaScript files and sourcemaps",
},
)

def js_module_info(sources, deps = []):
"""Constructs a JSModuleInfo including all transitive sources from JSModuleInfo providers in a list of deps.
Returns a single JSModuleInfo.
"""
transitive_depsets = [sources]
for dep in deps:
if JSModuleInfo in dep:
transitive_depsets.append(dep[JSModuleInfo].sources)

return JSModuleInfo(
direct_sources = sources,
sources = depset(transitive = transitive_depsets),
)

JSNamedModuleInfo = provider(
doc = """JavaScript files whose module name is self-contained.
Expand Down
22 changes: 11 additions & 11 deletions packages/jasmine/jasmine_node_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ These rules let you run tests outside of a browser. This is typically faster
than launching a test in Karma, for example.
"""

load("@build_bazel_rules_nodejs//:providers.bzl", "JSNamedModuleInfo")
load("@build_bazel_rules_nodejs//:providers.bzl", "JSModuleInfo")
load("@build_bazel_rules_nodejs//internal/node:node.bzl", "nodejs_test")

def _devmode_js_sources_impl(ctx):
def _js_sources_impl(ctx):
depsets = []
for src in ctx.attr.srcs:
if JSNamedModuleInfo in src:
depsets.append(src[JSNamedModuleInfo].sources)
if JSModuleInfo in src:
depsets.append(src[JSModuleInfo].sources)
if hasattr(src, "files"):
depsets.append(src.files)
sources = depset(transitive = depsets)
Expand All @@ -38,12 +38,12 @@ def _devmode_js_sources_impl(ctx):

return [DefaultInfo(files = sources)]

"""Rule to get devmode js sources from deps.
"""Rule to get js sources from deps.
Outputs a manifest file with the sources listed.
"""
_devmode_js_sources = rule(
implementation = _devmode_js_sources_impl,
_js_sources = rule(
implementation = _js_sources_impl,
attrs = {
"srcs": attr.label_list(
allow_files = True,
Expand Down Expand Up @@ -98,8 +98,8 @@ def jasmine_node_test(
if kwargs.pop("coverage", False):
fail("The coverage attribute has been removed, run your target with \"bazel coverage\" instead")

_devmode_js_sources(
name = "%s_devmode_srcs" % name,
_js_sources(
name = "%s_js_sources" % name,
srcs = srcs + deps,
testonly = 1,
tags = tags,
Expand All @@ -114,14 +114,14 @@ def jasmine_node_test(
all_data.extend(["@npm//jasmine", "@npm//jasmine-reporters", "@npm//c8"])

# END-INTERNAL
all_data += [":%s_devmode_srcs.MF" % name]
all_data += [":%s_js_sources.MF" % name]
all_data += [Label("@build_bazel_rules_nodejs//third_party/github.com/bazelbuild/bazel/tools/bash/runfiles")]

# jasmine_runner.js consumes the first 3 args.
# The remaining target templated_args will be passed through to jasmine or
# specs to consume.
templated_args = [
"$(rootpath :%s_devmode_srcs.MF)" % name,
"$(rootpath :%s_js_sources.MF)" % name,
"$(rootpath %s)" % config_file if config_file else "--noconfig",
] + kwargs.pop("templated_args", [])

Expand Down
12 changes: 5 additions & 7 deletions packages/karma/karma_web_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.
"Unit testing with Karma"

load("@build_bazel_rules_nodejs//:providers.bzl", "JSNamedModuleInfo", "NpmPackageInfo", "node_modules_aspect")
load("@build_bazel_rules_nodejs//:providers.bzl", "JSModuleInfo", "JSNamedModuleInfo", "NpmPackageInfo", "node_modules_aspect")
load("@build_bazel_rules_nodejs//internal/js_library:js_library.bzl", "write_amd_names_shim")
load("@io_bazel_rules_webtesting//web:web.bzl", "web_test_suite")
load("@io_bazel_rules_webtesting//web/internal:constants.bzl", "DEFAULT_WRAPPED_TEST_TAGS")
Expand Down Expand Up @@ -128,9 +128,8 @@ def _write_karma_config(ctx, files, amd_names_shim):
config_file = None

if ctx.attr.config_file:
# TODO: switch to JSModuleInfo when it is available
if JSNamedModuleInfo in ctx.attr.config_file:
config_file = _filter_js(ctx.attr.config_file[JSNamedModuleInfo].direct_sources.to_list())[0]
if JSModuleInfo in ctx.attr.config_file:
config_file = _filter_js(ctx.attr.config_file[JSModuleInfo].direct_sources.to_list())[0]
else:
config_file = ctx.file.config_file

Expand Down Expand Up @@ -295,9 +294,8 @@ ${{COMMAND}}
config_sources = []

if ctx.attr.config_file:
# TODO: switch to JSModuleInfo when it is available
if JSNamedModuleInfo in ctx.attr.config_file:
config_sources = ctx.attr.config_file[JSNamedModuleInfo].sources.to_list()
if JSModuleInfo in ctx.attr.config_file:
config_sources = ctx.attr.config_file[JSModuleInfo].sources.to_list()
else:
config_sources = [ctx.file.config_file]

Expand Down
6 changes: 5 additions & 1 deletion packages/labs/grpc_web/ts_proto_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.
"Protocol Buffers"

load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "JSEcmaScriptModuleInfo", "JSNamedModuleInfo")
load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "JSEcmaScriptModuleInfo", "JSModuleInfo", "JSNamedModuleInfo")
load("@rules_proto//proto:defs.bzl", "ProtoInfo")

typescript_proto_library_aspect = provider(
Expand Down Expand Up @@ -243,6 +243,10 @@ def _ts_proto_library_impl(ctx):
transitive_declarations = transitive_declarations,
type_blacklisted_declarations = depset([]),
),
JSModuleInfo(
direct_sources = es5_srcs,
sources = es5_srcs,
),
JSNamedModuleInfo(
direct_sources = es5_srcs,
sources = es5_srcs,
Expand Down
6 changes: 5 additions & 1 deletion packages/labs/protobufjs/ts_proto_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.
"Protocol Buffers"

load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "JSEcmaScriptModuleInfo", "JSNamedModuleInfo")
load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo", "JSEcmaScriptModuleInfo", "JSModuleInfo", "JSNamedModuleInfo")

def _run_pbjs(actions, executable, var, output_name, proto_files, suffix = ".js", wrap = "default", amd_name = ""):
js_file = actions.declare_file(output_name + suffix)
Expand Down Expand Up @@ -124,6 +124,10 @@ def _ts_proto_library(ctx):
transitive_declarations = declarations,
type_blacklisted_declarations = depset([]),
),
JSModuleInfo(
direct_sources = es5_sources,
sources = es5_sources,
),
JSNamedModuleInfo(
direct_sources = es5_sources,
sources = es5_sources,
Expand Down
16 changes: 7 additions & 9 deletions packages/protractor/protractor_web_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"Run end-to-end tests with Protractor"

load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
load("@build_bazel_rules_nodejs//:providers.bzl", "JSNamedModuleInfo", "NpmPackageInfo", "node_modules_aspect")
load("@build_bazel_rules_nodejs//:providers.bzl", "JSModuleInfo", "JSNamedModuleInfo", "NpmPackageInfo", "node_modules_aspect")
load("@build_bazel_rules_nodejs//internal/common:windows_utils.bzl", "create_windows_native_launcher_script", "is_windows")
load("@io_bazel_rules_webtesting//web:web.bzl", "web_test_suite")
load("@io_bazel_rules_webtesting//web/internal:constants.bzl", "DEFAULT_WRAPPED_TEST_TAGS")
Expand Down Expand Up @@ -80,21 +80,19 @@ def _protractor_web_test_impl(ctx):
configuration_sources = []
configuration_file = None
if ctx.attr.configuration:
# TODO: switch to JSModuleInfo when it is available
if JSNamedModuleInfo in ctx.attr.configuration:
configuration_sources = ctx.attr.configuration[JSNamedModuleInfo].sources.to_list()
configuration_file = _filter_js(ctx.attr.configuration[JSNamedModuleInfo].direct_sources.to_list())[0]
if JSModuleInfo in ctx.attr.configuration:
configuration_sources = ctx.attr.configuration[JSModuleInfo].sources.to_list()
configuration_file = _filter_js(ctx.attr.configuration[JSModuleInfo].direct_sources.to_list())[0]
else:
configuration_sources = [ctx.file.configuration]
configuration_file = ctx.file.configuration

on_prepare_sources = []
on_prepare_file = None
if ctx.attr.on_prepare:
# TODO: switch to JSModuleInfo when it is available
if JSNamedModuleInfo in ctx.attr.on_prepare:
on_prepare_sources = ctx.attr.on_prepare[JSNamedModuleInfo].sources.to_list()
on_prepare_file = _filter_js(ctx.attr.on_prepare[JSNamedModuleInfo].direct_sources.to_list())[0]
if JSModuleInfo in ctx.attr.on_prepare:
on_prepare_sources = ctx.attr.on_prepare[JSModuleInfo].sources.to_list()
on_prepare_file = _filter_js(ctx.attr.on_prepare[JSModuleInfo].direct_sources.to_list())[0]
else:
on_prepare_sources = [ctx.file.on_prepare]
on_prepare_file = ctx.file.on_prepare
Expand Down
9 changes: 7 additions & 2 deletions packages/rollup/rollup_bundle.bzl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"Rules for running Rollup under Bazel"

load("@build_bazel_rules_nodejs//:providers.bzl", "JSEcmaScriptModuleInfo", "NodeContextInfo", "NpmPackageInfo", "node_modules_aspect", "run_node")
load("@build_bazel_rules_nodejs//:providers.bzl", "JSEcmaScriptModuleInfo", "JSModuleInfo", "NodeContextInfo", "NpmPackageInfo", "node_modules_aspect", "run_node")
load("@build_bazel_rules_nodejs//internal/linker:link_node_modules.bzl", "module_mappings_aspect")

_DOC = """Runs the Rollup.js CLI under Bazel.
Expand Down Expand Up @@ -308,6 +308,8 @@ def _rollup_bundle(ctx):
for dep in ctx.attr.deps:
if JSEcmaScriptModuleInfo in dep:
deps_depsets.append(dep[JSEcmaScriptModuleInfo].sources)
elif JSModuleInfo in dep:
deps_depsets.append(dep[JSModuleInfo].sources)
elif hasattr(dep, "files"):
deps_depsets.append(dep.files)

Expand Down Expand Up @@ -397,8 +399,11 @@ def _rollup_bundle(ctx):
env = {"COMPILATION_MODE": ctx.var["COMPILATION_MODE"]},
)

outputs_depset = depset(outputs)

return [
DefaultInfo(files = depset(outputs)),
DefaultInfo(files = outputs_depset),
JSModuleInfo(sources = outputs_depset),
]

rollup_bundle = rule(
Expand Down
12 changes: 10 additions & 2 deletions packages/terser/terser_minified.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

"Rule to run the terser binary under bazel"

load("@build_bazel_rules_nodejs//:providers.bzl", "run_node")
load("@build_bazel_rules_nodejs//:providers.bzl", "JSModuleInfo", "run_node")

_DOC = """Run the terser minifier.
Expand Down Expand Up @@ -112,9 +112,16 @@ def _terser(ctx):

# CLI arguments; see https://www.npmjs.com/package/terser#command-line-usage
args = ctx.actions.args()
inputs = ctx.files.src[:]

inputs = []
outputs = []

# If src has a JSModuleInfo provider than use that otherwise use DefaultInfo files
if JSModuleInfo in ctx.attr.src:
inputs.extend(ctx.attr.src[JSModuleInfo].sources.to_list())
else:
inputs.extend(ctx.files.src[:])

sources = _filter_js(inputs)
sourcemaps = [f for f in inputs if f.extension == "map"]
directory_srcs = [s for s in sources if s.is_directory]
Expand Down Expand Up @@ -179,6 +186,7 @@ def _terser(ctx):

return [
DefaultInfo(files = depset(outputs)),
JSModuleInfo(sources = depset(outputs)),
]

terser_minified = rule(
Expand Down
Loading

0 comments on commit d3fcf85

Please sign in to comment.