Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions internal/linker/link_node_modules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,18 @@ def _link_mapping(label, mappings, k, v):
else:
return True

def write_node_modules_manifest(ctx, extra_data = [], mnemonic = None):
def write_node_modules_manifest(ctx, extra_data = [], mnemonic = None, link_workspace_root = False):
"""Writes a manifest file read by the linker, containing info about resolving runtime dependencies

Args:
ctx: starlark rule execution context
extra_data: labels to search for npm packages that need to be linked (ctx.attr.deps and ctx.attr.data will always be searched)
mnemonic: optional action mnemonic, used to differentiate module mapping files from the same rule context
link_workspace_root: Link the workspace root to the bin_dir to support absolute requires like 'my_wksp/path/to/file'.
If source files need to be required then they can be copied to the bin_dir with copy_to_bin.
"""

mappings = {}
mappings = {ctx.workspace_name: ["execroot", ctx.bin_dir.path]} if link_workspace_root else {}
node_modules_root = ""

# Look through data/deps attributes to find...
Expand Down
12 changes: 12 additions & 0 deletions internal/linker/test/workspace_link/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
load("//packages/jasmine:index.bzl", "jasmine_node_test")

jasmine_node_test(
name = "test",
srcs = ["test.js"],
link_workspace_root = True,
templated_args = ["--nobazel_patch_module_resolver"],
deps = [
"//internal/linker/test/workspace_link/bar",
"//internal/linker/test/workspace_link/foo",
],
)
10 changes: 10 additions & 0 deletions internal/linker/test/workspace_link/bar/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")

copy_to_bin(
name = "bar",
srcs = [
"main.js",
"package.json",
],
visibility = ["//internal/linker/test/workspace_link:__pkg__"],
)
3 changes: 3 additions & 0 deletions internal/linker/test/workspace_link/bar/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
bar: 'bar',
}
5 changes: 5 additions & 0 deletions internal/linker/test/workspace_link/bar/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "bar",
"main": "main.js",
"typings": "main.d.ts"
}
35 changes: 35 additions & 0 deletions internal/linker/test/workspace_link/foo/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
load("@npm//typescript:index.bzl", "tsc")

tsc(
name = "foo_lib",
outs = [
"main.d.ts",
"main.js",
],
args = [
"-p",
"$(execpath tsconfig.json)",
"--outDir",
# $(RULEDIR) is a shorthand for the dist/bin directory where Bazel requires we write outputs
"$(RULEDIR)",
],
data = [
"main.ts",
"tsconfig.json",
],
)

copy_to_bin(
name = "foo_files",
srcs = ["package.json"],
)

filegroup(
name = "foo",
srcs = [
":foo_files",
":foo_lib",
],
visibility = ["//internal/linker/test/workspace_link:__pkg__"],
)
1 change: 1 addition & 0 deletions internal/linker/test/workspace_link/foo/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const foo: string = 'foo';
5 changes: 5 additions & 0 deletions internal/linker/test/workspace_link/foo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "foo",
"main": "main.js",
"typings": "main.d.ts"
}
6 changes: 6 additions & 0 deletions internal/linker/test/workspace_link/foo/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compilerOptions": {
"declaration": true,
"types": []
}
}
8 changes: 8 additions & 0 deletions internal/linker/test/workspace_link/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
describe('linker', () => {
it('should be able to require by absolute path when link_workspace_root is True', () => {
const foo = require('build_bazel_rules_nodejs/internal/linker/test/workspace_link/foo');
expect(foo.foo).toBe('foo');
const bar = require('build_bazel_rules_nodejs/internal/linker/test/workspace_link/bar');
expect(bar.bar).toBe('bar');
});
});
6 changes: 5 additions & 1 deletion internal/node/node.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def _to_execroot_path(ctx, file):
return file.path

def _nodejs_binary_impl(ctx):
node_modules_manifest = write_node_modules_manifest(ctx)
node_modules_manifest = write_node_modules_manifest(ctx, link_workspace_root = ctx.attr.link_workspace_root)
node_modules_depsets = []
node_modules_depsets.append(depset(ctx.files.node_modules))
if NpmPackageInfo in ctx.attr.node_modules:
Expand Down Expand Up @@ -422,6 +422,10 @@ nodejs_binary(
mandatory = True,
allow_single_file = True,
),
"link_workspace_root": attr.bool(
doc = """Link the workspace root to the bin_dir to support absolute requires like 'my_wksp/path/to/file'.
If source files need to be required then they can be copied to the bin_dir with copy_to_bin.""",
),
"node_modules": attr.label(
doc = """The npm packages which should be available to `require()` during
execution.
Expand Down
7 changes: 6 additions & 1 deletion internal/node/npm_package_bin.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ _ATTRS = {
"configuration_env_vars": attr.string_list(default = []),
"data": attr.label_list(allow_files = True, aspects = [module_mappings_aspect, node_modules_aspect]),
"exit_code_out": attr.output(),
"link_workspace_root": attr.bool(),
"output_dir": attr.bool(),
"outs": attr.output_list(),
"stderr": attr.output(),
Expand Down Expand Up @@ -78,6 +79,7 @@ def _impl(ctx):
stdout = ctx.outputs.stdout,
stderr = ctx.outputs.stderr,
exit_code_out = ctx.outputs.exit_code_out,
link_workspace_root = ctx.attr.link_workspace_root,
)

return [DefaultInfo(files = depset(outputs + tool_outputs))]
Expand All @@ -87,7 +89,7 @@ _npm_package_bin = rule(
attrs = _ATTRS,
)

def npm_package_bin(tool = None, package = None, package_bin = None, data = [], outs = [], args = [], output_dir = False, **kwargs):
def npm_package_bin(tool = None, package = None, package_bin = None, data = [], outs = [], args = [], output_dir = False, link_workspace_root = False, **kwargs):
"""Run an arbitrary npm package binary (e.g. a program under node_modules/.bin/*) under Bazel.

It must produce outputs. If you just want to run a program with `bazel run`, use the nodejs_binary rule.
Expand Down Expand Up @@ -162,6 +164,8 @@ def npm_package_bin(tool = None, package = None, package_bin = None, data = [],
package_bin: the "bin" entry from `package` that should be run. By default package_bin is the same string as `package`
tool: a label for a binary to run, like `@npm//terser/bin:terser`. This is the longer form of package/package_bin.
Note that you can also refer to a binary in your local workspace.
link_workspace_root: Link the workspace root to the bin_dir to support absolute requires like 'my_wksp/path/to/file'.
If source files need to be required then they can be copied to the bin_dir with copy_to_bin.
"""
if not tool:
if not package:
Expand All @@ -175,5 +179,6 @@ def npm_package_bin(tool = None, package = None, package_bin = None, data = [],
args = args,
output_dir = output_dir,
tool = tool,
link_workspace_root = link_workspace_root,
**kwargs
)
12 changes: 11 additions & 1 deletion internal/providers/node_runtime_deps_info.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ def run_node(ctx, inputs, arguments, executable, **kwargs):
inputs: list or depset of inputs to the action
arguments: list or ctx.actions.Args object containing arguments to pass to the executable
executable: stringy representation of the executable this action will run, eg eg. "my_executable" rather than ctx.executable.my_executable
mnemonic: optional action mnemonic, used to differentiate module mapping files from the same rule context
link_workspace_root: Link the workspace root to the bin_dir to support absolute requires like 'my_wksp/path/to/file'.
If source files need to be required then they can be copied to the bin_dir with copy_to_bin.
kwargs: all other args accepted by ctx.actions.run
"""
if (type(executable) != "string"):
Expand All @@ -82,8 +85,15 @@ def run_node(ctx, inputs, arguments, executable, **kwargs):
extra_inputs = exec_attr[NodeRuntimeDepsInfo].deps
link_data = exec_attr[NodeRuntimeDepsInfo].pkgs

# NB: mnemonic is also passed to ctx.actions.run below
mnemonic = kwargs.get("mnemonic")
modules_manifest = write_node_modules_manifest(ctx, link_data, mnemonic)
link_workspace_root = kwargs.pop("link_workspace_root", False)
modules_manifest = write_node_modules_manifest(
ctx,
extra_data = link_data,
mnemonic = mnemonic,
link_workspace_root = link_workspace_root,
)
add_arg(arguments, "--bazel_node_modules_manifest=%s" % modules_manifest.path)

stdout_file = kwargs.pop("stdout", None)
Expand Down
5 changes: 5 additions & 0 deletions packages/rollup/rollup_bundle.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ Either this attribute or `entry_point` must be specified, but not both.
values = ["amd", "cjs", "esm", "iife", "umd", "system"],
default = "esm",
),
"link_workspace_root": attr.bool(
doc = """Link the workspace root to the bin_dir to support absolute requires like 'my_wksp/path/to/file'.
If source files need to be required then they can be copied to the bin_dir with copy_to_bin.""",
),
"output_dir": attr.bool(
doc = """Whether to produce a directory output.

Expand Down Expand Up @@ -349,6 +353,7 @@ def _rollup_bundle(ctx):
mnemonic = "Rollup",
execution_requirements = execution_requirements,
env = {"COMPILATION_MODE": ctx.var["COMPILATION_MODE"]},
link_workspace_root = ctx.attr.link_workspace_root,
)

outputs_depset = depset(outputs)
Expand Down
30 changes: 30 additions & 0 deletions packages/rollup/test/workspace_link/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
load("//packages/jasmine:index.bzl", "jasmine_node_test")
load("//packages/rollup:index.bzl", "rollup_bundle")

copy_to_bin(
name = "foo",
srcs = ["foo.js"],
)

rollup_bundle(
name = "bundle",
srcs = [
"bar.js",
"main.js",
":foo",
],
config_file = "rollup.config.js",
entry_point = "main.js",
link_workspace_root = True,
deps = [
"@npm//@rollup/plugin-commonjs",
"@npm//@rollup/plugin-node-resolve",
],
)

jasmine_node_test(
name = "test",
srcs = ["spec.js"],
deps = ["bundle"],
)
1 change: 1 addition & 0 deletions packages/rollup/test/workspace_link/bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const bar = 'bar';
1 change: 1 addition & 0 deletions packages/rollup/test/workspace_link/foo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const foo = 'foo';
5 changes: 5 additions & 0 deletions packages/rollup/test/workspace_link/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as foo from 'build_bazel_rules_nodejs/packages/rollup/test/workspace_link/foo';
import * as bar from './bar';

console.log(foo);
console.log(bar);
15 changes: 15 additions & 0 deletions packages/rollup/test/workspace_link/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import commonjs from '@rollup/plugin-commonjs';
import nodeResolve from '@rollup/plugin-node-resolve';

module.exports = {
onwarn: (warning) => {
// Always fail on warnings, assuming we don't know which are harmless.
// We can add exclusions here based on warning.code, if we discover some
// types of warning should always be ignored under bazel.
throw new Error(warning.message);
},
plugins: [
nodeResolve(),
commonjs(),
],
};
11 changes: 11 additions & 0 deletions packages/rollup/test/workspace_link/spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const fs = require('fs');
const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']);

describe('rollup', () => {
it('should bundle absolute & relative imports', async () => {
const file = runfiles.resolvePackageRelative('bundle.js');
const bundle = fs.readFileSync(file, 'utf-8');
expect(bundle).toContain(`const foo = 'foo';`);
expect(bundle).toContain(`const bar = 'bar';`);
});
});
5 changes: 5 additions & 0 deletions packages/terser/terser_minified.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ Instead of setting this attribute, consider using debugging compilation mode ins
bazel build --compilation_mode=dbg //my/terser:target
so that it only affects the current build.
""",
),
"link_workspace_root": attr.bool(
doc = """Link the workspace root to the bin_dir to support absolute requires like 'my_wksp/path/to/file'.
If source files need to be required then they can be copied to the bin_dir with copy_to_bin.""",
),
"sourcemap": attr.bool(
doc = "Whether to produce a .js.map output",
Expand Down Expand Up @@ -183,6 +187,7 @@ def _terser(ctx):
arguments = [args],
env = {"COMPILATION_MODE": ctx.var["COMPILATION_MODE"]},
progress_message = "Minifying JavaScript %s [terser]" % (outputs[0].short_path),
link_workspace_root = ctx.attr.link_workspace_root,
)

return [
Expand Down
5 changes: 5 additions & 0 deletions packages/typescript/internal/build_defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ def _compile_action(ctx, inputs, outputs, tsconfig_file, node_opts, description
arguments = arguments,
executable = "compiler",
env = {"COMPILATION_MODE": ctx.var["COMPILATION_MODE"]},
link_workspace_root = ctx.attr.link_workspace_root,
)

# Enable the replay_params in case an aspect needs to re-build this library.
Expand Down Expand Up @@ -384,6 +385,10 @@ This value will override the `target` option in the user supplied tsconfig.""",
default = _DEVMODE_TARGET_DEFAULT,
),
"internal_testing_type_check_dependencies": attr.bool(default = False, doc = "Testing only, whether to type check inputs that aren't srcs."),
"link_workspace_root": attr.bool(
doc = """Link the workspace root to the bin_dir to support absolute requires like 'my_wksp/path/to/file'.
If source files need to be required then they can be copied to the bin_dir with copy_to_bin.""",
),
"node_modules": attr.label(
doc = """The npm packages which should be available during the compile.

Expand Down
7 changes: 7 additions & 0 deletions packages/typescript/internal/ts_project.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ _ATTRS = {
"declaration_dir": attr.string(),
"deps": attr.label_list(providers = [DeclarationInfo], aspects = [module_mappings_aspect]),
"extends": attr.label_list(allow_files = [".json"]),
"link_workspace_root": attr.bool(),
"out_dir": attr.string(),
"root_dir": attr.string(),
# NB: no restriction on extensions here, because tsc sometimes adds type-check support
Expand Down Expand Up @@ -153,6 +154,7 @@ def _ts_project_impl(ctx):
ctx.label,
ctx.file.tsconfig.short_path,
),
link_workspace_root = ctx.attr.link_workspace_root,
)

providers = [
Expand Down Expand Up @@ -271,6 +273,7 @@ def ts_project_macro(
declaration_dir = None,
out_dir = None,
root_dir = None,
link_workspace_root = False,
**kwargs):
"""Compiles one TypeScript project using `tsc --project`

Expand Down Expand Up @@ -465,6 +468,9 @@ def ts_project_macro(
ts_build_info_file: the user-specified value of `tsBuildInfoFile` from the tsconfig.
Helps Bazel to predict the path where the .tsbuildinfo output is written.

link_workspace_root: Link the workspace root to the bin_dir to support absolute requires like 'my_wksp/path/to/file'.
If source files need to be required then they can be copied to the bin_dir with copy_to_bin.

**kwargs: passed through to underlying rule, allows eg. visibility, tags
"""

Expand Down Expand Up @@ -550,5 +556,6 @@ def ts_project_macro(
typing_maps_outs = _out_paths(srcs, typings_out_dir, root_dir, ".d.ts.map") if declaration_map else [],
buildinfo_out = tsbuildinfo_path if composite or incremental else None,
tsc = tsc,
link_workspace_root = link_workspace_root,
**kwargs
)