Skip to content
Draft
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
4 changes: 4 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ rules_ts_ext.deps(

use_repo(rules_ts_ext, "npm_typescript")

# Prebuilt host hermesc, referenced by the hermes_compile rule default.
hermes_ext = use_extension("//javascript:extensions.bzl", "hermes")
use_repo(hermes_ext, "rn_hermesc")

bazel_dep(name = "rules_kotlin", version = "2.1.8")
bazel_dep(name = "rules_java", version = "7.2.0")
bazel_dep(name = "rules_jvm_external", version = "6.8")
Expand Down
7 changes: 4 additions & 3 deletions docs/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ A test target that runs eslint on the given sources.
load("@rules_player//javascript:defs.bzl", "js_pipeline")

js_pipeline(<a href="#js_pipeline-package_name">package_name</a>, <a href="#js_pipeline-name">name</a>, <a href="#js_pipeline-srcs">srcs</a>, <a href="#js_pipeline-package_json">package_json</a>, <a href="#js_pipeline-root_package_json">root_package_json</a>, <a href="#js_pipeline-vitest_config">vitest_config</a>, <a href="#js_pipeline-tsup_config">tsup_config</a>,
<a href="#js_pipeline-tsconfig">tsconfig</a>, <a href="#js_pipeline-node_modules">node_modules</a>, <a href="#js_pipeline-deps">deps</a>, <a href="#js_pipeline-native_bundle">native_bundle</a>, <a href="#js_pipeline-private">private</a>, <a href="#js_pipeline-peer_deps">peer_deps</a>, <a href="#js_pipeline-create_package_json_args">create_package_json_args</a>,
<a href="#js_pipeline-include_packaging_targets">include_packaging_targets</a>, <a href="#js_pipeline-test_deps">test_deps</a>, <a href="#js_pipeline-lint_deps">lint_deps</a>, <a href="#js_pipeline-build_deps">build_deps</a>, <a href="#js_pipeline-benchmark_envs">benchmark_envs</a>,
<a href="#js_pipeline-_extra_replace_prefixes">_extra_replace_prefixes</a>)
<a href="#js_pipeline-tsconfig">tsconfig</a>, <a href="#js_pipeline-node_modules">node_modules</a>, <a href="#js_pipeline-deps">deps</a>, <a href="#js_pipeline-native_bundle">native_bundle</a>, <a href="#js_pipeline-emit_hbc">emit_hbc</a>, <a href="#js_pipeline-private">private</a>, <a href="#js_pipeline-peer_deps">peer_deps</a>,
<a href="#js_pipeline-create_package_json_args">create_package_json_args</a>, <a href="#js_pipeline-include_packaging_targets">include_packaging_targets</a>, <a href="#js_pipeline-test_deps">test_deps</a>, <a href="#js_pipeline-lint_deps">lint_deps</a>, <a href="#js_pipeline-build_deps">build_deps</a>,
<a href="#js_pipeline-benchmark_envs">benchmark_envs</a>, <a href="#js_pipeline-_extra_replace_prefixes">_extra_replace_prefixes</a>)
</pre>

The main entry point for any JS/TS project. `js_pipeline` should be the only thing you need in your BUILD file.
Expand All @@ -93,6 +93,7 @@ Creates a js_library, npm_package, and test targets for a given package.
| <a id="js_pipeline-node_modules"></a>node_modules | The base node_modules to pull dependencies from (defaults to //:node_modules). | `"//:node_modules"` |
| <a id="js_pipeline-deps"></a>deps | The dependencies for the package. | `[]` |
| <a id="js_pipeline-native_bundle"></a>native_bundle | The name for the native bundle global if defined. | `None` |
| <a id="js_pipeline-emit_hbc"></a>emit_hbc | When True (with native_bundle set), also compile the native bundle to Hermes bytecode, exposed as `:hbc`. Used for cross-platform Android plugins. | `False` |
| <a id="js_pipeline-private"></a>private | Whether or not the package should be private (skipping an npm release). | `False` |
| <a id="js_pipeline-peer_deps"></a>peer_deps | The peer dependencies for the package. | `[]` |
| <a id="js_pipeline-create_package_json_args"></a>create_package_json_args | Additional arguments to pass to the package_json creation | `{}` |
Expand Down
21 changes: 21 additions & 0 deletions javascript/extensions.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Module extensions for JavaScript rules."""

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

# Pinned react-native version whose npm tarball ships the prebuilt host hermesc.
_RN_VERSION = "0.78.1"
_RN_TARBALL_SHA256 = "bf4198ba712c09df3de6d493cfaf968498cddb7107ecd48a081a1ce32d18be06"

def _hermes_impl(_module_ctx):
http_archive(
name = "rn_hermesc",
build_file = "@rules_player//javascript/private:hermesc.BUILD",
sha256 = _RN_TARBALL_SHA256,
strip_prefix = "package",
url = "https://registry.npmjs.org/react-native/-/react-native-{v}.tgz".format(v = _RN_VERSION),
)

hermes = module_extension(
implementation = _hermes_impl,
doc = "Provides `@rn_hermesc//:hermesc`, the prebuilt host Hermes compiler.",
)
10 changes: 10 additions & 0 deletions javascript/private/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ bzl_library(
],
deps = [
":eslint",
":hermesc",
":package_json",
":tsup",
":utils",
Expand All @@ -48,6 +49,15 @@ bzl_library(
],
)

bzl_library(
name = "hermesc",
srcs = ["hermesc.bzl"],
visibility = [
"//docs:__subpackages__",
"//javascript:__subpackages__",
],
)

bzl_library(
name = "vitest",
srcs = ["vitest.bzl"],
Expand Down
18 changes: 18 additions & 0 deletions javascript/private/hermesc.BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Prebuilt Hermes compiler (hermesc) shipped in the react-native npm tarball.
# Host-only: compiles JS -> HBC on the build machine. Selected by host OS.
load("@bazel_skylib//rules:native_binary.bzl", "native_binary")

native_binary(
name = "hermesc",
src = select({
"@bazel_tools//src/conditions:darwin": "sdks/hermesc/osx-bin/hermesc",
"@bazel_tools//src/conditions:windows": "sdks/hermesc/win64-bin/hermesc.exe",
"//conditions:default": "sdks/hermesc/linux64-bin/hermesc",
}),
data = select({
"@bazel_tools//src/conditions:windows": glob(["sdks/hermesc/win64-bin/*.dll"]),
"//conditions:default": [],
}),
out = "hermesc",
visibility = ["//visibility:public"],
)
69 changes: 69 additions & 0 deletions javascript/private/hermesc.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""
Hermes bytecode (HBC) compilation.

`hermes_compile` runs the prebuilt host `hermesc` over a single JS file to emit
Hermes bytecode. `hermes_bundle` is a convenience macro that extracts the
`<bundle>.native.js` produced by a `js_pipeline` native bundle and compiles it.
"""

def _hermes_compile_impl(context):
input = context.file.js
hbc = context.actions.declare_file("%s.hbc" % input.basename)

args = context.actions.args()
args.add("-emit-binary")
args.add("-out", hbc)
args.add(input)

context.actions.run(
mnemonic = "HermesC",
executable = context.executable._hermesc,
arguments = [args],
inputs = depset([input]),
outputs = [hbc],
)

return [DefaultInfo(files = depset([hbc]))]

hermes_compile = rule(
implementation = _hermes_compile_impl,
attrs = {
"js": attr.label(
allow_single_file = True,
doc = "Single JS file to compile to HBC.",
),
"_hermesc": attr.label(
default = Label("@rn_hermesc//:hermesc"),
allow_single_file = True,
executable = True,
cfg = "exec",
),
},
)

def hermes_bundle(name, native_bundle, bundle_name, visibility = None):
"""Compile a js_pipeline native bundle to Hermes bytecode.

Args:
name: Name of the resulting HBC target.
native_bundle: The `:<name>_native_bundle` target from js_pipeline.
bundle_name: The `native_bundle` string passed to js_pipeline (e.g. "Player").
visibility: Visibility for the generated targets.
"""
native_js = "%s.native.js" % bundle_name
extract_name = "%s_native_js" % name

# js_run_binary emits a set of files (dist/<bundle>.native.js + .map);
# hermesc needs a single file, so pull it out flat.
native.genrule(
name = extract_name,
srcs = [native_bundle],
outs = [native_js],
cmd = "echo $(SRCS) | tr ' ' '\\n' | grep %s$$ | xargs -I {} cp {} $(OUTS)" % native_js,
)

hermes_compile(
name = name,
js = ":" + extract_name,
visibility = visibility,
)
12 changes: 12 additions & 0 deletions javascript/private/js_pipeline.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ load("@aspect_rules_js//npm:defs.bzl", "npm_package")
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
load(":eslint.bzl", "eslint_test")
load(":hermesc.bzl", "hermes_bundle")
load(":package_json.bzl", "create_package_json")
load(":tsup.bzl", "tsup_build", "tsup_native_build")
load(":utils.bzl", "filter_empty", "without_tests")
Expand All @@ -29,6 +30,7 @@ def js_pipeline(
node_modules = "//:node_modules",
deps = [],
native_bundle = None,
emit_hbc = False,
private = False,
peer_deps = [],
create_package_json_args = {},
Expand All @@ -55,6 +57,8 @@ def js_pipeline(
node_modules: The base node_modules to pull dependencies from (defaults to //:node_modules).
deps: The dependencies for the package.
native_bundle: The name for the native bundle global if defined.
emit_hbc: When True (with native_bundle set), also compile the native bundle to
Hermes bytecode, exposed as `:hbc`. Used for cross-platform Android plugins.
private: Whether or not the package should be private (skipping an npm release).
create_package_json_args: Additional arguments to pass to the package_json creation
include_packaging_targets: Additional dependencies to add to the package target
Expand Down Expand Up @@ -105,6 +109,14 @@ def js_pipeline(
node_modules = node_modules,
)

if emit_hbc:
hermes_bundle(
name = name + "_hbc",
native_bundle = native_bundle_target,
bundle_name = native_bundle,
visibility = ["//visibility:public"],
)

if tsconfig == None:
tsconfig_name = "{}_tsconfig".format(name)
prefix = "../" * len(native.package_name().split("/"))
Expand Down