Skip to content

Commit

Permalink
feat(esbuild): make Starlark build settings usable as defines (#3122)
Browse files Browse the repository at this point in the history
Adds a `define_settings` attribute to the `esbuild` rules that allows
using the values of Starlark build settings to globally replace
specified identifiers.

The value of the setting is automatically converted to a JS literal.
Note: This currently uses json.encode, which is only available from
Bazel 5 on. If this addition is generally viewed favorably, I would
look into "polyfilling" this functionality in Starlark.
  • Loading branch information
fmeum authored and alexeagle committed Dec 18, 2021
1 parent b21827b commit f22502d
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 7 deletions.
35 changes: 31 additions & 4 deletions docs/esbuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ This will create an output directory containing all the code split chunks, along
**USAGE**

<pre>
esbuild(<a href="#esbuild-name">name</a>, <a href="#esbuild-args">args</a>, <a href="#esbuild-args_json">args_json</a>, <a href="#esbuild-config">config</a>, <a href="#esbuild-define">define</a>, <a href="#esbuild-deps">deps</a>, <a href="#esbuild-entry_point">entry_point</a>, <a href="#esbuild-entry_points">entry_points</a>, <a href="#esbuild-external">external</a>, <a href="#esbuild-format">format</a>,
<a href="#esbuild-launcher">launcher</a>, <a href="#esbuild-link_workspace_root">link_workspace_root</a>, <a href="#esbuild-max_threads">max_threads</a>, <a href="#esbuild-metafile">metafile</a>, <a href="#esbuild-minify">minify</a>, <a href="#esbuild-node_context_data">node_context_data</a>, <a href="#esbuild-output">output</a>,
<a href="#esbuild-output_css">output_css</a>, <a href="#esbuild-output_dir">output_dir</a>, <a href="#esbuild-output_map">output_map</a>, <a href="#esbuild-platform">platform</a>, <a href="#esbuild-sourcemap">sourcemap</a>, <a href="#esbuild-sources_content">sources_content</a>, <a href="#esbuild-splitting">splitting</a>, <a href="#esbuild-srcs">srcs</a>,
<a href="#esbuild-target">target</a>)
esbuild(<a href="#esbuild-name">name</a>, <a href="#esbuild-args">args</a>, <a href="#esbuild-args_json">args_json</a>, <a href="#esbuild-config">config</a>, <a href="#esbuild-define">define</a>, <a href="#esbuild-define_settings">define_settings</a>, <a href="#esbuild-deps">deps</a>, <a href="#esbuild-entry_point">entry_point</a>, <a href="#esbuild-entry_points">entry_points</a>,
<a href="#esbuild-external">external</a>, <a href="#esbuild-format">format</a>, <a href="#esbuild-launcher">launcher</a>, <a href="#esbuild-link_workspace_root">link_workspace_root</a>, <a href="#esbuild-max_threads">max_threads</a>, <a href="#esbuild-metafile">metafile</a>, <a href="#esbuild-minify">minify</a>,
<a href="#esbuild-node_context_data">node_context_data</a>, <a href="#esbuild-output">output</a>, <a href="#esbuild-output_css">output_css</a>, <a href="#esbuild-output_dir">output_dir</a>, <a href="#esbuild-output_map">output_map</a>, <a href="#esbuild-platform">platform</a>, <a href="#esbuild-sourcemap">sourcemap</a>,
<a href="#esbuild-sources_content">sources_content</a>, <a href="#esbuild-splitting">splitting</a>, <a href="#esbuild-srcs">srcs</a>, <a href="#esbuild-target">target</a>)
</pre>

Runs the esbuild bundler under Bazel
Expand Down Expand Up @@ -157,6 +157,33 @@ esbuild(

See https://esbuild.github.io/api/#define for more details

Defaults to `{}`

<h4 id="esbuild-define_settings">define_settings</h4>

(*<a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: Label -> String</a>*): A dict of labels of Starlark build settings and identifiers to be replaced with their values.
Example:
```python
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")

string_flag(
name = "api_endpoint",
build_setting_default = "https://example.com/v1",
)

esbuild(
name = "bundle",
define_settings = {
":api_endpoint": "API_ENDPOINT",
},
)
```

The build setting has to provide [`BuildSettingInfo`](https://github.com/bazelbuild/bazel-skylib/blob/6e30a77347071ab22ce346b6d20cf8912919f644/rules/common_settings.bzl#L24).
The value is automatically converted to a JS literal.
See https://docs.bazel.build/versions/main/skylark/config.html#predefined-settings for more details on Starlark build settings. The dependencies of this attribute must provide: Unknown Provider


Defaults to `{}`

<h4 id="esbuild-deps">deps</h4>
Expand Down
2 changes: 1 addition & 1 deletion packages/esbuild/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ bzl_library(
"@bazel_tools//tools:bzl_srcs",
],
deps = [
"@bazel_skylib//lib:paths",
"@bazel_skylib//rules:common_settings",
"@build_bazel_rules_nodejs//:bzl",
"@build_bazel_rules_nodejs//internal/common:bzl",
"@build_bazel_rules_nodejs//internal/node:bzl",
Expand Down
33 changes: 32 additions & 1 deletion packages/esbuild/esbuild.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
esbuild rule
"""

load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
load("@build_bazel_rules_nodejs//:providers.bzl", "ExternalNpmPackageInfo", "JSEcmaScriptModuleInfo", "JSModuleInfo", "NODE_CONTEXT_ATTRS", "NodeContextInfo", "node_modules_aspect", "run_node")
load("@build_bazel_rules_nodejs//internal/linker:link_node_modules.bzl", "LinkerPackageMappingInfo", "module_mappings_aspect")
Expand Down Expand Up @@ -49,7 +50,6 @@ def _esbuild_impl(ctx):
inputs = [d for d in inputs if not (d.path.endswith(".d.ts") or d.path.endswith(".tsbuildinfo"))]

outputs = []

args = dict({
"bundle": True,
"define": dict([
Expand All @@ -58,6 +58,12 @@ def _esbuild_impl(ctx):
expand_variables(ctx, ctx.expand_location(v), attribute_name = "define"),
]
for k, v in ctx.attr.define.items()
] + [
[
placeholder,
json.encode(setting[BuildSettingInfo].value),
]
for setting, placeholder in ctx.attr.define_settings.items()
]),
# the entry point files to bundle
"entryPoints": [
Expand Down Expand Up @@ -226,6 +232,31 @@ esbuild(
See https://esbuild.github.io/api/#define for more details
""",
),
"define_settings": attr.label_keyed_string_dict(
default = {},
doc = """A dict of labels of Starlark build settings and identifiers to be replaced with their values.
Example:
```python
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
string_flag(
name = "api_endpoint",
build_setting_default = "https://example.com/v1",
)
esbuild(
name = "bundle",
define_settings = {
":api_endpoint": "API_ENDPOINT",
},
)
```
The build setting has to provide [`BuildSettingInfo`](https://github.com/bazelbuild/bazel-skylib/blob/6e30a77347071ab22ce346b6d20cf8912919f644/rules/common_settings.bzl#L24).
The value is automatically converted to a JS literal.
See https://docs.bazel.build/versions/main/skylark/config.html#predefined-settings for more details on Starlark build settings.""",
providers = [BuildSettingInfo],
),
"deps": attr.label_list(
default = [],
aspects = [module_mappings_aspect, node_modules_aspect],
Expand Down
19 changes: 19 additions & 0 deletions packages/esbuild/test/define/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ load("//packages/esbuild:index.bzl", "esbuild", "esbuild_config")
load("//packages/jasmine:index.bzl", "jasmine_node_test")
load("//packages/concatjs:index.bzl", "ts_library")
load("//internal/node:context.bzl", "node_context_data")
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag")

ts_library(
name = "main",
Expand All @@ -26,6 +27,10 @@ esbuild(
"process.env.NODE_ENV": "\"defined_in_bundle\"",
"SOME_TEST_ENV": "'$(SOME_TEST_ENV)'",
},
define_settings = {
":some_bool_flag": "SOME_BOOL_FLAG_VALUE",
":some_string_flag": "SOME_STRING_FLAG_VALUE",
},
entry_point = "main.ts",
deps = [":main"],
)
Expand Down Expand Up @@ -53,6 +58,10 @@ esbuild(
"process.env.NODE_ENV": "\"defined_on_rule\"",
"SOME_TEST_ENV": "'$(SOME_TEST_ENV)'",
},
define_settings = {
":some_bool_flag": "SOME_BOOL_FLAG_VALUE",
":some_string_flag": "SOME_STRING_FLAG_VALUE",
},
entry_point = "main.ts",
node_context_data = ":context_data",
deps = [":main"],
Expand All @@ -66,3 +75,13 @@ jasmine_node_test(
":stamped_bundle",
],
)

bool_flag(
name = "some_bool_flag",
build_setting_default = True,
)

string_flag(
name = "some_string_flag",
build_setting_default = "default_`'\"flag\"'`_value",
)
4 changes: 4 additions & 0 deletions packages/esbuild/test/define/bundle_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ describe('esbuild define', () => {
const bundle = readFileSync(location, {encoding: 'utf8'});
expect(bundle).toContain(`nodeEnv = "defined_in_bundle"`);
expect(bundle).toContain(`env = "some_value"`);
expect(bundle).toContain(`someStringFlag = "default_\`'\\"flag\\"'\`_value"`);
expect(bundle).toContain(`someBoolFlag = true`);
expect(bundle).toContain(`cwd: () => "rules_nodejs"`);
expect(bundle).toContain(`version = BUILD_SCM_VERSION`);
});
Expand All @@ -17,6 +19,8 @@ describe('esbuild define', () => {
const bundle = readFileSync(stampedLocation, {encoding: 'utf8'});
expect(bundle).toContain(`nodeEnv = "defined_on_rule"`);
expect(bundle).toContain(`env = "some_value"`);
expect(bundle).toContain(`someStringFlag = "default_\`'\\"flag\\"'\`_value"`);
expect(bundle).toContain(`someBoolFlag = true`);
expect(bundle).toContain(`version = "v1.2.3"`);
});
});
6 changes: 5 additions & 1 deletion packages/esbuild/test/define/main.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
declare const BUILD_SCM_VERSION: string;
declare const SOME_TEST_ENV: string;
declare const SOME_BOOL_FLAG_VALUE: boolean;
declare const SOME_STRING_FLAG_VALUE: string;

export const nodeEnv = process.env.NODE_ENV;
export const version = BUILD_SCM_VERSION;
export const env = SOME_TEST_ENV;
export const someBoolFlag = SOME_BOOL_FLAG_VALUE;
export const someStringFlag = SOME_STRING_FLAG_VALUE;

console.log(process.cwd());
console.log(process.cwd());
10 changes: 10 additions & 0 deletions toolchains/esbuild/esbuild_repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ def esbuild_repositories(name = "", npm_repository = "npm", npm_args = []):
npm_args: additional args to pass to the npm install rule
"""

_maybe(
http_archive,
name = "bazel_skylib",
sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d",
urls = [
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
],
)

for name, meta in ESBUILD_PACKAGES.platforms.items():
maybe(
http_archive,
Expand Down

0 comments on commit f22502d

Please sign in to comment.