Skip to content

Commit

Permalink
bun: init configHook and fetchDeps; bun 1.1.43 -> 1.2.0; bun: switch …
Browse files Browse the repository at this point in the history
…to finalAttrs from rec

bun: switch to finalAttrs from rec

Could speed up hydra?

bun: added hook tests and improve passthru for hooks
  • Loading branch information
Eveeifyeve committed Jan 24, 2025
1 parent 4b85446 commit bb19900
Show file tree
Hide file tree
Showing 6 changed files with 430 additions and 70 deletions.
128 changes: 127 additions & 1 deletion doc/languages-frameworks/javascript.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,8 @@ set `prePnpmInstall` to the right commands to run. For example:

```nix
prePnpmInstall = ''
pnpm config set dedupe-peer-dependants false
pnpm config set dedupe-peer-dependants false
'';
pnpmDeps = pnpm.fetchDeps {
inherit (finalAttrs) prePnpmInstall;
Expand All @@ -525,6 +526,131 @@ pnpmDeps = pnpm.fetchDeps {
In this example, `prePnpmInstall` will be run by both `pnpm.configHook` and by the `pnpm.fetchDeps` builder.


### Bun {#javascript-bun}

Bun based projects use a `bun.lock` file instead of a `package-lock.json` to pin dependencies. Nixpkgs provides a hooks below to for install dependacies via `bun.configHook` which configuates the project to install via the use of `bunDeps` before building the project.

```nix
{
stdenv,
bun
}:
stdenv.mkDerivation (finalAttrs: {
pname = "foo";
version = "0-unstable-1980-01-01";
src = ...;
nativeBuildInputs = [
bun.configHook
];
bunDeps = bun.fetchDeps {
inherit (finalAttrs) pname version src;
hash = "...";
};
})
```

`bun.configHook` supports additional flags to `bun install` via `bunInstallFlags`

```nix
{
bun,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "foo";
version = "0-unstable-1980-01-01";
src = ...;
bunInstallFlags = [ "--shamefully-hoist" ];
bunDeps = bun.fetchDeps {
inherit (finalAttrs) bunInstallFlags;
};
})
```


#### Dealing with `sourceRoot` {#javascript-bun-sourceRoot}

If the bun project is in a subdirectory, you can just define `sourceRoot` or `setSourceRoot` for `fetchDeps`.
If `sourceRoot` is different between the parent derivation and `fetchDeps`, you will have to set `bunRoot` to effectively be the same location as it is in `fetchDeps`.

Assuming the following directory structure, we can define `sourceRoot` and `pnpmRoot` as follows:

```
.
├── frontend
│   ├── ...
│   ├── package.json
│   └── bun.lock
└── ...
```

```nix
...
bunDeps = bun.fetchDeps {
...
sourceRoot = "${finalAttrs.src.name}/frontend";
};
# by default the working directory is the extracted source
bunRoot = "frontend";
```

#### Bun workspaces {#javascript-bun-workspaces}

If you need to use a Bun workspace for your project, then set `bunWorkspaces = [ "<workspace project name 1>" "<workspace project name 2>" ]`, etc, in your `bun.fetchDeps` call,
which will make Bun only install dependencies for those workspace packages.

For example:

```nix
...
bunWorkspaces = [ "@astrojs/language-server" ];
bunDeps = bun.fetchDeps {
inherit (finalAttrs) pnpmWorkspaces;
...
}
```

The above would make `bun.fetchDeps` call only install dependencies for the `@astrojs/language-server` workspace package.
Note that you do not need to set `sourceRoot` to make this work.

Usually in such cases, you'd want to use `bun --filter=<bun workspace name> build` to build your project, as `npmHooks.npmBuildHook` probably won't work. A `buildPhase` based on the following example will probably fit most workspace projects:

```nix
buildPhase = ''
runHook preBuild
bun --filter=@astrojs/language-server build
runHook postBuild
'';
```

#### Additional PNPM Commands and settings {#javascript-bun-extraCommands}

If you require setting an additional Bun configuration setting (such as `--dry-run` or similar),
set `preBunInstall` to the right commands to run. For example:

```nix
preBunInstall = ''
--dry-run
'';
pnpmDeps = pnpm.fetchDeps {
inherit (finalAttrs) preBunInstall;
...
};
```

In this example, `preBunInstall` will be run by both `bun.configHook` and by the `bun.fetchDeps` builder.

### Yarn {#javascript-yarn}

Yarn based projects use a `yarn.lock` file instead of a `package-lock.json` to pin dependencies. Nixpkgs provides the Nix function `fetchYarnDeps` which fetches an offline cache suitable for running `yarn install` before building the project. In addition, Nixpkgs provides the hooks:
Expand Down
12 changes: 12 additions & 0 deletions doc/redirects.json
Original file line number Diff line number Diff line change
Expand Up @@ -3055,6 +3055,18 @@
"javascript-pnpm-extraCommands": [
"index.html#javascript-pnpm-extraCommands"
],
"javascript-bun": [
"index.html#javascript-bun"
],
"javascript-bun-sourceRoot": [
"index.html#javascript-bun-sourceRoot"
],
"javascript-bun-workspaces": [
"index.html#javascript-bun-workspaces"
],
"javascript-bun-extraCommands": [
"index.html#javascript-bun-extraCommands"
],
"javascript-yarn": [
"index.html#javascript-yarn"
],
Expand Down
50 changes: 50 additions & 0 deletions pkgs/by-name/bu/bun/fetch-deps/bun-config-hook.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# shellcheck shell=bash

bunConfigHook() {
echo "Executing bunConfigHook"

if [ -n "${bunRoot-}" ]; then
pushd "$bunRoot"
fi

if [ -z "${bunDeps-}" ]; then
echo "Error: 'bunDeps' must be set when using bunConfigHook."
exit 1
fi

echo "Configuring bun store"

export HOME=$(mktemp -d)
export BUN_INSTALL_CACHE_DIR=$(mktemp -d)

cp -Tr "$bunDeps" "$BUN_INSTALL_CACHE_DIR"
chmod -R +w "$BUN_INSTALL_CACHE_DIR"

echo "Installing dependencies"
if [[ -n "$bunWorkspaces" ]]; then
local IFS=" "
for ws in $bunWorkspaces; do
bunInstallFlags+=("--filter=$ws")
done
fi

runHook preBunInstall

bun install \
--offline \
--ignore-scripts \
"${bunInstallFlags[@]}" \
--frozen-lockfile

echo "Patching scripts"

patchShebangs node_modules/{*,.*}

if [ -n "${bunRoot-}" ]; then
popd
fi

echo "Finished bunConfigHook"
}

postConfigureHooks+=(pnpmConfigHook)
100 changes: 100 additions & 0 deletions pkgs/by-name/bu/bun/fetch-deps/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
{
lib,
stdenvNoCC,
callPackage,
jq,
moreutils,
cacert,
makeSetupHook,
bun,
yq,
}:

{
fetchDeps =
{
hash ? "",
pname,
bunWorkspaces ? [ ],
preBunInstall ? "",
bunInstallFlags ? [ ],
...
}@args:
let
args' = builtins.removeAttrs args [
"hash"
"pname"
];
hash' =
if hash != "" then
{ outputHash = hash; }
else
{
outputHash = "";
outputHashAlgo = "sha256";
};

filterFlags = lib.map (package: "--filter=${package}") bunWorkspaces;
in
stdenvNoCC.mkDerivation (
finalAttrs:
(
args'
// {
name = "${pname}-bun-deps";

nativeBuildInputs = [
cacert
jq
moreutils
bun
];

installPhase = ''
runHook preInstall
lockfileVersion="$(jq -r .lockfileVersion bun.lock)"
if [[ ''${lockfileVersion:0:1} -gt ${lib.versions.major bun.version} ]]; then
echo "ERROR: lockfileVersion $lockfileVersion in bun.lock is too new for the provided bun version ${lib.versions.major bun.version}!"
exit 1
fi
export HOME=$(mktemp -d)
export BUN_INSTALL_CACHE_DIR = $out
${preBunInstall}
bun install \
--force \
${lib.escapeShellArgs filterFlags} \
${lib.escapeShellArgs bunInstallFlags} \
--frozen-lockfile
runHook postInstall
'';

fixupPhase = ''
runHook preFixup
# Remove timestamp and sort the json files
# rm -rf $out/v3/tmp
# for f in $(find $out -name "*.json"); do
# jq --sort-keys "del(.. | .checkedAt?)" $f | sponge $f
# done
runHook postFixup
'';

dontConfigure = true;
dontBuild = true;
outputHashMode = "recursive";
}
// hash'
)
);

configHook = makeSetupHook {
name = "bun-config-hook";
propagatedBuildInputs = [ bun ];
} ./bun-config-hook.sh;
}
Loading

0 comments on commit bb19900

Please sign in to comment.