Skip to content

Commit 1e357fd

Browse files
Alex Eaglealexeagle
authored andcommitted
feat: promote js_library to public API
Fixes #149 Fixes #1771
1 parent 9ff4508 commit 1e357fd

45 files changed

Lines changed: 186 additions & 90 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/stale.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ jobs:
4444
4545
close-issue-message: >
4646
This issue was automatically closed because it went two weeks without a reply
47-
since it was labelled "Can Close?"
47+
since it was labeled "Can Close?"
4848
4949
close-pr-message: >
5050
This PR was automatically closed because it went two weeks without a reply
51-
since it was labelled "Can Close?"
51+
since it was labeled "Can Close?"

BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ bzl_library(
4848
deps = [
4949
"//internal/common:bzl",
5050
"//internal/generated_file_test:bzl",
51+
"//internal/js_library:bzl",
5152
"//internal/linker:bzl",
5253
"//internal/pkg_npm:bzl",
5354
"//internal/pkg_web:bzl",

e2e/nodejs_image/foolib/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("@build_bazel_rules_nodejs//internal/js_library:js_library.bzl", "js_library")
1+
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
22

33
js_library(
44
name = "foolib",

index.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ load("//internal/common:check_version.bzl", "check_version")
2323
load("//internal/common:copy_to_bin.bzl", _copy_to_bin = "copy_to_bin")
2424
load("//internal/common:params_file.bzl", _params_file = "params_file")
2525
load("//internal/generated_file_test:generated_file_test.bzl", _generated_file_test = "generated_file_test")
26+
load("//internal/js_library:js_library.bzl", _js_library = "js_library")
2627
load(
2728
"//internal/node:node.bzl",
2829
_nodejs_binary = "nodejs_binary",
@@ -44,6 +45,7 @@ pkg_web = _pkg_web
4445
copy_to_bin = _copy_to_bin
4546
params_file = _params_file
4647
generated_file_test = _generated_file_test
48+
js_library = _js_library
4749
# ANY RULES ADDED HERE SHOULD BE DOCUMENTED, see index.for_docs.bzl
4850

4951
# Allows us to avoid a transitive dependency on bazel_skylib from leaking to users

index.for_docs.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ load("//internal/common:check_bazel_version.bzl", _check_bazel_version = "check_
2020
load("//internal/common:copy_to_bin.bzl", _copy_to_bin = "copy_to_bin")
2121
load("//internal/common:params_file.bzl", _params_file = "params_file")
2222
load("//internal/generated_file_test:generated_file_test.bzl", _generated_file_test = "generated_file_test")
23+
load("//internal/js_library:js_library.bzl", _js_library = "js_library")
2324
load("//internal/node:node.bzl", _nodejs_binary = "nodejs_binary", _nodejs_test = "nodejs_test")
2425
load("//internal/node:node_repositories.bzl", _node_repositories = "node_repositories_rule")
2526
load("//internal/node:npm_package_bin.bzl", _npm_bin = "npm_package_bin")
@@ -39,4 +40,5 @@ yarn_install = _yarn_install
3940
npm_package_bin = _npm_bin
4041
pkg_web = _pkg_web
4142
generated_file_test = _generated_file_test
43+
js_library = _js_library
4244
# ANY RULES ADDED HERE SHOULD BE DOCUMENTED, run yarn stardoc to verify

internal/js_library/js_library.bzl

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,37 @@ load(
3434
"copy_cmd",
3535
)
3636

37-
_AMD_NAMES_DOC = """Mapping from require module names to global variables.
38-
This allows devmode JS sources to load unnamed UMD bundles from third-party libraries."""
37+
_ATTRS = {
38+
"amd_names": attr.string_dict(
39+
doc = """Non-public legacy API, not recommended to make new usages.
40+
See documentation on AmdNamesInfo""",
41+
),
42+
"deps": attr.label_list(),
43+
"is_windows": attr.bool(
44+
doc = "Internal use only. Automatically set by macro",
45+
mandatory = True,
46+
),
47+
# module_name for legacy ts_library module_mapping support
48+
# which is still being used in a couple of tests
49+
# TODO: remove once legacy module_mapping is removed
50+
"module_name": attr.string(
51+
doc = "Internal use only. It will be removed soon.",
52+
),
53+
"named_module_srcs": attr.label_list(
54+
doc = """Non-public legacy API, not recommended to make new usages.
55+
A subset of srcs that are javascript named-UMD or
56+
named-AMD for use in rules such as ts_devserver.
57+
They will be copied into the package bin folder if needed.""",
58+
allow_files = True,
59+
),
60+
"package_name": attr.string(),
61+
"srcs": attr.label_list(allow_files = True),
62+
}
3963

4064
AmdNamesInfo = provider(
41-
doc = "provide access to the amd_names attribute of js_library",
42-
fields = {"names": _AMD_NAMES_DOC},
65+
doc = "Non-public API. Provides access to the amd_names attribute of js_library",
66+
fields = {"names": """Mapping from require module names to global variables.
67+
This allows devmode JS sources to load unnamed UMD bundles from third-party libraries."""},
4368
)
4469

4570
def write_amd_names_shim(actions, amd_names_shim, targets):
@@ -48,7 +73,7 @@ def write_amd_names_shim(actions, amd_names_shim, targets):
4873
These are collected from our bootstrap deps (the only place global scripts should appear)
4974
5075
Args:
51-
actions: skylark rule execution context.actions
76+
actions: starlark rule execution context.actions
5277
amd_names_shim: File where the shim is written
5378
targets: dependencies to be scanned for AmdNamesInfo providers
5479
"""
@@ -199,57 +224,88 @@ def _impl(ctx):
199224

200225
_js_library = rule(
201226
implementation = _impl,
202-
attrs = {
203-
"amd_names": attr.string_dict(
204-
doc = _AMD_NAMES_DOC,
205-
),
206-
"deps": attr.label_list(
207-
doc = """Transitive dependencies of the package.
208-
It should include fine grained npm dependencies from the sources
209-
or other targets we want to include in the library but also propagate their own deps.""",
210-
),
211-
"is_windows": attr.bool(
212-
doc = "Automatically set by macro",
213-
mandatory = True,
214-
),
215-
# module_name for legacy ts_library module_mapping support
216-
# which is still being used in a couple of tests
217-
# TODO: remove once legacy module_mapping is removed
218-
"module_name": attr.string(
219-
doc = "Internal use only. It will be removed soon.",
220-
),
221-
"named_module_srcs": attr.label_list(
222-
doc = """A subset of srcs that are javascript named-UMD or
223-
named-AMD for use in rules such as ts_devserver.
224-
They will be copied into the package bin folder if needed.""",
225-
allow_files = True,
226-
),
227-
"package_name": attr.string(
228-
doc = """Optional package_name that this package may be imported as.""",
229-
),
230-
"srcs": attr.label_list(
231-
doc = """The list of files that comprise the package.
232-
They will be copied into the package bin folder if needed.""",
233-
allow_files = True,
234-
),
235-
},
236-
doc = "Defines a js_library package",
227+
attrs = _ATTRS,
237228
)
238229

239230
def js_library(
240231
name,
241232
srcs = [],
242-
amd_names = {},
243233
package_name = None,
244234
deps = [],
245-
named_module_srcs = [],
246235
**kwargs):
247-
"""Internal use only yet. It will be released into a public API in a future release."""
236+
"""Groups JavaScript code so that it can be depended on like an npm package.
237+
238+
### Behavior
239+
240+
This rule doesn't perform any build steps ("actions") so it is similar to a `filegroup`.
241+
However it produces several Bazel "Providers" for interop with other rules.
242+
243+
> Compare this to `pkg_npm` which just produces a directory output, and therefore can't expose individual
244+
> files to downstream targets and causes a cascading re-build of all transitive dependencies when any file
245+
> changes
246+
247+
These providers are:
248+
- DeclarationInfo so this target can be a dependency of a TypeScript rule
249+
- NpmPackageInfo so this target can interop with rules that expect third-party npm packages
250+
- LinkablePackageInfo for use with our "linker" that makes this package importable (similar to `npm link`)
251+
- JsModuleInfo so rules like bundlers can collect the transitive set of .js files
252+
253+
`js_library` also copies any source files into the bazel-out folder.
254+
This is the same behavior as the `copy_to_bin` rule.
255+
By copying the complete package to the output tree, we ensure that the linker (our `npm link` equivalent)
256+
will make your source files available in the node_modules tree where resolvers expect them.
257+
It also means you can have relative imports between the files
258+
rather than being forced to use Bazel's "Runfiles" semantics where any program might need a helper library
259+
to resolve files between the logical union of the source tree and the output tree.
260+
261+
### Usage
262+
263+
`js_library` is intended to be used internally within Bazel, such as between two libraries in your monorepo.
264+
265+
> Compare this to `pkg_npm` which is intended to publish your code for external usage outside of Bazel, like
266+
> by publishing to npm or artifactory.
267+
268+
The typical example usage of `js_library` is to expose some sources with a package name:
269+
270+
```python
271+
ts_project(
272+
name = "compile_ts",
273+
srcs = glob(["*.ts"]),
274+
)
275+
276+
js_library(
277+
name = "my_pkg",
278+
# Code that depends on this target can import from "@myco/mypkg"
279+
package_name = "@myco/mypkg",
280+
# Consumers might need fields like "main" or "typings"
281+
srcs = ["package.json"],
282+
# The .js and .d.ts outputs from above will be part of the package
283+
deps = [":compile_ts"],
284+
)
285+
```
286+
287+
To help work with "named AMD" modules as required by `ts_devserver` and other Google-style "concatjs" rules,
288+
`js_library` has some undocumented advanced features you can find in the source code or in our examples.
289+
These should not be considered a public API and aren't subject to our usual support and semver guarantees.
290+
291+
Args:
292+
name: a name for the target
293+
srcs: the list of files that comprise the package
294+
package_name: the name it will be imported by. Should match the "name" field in the package.json file.
295+
deps: other targets that provide JavaScript code
296+
**kwargs: used for undocumented legacy features
297+
"""
298+
299+
# Undocumented features
300+
amd_names = kwargs.pop("amd_names", {})
248301
module_name = kwargs.pop("module_name", None)
302+
named_module_srcs = kwargs.pop("named_module_srcs", [])
303+
249304
if module_name:
250305
fail("use package_name instead of module_name in target //%s:%s" % (native.package_name(), name))
251306
if kwargs.pop("is_windows", None):
252-
fail("is_windows is set by the js_library macro and should not be set explicitely")
307+
fail("is_windows is set by the js_library macro and should not be set explicitly")
308+
253309
_js_library(
254310
name = name,
255311
amd_names = amd_names,

internal/linker/test/integration/dynamic_linked_pkg/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("//internal/js_library:js_library.bzl", "js_library")
1+
load("//:index.bzl", "js_library")
22

33
package(default_visibility = ["//internal/linker/test:__subpackages__"])
44

internal/linker/test/integration/dynamic_linked_scoped_pkg/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("//internal/js_library:js_library.bzl", "js_library")
1+
load("//:index.bzl", "js_library")
22

33
package(default_visibility = ["//internal/linker/test:__subpackages__"])
44

internal/linker/test/integration/static_linked_pkg/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
2-
load("//internal/js_library:js_library.bzl", "js_library")
2+
load("//:index.bzl", "js_library")
33

44
package(default_visibility = ["//internal/linker/test:__subpackages__"])
55

internal/linker/test/integration/static_linked_scoped_pkg/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("//internal/js_library:js_library.bzl", "js_library")
1+
load("//:index.bzl", "js_library")
22

33
package(default_visibility = ["//internal/linker/test:__subpackages__"])
44

0 commit comments

Comments
 (0)