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
7 changes: 6 additions & 1 deletion .github/configure-bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#!/usr/bin/env sh
set -e
cat > user.bazelrc <<EOF
cat > .bazelrc.user <<EOF
build --config=ci
build --noworker_sandboxing
build --noexperimental_use_hermetic_linux_sandbox
build --noexperimental_worker_multiplex_sandboxing
build --noexperimental_worker_sandbox_hardening
build:linux --noexperimental_worker_sandbox_hardening
EOF
22 changes: 15 additions & 7 deletions docs/nodejs.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ Then run:
bazel run :nodejs_install
```

`nodejs_install` writes `node_modules/.install-manifest.json` and, by default,
`node_modules/.yarn-state.yml`. The Yarn state file contains a digest of the
generated install manifest so tools such as Vite, which key dependency caches
from package-manager install state, invalidate caches when the Bazel-generated
`node_modules` layout changes. Set `package_manager_state_file = ""` to disable
this marker.

# //nodejs:nodejs.bzl

<!-- Generated with Stardoc: http://skydoc.bazel.build -->
Expand Down Expand Up @@ -400,17 +407,18 @@ nodejs_toolchain(<a href="#nodejs_toolchain-name">name</a>, <a href="#nodejs_too
<pre>
load("@rules_javascript//nodejs:rules.bzl", "nodejs_install")

nodejs_install(<a href="#nodejs_install-name">name</a>, <a href="#nodejs_install-src">src</a>, <a href="#nodejs_install-path">path</a>, <a href="#nodejs_install-kwargs">**kwargs</a>)
nodejs_install(<a href="#nodejs_install-name">name</a>, <a href="#nodejs_install-src">src</a>, <a href="#nodejs_install-path">path</a>, <a href="#nodejs_install-package_manager_state_file">package_manager_state_file</a>, <a href="#nodejs_install-kwargs">**kwargs</a>)
</pre>

**PARAMETERS**

| Name | Description | Default Value |
| :--------------------------------------- | :------------------------ | :------------ |
| <a id="nodejs_install-name"></a>name | <p align="center"> - </p> | none |
| <a id="nodejs_install-src"></a>src | <p align="center"> - </p> | none |
| <a id="nodejs_install-path"></a>path | <p align="center"> - </p> | `None` |
| <a id="nodejs_install-kwargs"></a>kwargs | <p align="center"> - </p> | none |
| Name | Description | Default Value |
| :------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------ |
| <a id="nodejs_install-name"></a>name | <p align="center"> - </p> | none |
| <a id="nodejs_install-src"></a>src | <p align="center"> - </p> | none |
| <a id="nodejs_install-path"></a>path | <p align="center"> - </p> | `None` |
| <a id="nodejs_install-package_manager_state_file"></a>package_manager_state_file | Package manager install-state file to write under `node_modules`. The default `.yarn-state.yml` lets tools such as Vite invalidate dependency caches when the generated install manifest changes. Set to `""` to disable. | `".yarn-state.yml"` |
| <a id="nodejs_install-kwargs"></a>kwargs | <p align="center"> - </p> | none |

<a id="nodejs_modules"></a>

Expand Down
2 changes: 1 addition & 1 deletion jest/test/src/snapshot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ test("Snapshot", async () => {
await fs.promises.unlink(
"jest/test/bazel/snapshot/__snapshots__/example.spec.js.snap",
);
});
}, 120_000);
7 changes: 7 additions & 0 deletions nodejs/doc/doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,10 @@ Then run:
```sh
bazel run :nodejs_install
```

`nodejs_install` writes `node_modules/.install-manifest.json` and, by default,
`node_modules/.yarn-state.yml`. The Yarn state file contains a digest of the
generated install manifest so tools such as Vite, which key dependency caches
from package-manager install state, invalidate caches when the Bazel-generated
`node_modules` layout changes. Set `package_manager_state_file = ""` to disable
this marker.
3 changes: 2 additions & 1 deletion nodejs/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -630,10 +630,11 @@ nodejs_repl = rule(
implementation = _nodejs_repl_impl,
)

def nodejs_install(name, src, path = None, **kwargs):
def nodejs_install(name, src, path = None, package_manager_state_file = ".yarn-state.yml", **kwargs):
pkg_install(
name = name,
pkg = src,
package_manager_state_file = package_manager_state_file,
path = "%s/node_modules" % path if path else "node_modules",
**kwargs
)
Expand Down
1 change: 1 addition & 0 deletions npm/test/bazel/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ exports_files(
yarn_resolve(
name = "resolve",
output = "npm.bzl",
patches = "npm-patches",
)
2 changes: 1 addition & 1 deletion npm/test/bazel/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"devDependencies": {
"lodash": "^4.17.21"
"lodash": "^4.18.1"
}
}
9 changes: 4 additions & 5 deletions npm/test/bazel/yarn.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/install-runner.sh.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ if [ -z "${RUNFILES_DIR-}" ]; then
fi
fi

exec "$RUNFILES_DIR"/%{install} "$RUNFILES_DIR"/%{manifest} "${BUILD_WORKSPACE_DIRECTORY-.}"/%{path}
exec "$RUNFILES_DIR"/%{install} %{package_manager_state_args} "$RUNFILES_DIR"/%{manifest} "${BUILD_WORKSPACE_DIRECTORY-.}"/%{path}
39 changes: 39 additions & 0 deletions pkg/install/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from "@rules-javascript/pkg-install-manifest";
import { JsonFormat } from "@rules-javascript/util-json";
import { ArgumentParser } from "argparse";
import { createHash } from "node:crypto";
import {
chmod,
copyFile,
Expand All @@ -19,6 +20,7 @@ import { join } from "node:path";

(async () => {
const parser = new ArgumentParser();
parser.add_argument("--package-manager-state-file");
parser.add_argument("manifest");
parser.add_argument("output");
const args = parser.parse_args();
Expand All @@ -30,10 +32,14 @@ import { join } from "node:path";
);

const existingPath = join(args.output, ".install-manifest.json");
const packageManagerStatePath = args.package_manager_state_file
? join(args.output, args.package_manager_state_file)
: undefined;
let existing: InstallManifest | undefined;
try {
const existingContent = await readFile(existingPath, "utf8");
if (manifestContent === existingContent) {
await writePackageManagerState(packageManagerStatePath, manifestContent);
return;
}
existing = JsonFormat.parse(installManifestFormat(false), existingContent);
Expand All @@ -48,11 +54,44 @@ import { join } from "node:path";

await install(manifest, existing, args.output);
await writeFile(existingPath, manifestContent);
await writePackageManagerState(packageManagerStatePath, manifestContent);
})().catch((error) => {
console.error(error);
process.exit(1);
});

async function writePackageManagerState(
path: string | undefined,
manifestContent: string,
) {
if (!path) {
return;
}
const manifestSha256 = createHash("sha256")
.update(manifestContent)
.digest("hex");
const content = [
"# Warning: This file is automatically generated. Removing it is fine, but will",
"# cause your node_modules installation to become invalidated.",
"",
"__metadata:",
" version: 1",
" nmMode: classic",
` rulesJavascriptInstallManifestSha256: ${manifestSha256}`,
"",
].join("\n");
try {
if ((await readFile(path, "utf8")) === content) {
return;
}
} catch (error) {
if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) {
throw error;
}
}
await writeFile(path, content);
}

async function install(
manifest: InstallEntry,
existing: InstallEntry | undefined,
Expand Down
6 changes: 6 additions & 0 deletions pkg/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ def _pkg_install_impl(ctx):
substitutions = {
"%{install}": shell.quote(to_rlocation_path(ctx, install)),
"%{manifest}": shell.quote(to_rlocation_path(ctx, manifest)),
"%{package_manager_state_args}": (
"--package-manager-state-file %s" % shell.quote(ctx.attr.package_manager_state_file) if ctx.attr.package_manager_state_file else ""
),
"%{path}": shell.quote(path),
},
is_executable = True,
Expand All @@ -141,6 +144,9 @@ def _pkg_install_impl(ctx):
pkg_install = rule(
attrs = {
"path": attr.string(mandatory = True),
"package_manager_state_file": attr.string(
doc = "Optional package manager install-state file to write under path, for tools that key caches from package manager state.",
),
"pkg": attr.label(
mandatory = True,
providers = [PackageFilegroupInfo],
Expand Down
57 changes: 55 additions & 2 deletions rollup/rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("//commonjs:providers.bzl", "CjsInfo", "gen_manifest", "package_path")
load("//file:file.bzl", "FileInfo")
load("//javascript:providers.bzl", "JsInfo")
load("//javascript:rules.bzl", "js_export")
load("//javascript:rules.bzl", "js_dep_file")
load("//nodejs:nodejs.bzl", "NodejsInfo")
load("//nodejs:rules.bzl", "nodejs_binary")
load("//pnp:providers.bzl", "pnp_gen")
Expand Down Expand Up @@ -128,7 +128,7 @@ def _rollup_bundle_impl(ctx):

return [default_info]

rollup_bundle = rule(
_rollup_bundle = rule(
attrs = {
"config": attr.label(
cfg = _rollup_config_transition,
Expand Down Expand Up @@ -178,3 +178,56 @@ rollup_bundle = rule(
doc = "Rollup bundle",
implementation = _rollup_bundle_impl,
)

def configure_rollup(name, dep, config, config_dep, visibility = None):
"""Set up a Rollup tool target with a bundled config.

This macro preserves the older API where rollup_bundle accepted a configured
rollup target instead of a separate config attribute.
"""

js_dep_file(
name = "%s.config" % name,
dep = config_dep,
path = config,
visibility = ["//visibility:private"],
)

rollup(
name = name,
dep = dep,
visibility = visibility,
)

def rollup_bundle(name, dep, config = None, rollup = None, output = "", **kwargs):
"""Bundle JavaScript with Rollup.

Prefer passing config directly. If config is omitted, rollup must point to a
target created by configure_rollup.
"""

if config == None:
if rollup == None:
fail("rollup_bundle requires config unless rollup points to a target created by configure_rollup")
config = _configured_rollup_config_label(rollup)

attrs = {
"name": name,
"config": config,
"dep": dep,
"output": output,
}
if rollup != None:
attrs["rollup"] = rollup
attrs.update(kwargs)
_rollup_bundle(**attrs)

def _configured_rollup_config_label(rollup):
rollup = str(rollup)
if ":" in rollup:
return "%s.config" % rollup
if rollup.startswith("//") or rollup.startswith("@"):
package = rollup.split("//", 1)[1]
name = package.rpartition("/")[2]
return "%s:%s.config" % (rollup, name)
return "%s.config" % rollup
15 changes: 14 additions & 1 deletion rollup/test/bazel/basic/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
load("@rules_javascript//commonjs:rules.bzl", "cjs_root")
load("@rules_javascript//javascript:rules.bzl", "js_file", "js_library")
load("@rules_javascript//rollup:rules.bzl", "rollup_bundle")
load("@rules_javascript//rollup:rules.bzl", "configure_rollup", "rollup_bundle")

cjs_root(
name = "root",
Expand Down Expand Up @@ -32,3 +32,16 @@ rollup_bundle(
config = ":rollup_config",
dep = ":lib",
)

configure_rollup(
name = "legacy_rollup",
config = "rollup.config.js",
config_dep = ":rollup_config",
dep = "@npm//rollup:lib",
)

rollup_bundle(
name = "legacy_bundle",
dep = ":lib",
rollup = ":legacy_rollup",
)
14 changes: 9 additions & 5 deletions rollup/test/src/basic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import { spawnOptions } from "@rules-javascript/test";
import * as childProcess from "node:child_process";

test("Basic", () => {
const result = childProcess.spawnSync("bazel", ["build", "basic:bundle"], {
cwd: "rollup/test/bazel",
stdio: "inherit",
...spawnOptions(),
});
const result = childProcess.spawnSync(
"bazel",
["build", "basic:bundle", "basic:legacy_bundle"],
{
cwd: "rollup/test/bazel",
stdio: "inherit",
...spawnOptions(),
},
);
expect(result.status).toBe(0);
});
Loading