-
-
Notifications
You must be signed in to change notification settings - Fork 19.7k
pkgs/build-support/node: add fetchBunDeps and bun build hooks #414837
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,30 @@ | ||||||
| #!/usr/bin/env bash | ||||||
|
|
||||||
| bunBuildHook() { | ||||||
| runHook preBuild | ||||||
| echo "Executing bunBuildHook" | ||||||
|
|
||||||
| if [ -z "${bunBuildScript-}" ]; then | ||||||
| bunBuildScript="build" | ||||||
| fi | ||||||
|
|
||||||
| if ! type node > /dev/null 2>&1; then | ||||||
| echo "bunConfigHook WARNING: a node interpreter was not added to the build, and is probably required to run 'bun $bunBuildScript'. A common symptom of this is getting 'command not found' errors for Nodejs related tools." | ||||||
| fi | ||||||
|
|
||||||
| # shellcheck disable=SC2154 | ||||||
| # SC2154: bunBuildFlags is referenced but not assigned | ||||||
| # This variable is provided by the Nix build environment, not assigned in this script | ||||||
| if [[ -n "${bunBuildFlags-}" ]]; then | ||||||
| bun run "$bunBuildScript" "${bunBuildFlags[@]}" | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Bun actually doesn't need the run prefix and will look for scripts in your package json if it is not a built in command i.e. is equal to
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No harm in using run, though right? pnpm behaves the same way, and I tend to include it out of habit. Just wondering, is omitting run the preferred style in Bun?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've seen both but I believe omitting it is preferred and run is included so bun can be aliases to node although I may be wrong
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe it's preferable to use |
||||||
| else | ||||||
| bun run "$bunBuildScript" | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| fi | ||||||
|
|
||||||
| echo "finished bunBuildHook" | ||||||
| runHook postBuild | ||||||
| } | ||||||
|
|
||||||
| if [[ -z "${dontBunBuild-}" && -z "${buildPhase-}" ]]; then | ||||||
| buildPhase=bunBuildHook | ||||||
| fi | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| bunConfigHook() { | ||
| echo "Executing bunConfigHook" | ||
|
|
||
| # HOME directory is provided by writableTmpDirAsHomeHook | ||
| # The hook ensures HOME points to a writable location | ||
| if [[ -n "$bunOfflineCache" ]]; then | ||
| offlineCache="$bunOfflineCache" | ||
| fi | ||
| if [[ -z "$offlineCache" ]]; then | ||
| echo bunConfigHook: No bunOfflineCache or offlineCache were defined\! >&2 | ||
| exit 2 | ||
| fi | ||
|
|
||
| local -r cacheLockfile="$offlineCache/bun.lock" | ||
| local -r srcLockfile="$PWD/bun.lock" | ||
|
|
||
| echo "Validating consistency between $srcLockfile and $cacheLockfile" | ||
|
|
||
| if ! @diff@ "$srcLockfile" "$cacheLockfile"; then | ||
| # If the diff failed, first double-check that the file exists, so we can | ||
| # give a friendlier error msg. | ||
| if ! [ -e "$srcLockfile" ]; then | ||
| echo | ||
| echo "ERROR: Missing bun.lock from src. Expected to find it at: $srcLockfile" | ||
| echo "Hint: You can copy a vendored bun.lock file via postPatch." | ||
| echo | ||
|
|
||
| exit 1 | ||
| fi | ||
|
|
||
| if ! [ -e "$cacheLockfile" ]; then | ||
| echo | ||
| echo "ERROR: Missing lockfile from cache. Expected to find it at: $cacheLockfile" | ||
| echo | ||
|
|
||
| exit 1 | ||
| fi | ||
|
|
||
| echo | ||
| echo "ERROR: fetchBunDeps hash is out of date" | ||
| echo | ||
| echo "The bun.lock in src is not the same as the in $offlineCache." | ||
| echo | ||
| echo "To fix the issue:" | ||
| echo "1. Use \`lib.fakeHash\` as the fetchBunDeps hash value" | ||
| echo "2. Build the derivation and wait for it to fail with a hash mismatch" | ||
| echo "3. Copy the 'got: sha256-' value back into the fetchBunDeps hash field" | ||
| echo | ||
|
|
||
| exit 1 | ||
| fi | ||
|
|
||
| # Configure Bun to use the offline cache | ||
| # Bun doesn't have a config command yet, so we use environment variables | ||
| # See: https://bun.sh/docs/runtime/env | ||
| export BUN_INSTALL_CACHE_DIR="$offlineCache" | ||
|
|
||
| # Create and use a temporary directory inside HOME for Bun operations | ||
| local bun_tmp_dir="$HOME/.bun-tmp" | ||
| mkdir -p "$bun_tmp_dir" | ||
| export BUN_TMPDIR="$bun_tmp_dir" | ||
|
|
||
| # Create additional directories Bun might need | ||
| mkdir -p "$HOME/.bun/install/cache" | ||
|
|
||
| # Configure additional Bun directories | ||
| export BUN_CONFIG_DIR="$HOME/.bun" | ||
|
|
||
| echo "Using Bun temp directory: $bun_tmp_dir" | ||
|
|
||
| # Fix up the lockfile | ||
| fixup-bun-lock bun.lock | ||
|
|
||
| # Create a specific cache directory | ||
| local bun_cache_dir="$HOME/.bun-cache" | ||
| mkdir -p "$bun_cache_dir" | ||
|
|
||
| # Create test files in each directory to verify they're writable | ||
| echo "test" > "$bun_tmp_dir/test-tmp.txt" | ||
| echo "test" > "$bun_cache_dir/test-cache.txt" | ||
| echo "test" > "$HOME/.bun/test-bun.txt" | ||
|
|
||
| echo "DEBUG: Created test files to verify directories are writable" | ||
|
|
||
| # Create a bunfig.toml file to explicitly configure Bun | ||
| cat > "$PWD/bunfig.toml" << EOF | ||
| [install] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as I am aware, unfortunately bun currently can't install from an offline cache and properly guarantee that nothing is fetched without a workaround, you can opt to install it manually and create See here |
||
| # Set cache directory to a writable location | ||
| cache = "$bun_cache_dir" | ||
| # Configure global directories | ||
| globalDir = "$HOME/.bun/global" | ||
| globalBinDir = "$HOME/.bun/bin" | ||
| # Don't update lockfile | ||
| frozenLockfile = true | ||
| # Don't use default cache | ||
| dry = false | ||
|
|
||
| # Make sure Bun uses our temp directory | ||
| tmpdir = "$bun_tmp_dir" | ||
|
|
||
| [install.lockfile] | ||
| # Don't save lockfile changes | ||
| save = false | ||
| EOF | ||
|
|
||
| echo "Created bunfig.toml:" | ||
| cat "$PWD/bunfig.toml" | ||
|
|
||
| # Debug: Check Bun's configuration and directories | ||
| echo "DEBUG: Bun version: $(bun --version)" | ||
| echo "DEBUG: Bun's cache directory: $(bun pm cache)" | ||
| echo "DEBUG: Checking if bun recognizes our config:" | ||
| bun --config="$PWD/bunfig.toml" pm cache || echo "Failed to use config" | ||
|
|
||
| echo "DEBUG: Current directory contents:" | ||
| ls -la "$PWD" | ||
|
|
||
| echo "DEBUG: BUN_TMPDIR directory:" | ||
| ls -la "$bun_tmp_dir" | ||
|
|
||
| # Install dependencies from the offline cache | ||
| # Using the bunfig.toml for configuration | ||
| bun install \ | ||
| --frozen-lockfile \ | ||
| --no-progress \ | ||
| --no-save \ | ||
| --offline \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bun does not have a
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey, thanks for the detailed feedback, i built this to learn a bit, but now i'm fairly invested, so i appreciate it The
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I ended up doing for mine was a manual implementation of |
||
| --no-cache \ | ||
| --cache-dir="$bun_cache_dir" \ | ||
| --backend=copyfile \ | ||
| --config="$PWD/bunfig.toml" \ | ||
| --verbose | ||
|
|
||
| # TODO: Check if this is really needed | ||
| patchShebangs node_modules | ||
|
|
||
| echo "finished bunConfigHook" | ||
| } | ||
|
|
||
| if [[ -z "${dontBunInstallDeps-}" ]]; then | ||
| postConfigureHooks+=(bunConfigHook) | ||
| fi | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| #!/usr/bin/env bash | ||
| # shellcheck shell=bash | ||
|
|
||
| bunInstallHook() { | ||
| echo "Executing bunInstallHook" | ||
|
|
||
| runHook preInstall | ||
|
|
||
| # shellcheck disable=SC2154 | ||
| # SC2154: $out is referenced but not assigned | ||
| # $out is a standard Nix environment variable representing the output path for the derivation | ||
| local -r packageOut="$out/lib/node_modules/$(@jq@ --raw-output '.name' ./package.json)" | ||
| mkdir -p "$packageOut" | ||
|
|
||
| local -ar bunArgs=( | ||
| --no-progress | ||
| --no-save | ||
| --offline | ||
| ) | ||
|
|
||
| local tmpDir | ||
| tmpDir="$(mktemp -d)" | ||
| local -r tmpDir | ||
|
|
||
| # Pack the package (equivalent to yarn pack in Bun) | ||
| bun pack \ | ||
| --out-file "$tmpDir/bun-pack.tgz" \ | ||
| "${bunArgs[@]}" | ||
|
|
||
| tar xzf "$tmpDir/bun-pack.tgz" \ | ||
| -C "$packageOut" \ | ||
| --strip-components 1 \ | ||
| package/ | ||
|
|
||
| nodejsInstallExecutables ./package.json | ||
|
|
||
| nodejsInstallManuals ./package.json | ||
|
|
||
| local -r nodeModulesPath="$packageOut/node_modules" | ||
|
|
||
| if [ ! -d "$nodeModulesPath" ]; then | ||
| if [ -z "${bunKeepDevDeps-}" ]; then | ||
| # Install production dependencies only | ||
| if ! bun install \ | ||
| --frozen-lockfile \ | ||
| --production \ | ||
| "${bunArgs[@]}" | ||
| then | ||
| echo | ||
| echo | ||
| echo "ERROR: bun production install step failed" | ||
| echo | ||
| echo "If bun tried to download additional dependencies above, try setting \`bunKeepDevDeps = true\`." | ||
| echo | ||
|
|
||
| exit 1 | ||
| fi | ||
| fi | ||
|
|
||
| find node_modules -maxdepth 1 -type d -empty -delete | ||
|
|
||
| cp -r node_modules "$nodeModulesPath" | ||
| fi | ||
|
|
||
| runHook postInstall | ||
|
|
||
| echo "Finished bunInstallHook" | ||
| } | ||
|
|
||
| if [ -z "${dontBunInstall-}" ] && [ -z "${installPhase-}" ]; then | ||
| installPhase=bunInstallHook | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| const path = require('path') | ||
|
|
||
| // This has to match the logic in pkgs/development/tools/yarn2nix-moretea/yarn2nix/lib/urlToName.js | ||
| // so that fixup_bun_lock produces the same paths | ||
| const urlToName = url => { | ||
| const isCodeloadGitTarballUrl = url.startsWith('https://codeload.github.com/') && url.includes('/tar.gz/') | ||
|
|
||
| if (url.startsWith('file:')) { | ||
| return url | ||
| } else if (url.startsWith('git+') || isCodeloadGitTarballUrl) { | ||
| return path.basename(url) | ||
| } else { | ||
| return url | ||
| .replace(/https:\/\/(.)*(.com)\//g, '') // prevents having long directory names | ||
| .replace(/[@/%:-]/g, '_') // replace @ and : and - and % characters with underscore | ||
| } | ||
| } | ||
|
|
||
| // JSONC parsing - strip comments from JSON string | ||
| const stripJsonComments = (jsonString) => { | ||
| // Remove single-line comments (//) | ||
| let result = jsonString.replace(/\/\/.*$/gm, ''); | ||
|
|
||
| // Remove multi-line comments (/* ... */) | ||
| result = result.replace(/\/\*[\s\S]*?\*\//g, ''); | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| module.exports = { urlToName, stripJsonComments }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bun has a
--bunflag which can be used to provide an alias to bun for node in these cases. Consider mentioning it in this error message