Skip to content

build: Add a flake.nix dev environment, and switch to bun for package management#4020

Open
matthawkins90 wants to merge 6 commits intodecred:masterfrom
matthawkins90:switch_to_bun
Open

build: Add a flake.nix dev environment, and switch to bun for package management#4020
matthawkins90 wants to merge 6 commits intodecred:masterfrom
matthawkins90:switch_to_bun

Conversation

@matthawkins90
Copy link
Contributor

Migrate from Yarn to Bun

This PR migrates the project's package manager from Yarn to Bun for faster dependency installation and script execution.

I've been noticing that decrediton's dependencies are starting to look a little long in the tooth, so I want to start bumping old/deprecated dependencies, but I also don't want to spend ages fiddling with the dev environment and waiting for dependencies to reload. This PR should make it a whole lot less frustrating.

Summary

Nix Flake Development Environment

Added a Nix flake for a reproducible env using direnv:

  • flake.nix: Dev shell with bun, nodejs_20, yarn (fallback for older hardware), python311, and cmake
  • LD_LIBRARY_PATH: Configures native library paths for Electron (GTK, X11, mesa, etc.)
  • .envrc: direnv integration

Why both Bun and Node.js? I couldn't fully get rid of Node.js. While Bun is the new package manager and script runner, nodejs_20 is still required because electron-builder shells out to Node.js during the build process and doesn't support Bun's runtime.

Package.json Script Changes

Updated scripts to use bun run instead of npm run or yarn:

  • build: bun run build-trezor && bun run build-preload && bun run build-main && bun run build-renderer
  • rebuild-dexc: cd modules/dex && bun run install
  • rebuild-pi-ui: Builds git-based pi-ui dependency and removes duplicate React instances
  • rebuild-sbffi: Compiles native FFI module via cmake-js (This was required to run the dex and also to start a hot dev build)
  • postinstall: Updated to use bun run rebuild-dexc && bun run rebuild-pi-ui
  • dev / dev-nosandbox: bun run hot-server -- --start-hot[-nosandbox]
  • package-*: All packaging scripts now use bun run build

The postinstall script also includes unset npm_execpath npm_config_user_agent to ensure electron-builder install-app-deps uses the system Node.js rather than attempting to use Bun. I got errors with pi-ui until I did this.

Test Setup Changes

Updated test/setup.js to polyfill TextEncoder and TextDecoder:

import { TextEncoder, TextDecoder } from "util";
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;

Why? The trezor-connect library (v8.2.12-extended) uses TextEncoder/TextDecoder internally. While these are available globally in browsers and modern Node.js, the Jest test environment (jsdom) doesn't provide them. I got "TextEncoder is not defined" errors during tests until I added these.

Testing

After applying these changes:

# Enter the nix dev shell (if using direnv, this happens automatically)
nix develop

# Install dependencies
bun install

# Run tests
bun run test

# Start development server
bun run dev

# Build for production
bun run build

Note on flaky tests: Running bun run test often results in failing tests due to timing-related flakiness when tests run in parallel. If you encounter failures, running the tests sequentially will typically get them all to pass:

bun run test -- --runInBand

Testing these changes on various machines:

I tested this on a modern NixOS installation, as well as NixOS on older (2010) hardware which doesn't work with bun. Bun fails with "illegal hardware instruction", so I added yarn again to the flake.nix, got it to work, and then added a section to the README.md.

New Lock Files

Unfortunately, in order to allow building from source on older hardware, we have to keep yarn. This means we have both yarn.lock and bun.lock. I tried several methods to potentially keep these in sync. Bun has bun install --yarn, which will generate a yarn.lock file and keep it in sync with bun.lock being the source of truth. However, this won't work, because unfortunately the github commit link to pi-ui that gets generated in the yarn.lock doesn't actually work.

So basically, in an ideal world we wouldn't have two lockfiles that could get out of sync, and we would probably want to ONLY use bun.lock. But I'm trying to maintain some backwards-compatibility with older hardware that can't use bun, and so this was the best I could come up with.

It's possible we could add bun.lock to the gitignore so that people regenerate a new bun.lock based on the yarn.lock every time, but I'm open to suggestions.

@matthawkins90 matthawkins90 force-pushed the switch_to_bun branch 2 times, most recently from 5ea97dc to 308d9c3 Compare January 23, 2026 01:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant