bundlebun bundles Bun, a fast JavaScript runtime, package manager, and builder, with your Ruby and Rails applications. No need to use Docker, devcontainers, curl ... | sh
, or brew
.
Starting with your Ruby or Rails project, no Bun or anything like that required:
bundle add bundlebun
rake bun:install
and then:
> bin/bun ...
Bun is a fast JavaScript runtime, package manager, bundler, and test runner. (1.1.38+bf2f153f5)
Usage: bun <command> [...flags] [...args]
...
Modern frontend setup is needlessly complex and may involve a lot of maintenance. Developers need at the very least a JavaScript runtime (typically, Node.js), a package manager (could be npm, yarn, or pnpm), and a build tool (Vite, Webpack, esbuild, Parcel—dozens of them).
- One way forward is to dockerize development environments, creating unnecessary headaches for the development team—both frontend and backend engineers (especially if the team is not that large and the project is not that complex).
- Another approach is to declare front-ops bankruptcy and pursue the "no-build" route.
What if we could simplify this? Bun is a JavaScript runtime, optimized for speed and developer experience. Bun is also a fast JavaScript package manager. Bun is also a build tool. Bun is also distributed as a single executable file.
However, Bun still requires some installation, and we need to make sure everyone on the team is using the same version.
So, how about we just pack it into a Ruby gem as a binary and allow developers to stay updated? Then, we'll be ready every time a new Bun version is out—or the user can freeze their desired version within their Ruby project. There are no setups, large READMEs with instructions, and no enforcing the Docker workflow.
Enter bundlebun. With a fast JavaScript runtime and a package manager included, you can even skip the build tool and use Bun itself.
bundlebun gem releases include a binary distribution of Bun for each supported Bun platform (macOS, Linux, Windows) and architecture.
First, add it to your Gemfile
:
gem "bundlebun"
and:
bundle install
(or just):
bundle add bundlebun
If you're seeing a message like Could not find gems matching 'bundlebun' valid for all resolution platforms (aarch64-linux, aarch64-linux-gnu <...> )
, this may be a known issue with Bundler/Gemfile.lock
which you can fix. Open Gemfile.lock
in your text editor, find a section called PLATFORMS
, and alter a list of platforms you need to support. This can be a good default for most if you're targeting Linux and macOS (for Windows, also leave entries with x64_mingw
):
(rest of the file here)
PLATFORMS
aarch64-linux
arm64-darwin
x86_64-darwin
x86_64-linux
(rest of the file here)
... and try bundle install
again.
Next, run:
rake bun:install
The task will install a binstub (bin/bun
) that you can use to run Bun commands; try running bin/bun
or bin/bun --version
.
You should use bin/bun
in your scripts, including your local runners like Procfile.dev
or Procfile
, and package.json
—if you had a call to node
or bun
in the scripts
section there.
Next, the Rake task will try to detect the integrations we need to install based on the classes and modules Rake can see in your project. We'll continue with integrations.
rake bun:install
will detect already-loaded gems and run the corresponding installation tasks.
Alternatively, you can ensure an integration is loaded and the necessary modules are patched by calling methods that look like Bundlebun::Integration::IntegrationName.bun!
: more on that below.
cssbundling and jsbundling are Rails gems that support the traditional CSS and JS building pipeline for Ruby on Rails.
Be sure to check both gems for documentation on bootstrapping your frontend build pipeline (as bundlebun supports them) instead of duplicating approaches. cssbundling, for instance, includes an excellent sample build configuration for Bun.
To quote their READMEs, try this for cssbundling:
bundle add cssbundling-rails
bin/rails css:install:[tailwind|bootstrap|bulma|postcss|sass]
bin/rails css:build
and this jsbundling:
bundle add jsbundling-rails
bin/rails javascript:install:bun
To install the bundlebun integration, run
rake bun:install:rails
The task makes sure a bin/bun
binstub exists and installs an initializer/task of sorts to ensure both build-related gems use our bundled version of Bun.
Alternatively, you can call the following in one of your project's rakefiles:
Bundlebun::Integrations::Cssbundling.bun!
Bundlebun::Integrations::Jsbundling.bun!
vite-ruby and vite-rails are gems that make Ruby and Rails integration with Vite, a great JavaScript build tool and platform, seamless and easy.
The bundlebun integration would be installed automatically, or you can run:
rake bun:install:vite
That will make sure you have a bin/bun
binstub.
Next, we'll install a custom bin/vite
binstub (otherwise, ruby-vite won't be able to sense bundlebun presence); the original file, if present, would be backed up to bin/vite-backup
.
Finally, we'll put an initializer that forces vite-ruby to use bundlebun. Alternatively, you can call this yourself:
Bundlebun::Integrations::ViteRuby.bun!
ExecJS runs JavaScript code straight from Ruby. To do so, it supports a bunch of runtimes it can launch—and get a result. The Bun runtime already exists for ExecJS; we just need to ensure it uses the bundled one.
The bundlebun integration can be installed automatically, or you can run:
rake bun:install:execjs
This will create an initializer to redefine the Bun runtime for ExecJS and force its usage to be default. Alternatively, you can call:
Bundlebun::Integrations::ExecJS.bun!
bundlebun is designed to be used with Bundler: installed in specific projects, and launched via bin/bun
or integrations.
If you install the gem globally, you won't see the bun
executable as a wrapper for a Ruby-bundled Bun runtime; instead, it would be called bundlebun
.
This naming discrepency is to avoid possible conflicts in your $PATH
if you have an independent Bun runtime installed: if the directory with Ruby gem-generated binstubs is in your $PATH
before the directory with your Bun runtime, running bun
will launch the bundlebun's version, causing a lot of confusion. And that is why bundlebun is not greedy with the bun
executable name. If you wish to run Bun runtime globally using this gem, a simple symlink or a wrapper script will do, but the gem won't act destructively.
The easiest way to interact with bundled Bun is via the binstub at bin/bun
; it will launch the bundled version of Bun with the arguments provided:
> bin/bun
Bun is a fast JavaScript runtime, package manager, bundler, and test runner. (1.1.38+bf2f153f5)
Usage: bun <command> [...flags] [...args]
...
Note that with this (or any other option to run Bun), bundlebun will return the error code 127
if the executable is not found.
Alternatively, you can use a Rake task. The syntax is far from perfect, but that's a limitation of Rake. You need to add quotes around the parameters and put them into square brackets. If you cannot install the binstub, though, might be your option.
rake bun[command] # Run bundled Bun with parameters
> rake "bun[outdated]"
bun outdated v1.1.38 (bf2f153f)
...
Check bundlebun API: https://rubydoc.info/gems/bundlebun.
The easiest way to call Bun from Ruby would be Bundlebun.call
:
Bundlebun.call("outdated") # => `bun outdated`
Bundlebun.call(["add", "postcss"]) # => `bun add postcss`
Check out the API documentation on Bundlebun::Runner
for helper methods. Some of the most useful ones:
-
Bundlebun::Runner.binary_path
: returns the full path to the bundled Bun library. -
Bundlebun::Runner.binary_path_exist?
: checks if that binary even exists. -
Bundlebun::Runner.binstub_exist?
: checks if the binstub exists. -
Bundlebun::Runner.binstub_or_binary_path
: returns the optimal way to run bundled Bun: a path to binstub or a full path to the binary.
bundlebun uses the #{bundlebun.version}.#{bun.version}
versioning scheme. Meaning: gem bundlebun version 0.1.0.1.1.38
is a distribution that includes a gem with its own code version 0.1.0
and a Bun runtime with version 1.1.38
.
bundlebun is designed to automatically push new gem versions when there is a new Bun release. That said, you can lock the exact version number in your Gemfile
, or leave the version unspecified and update it as you wish.
To uninstall, remove the gem:
bundle remove bundlebun
Or remove it from your Gemfile
and run bundler.
Next, remove the integrations you have in place:
bin/bun
- Delete
bin/vite
if exists or restore it frombin/vite-backup
- Delete
tasks/bundlebun.rake
if exists - Delete
config/initializers/bundlebun-vite.rb
if exists - Delete
config/initializers/bundlebun-execjs.rb
if exists - Search for
bin/bun
mentions in your code and configs - Search for
Bundlebun
mentions in your code.
bundlebun gem downloads contain binary distributions of Bun available directly from https://github.com/oven-sh/bun/releases.
Bun was created by Jarred Sumner @jarred-sumner & co. and is distributed under MIT. Check their LICENSE.
Big thanks to Jason Meller @terracatta for his work on integrating Bun into the Ruby on Rails ecosystem: jsbundling-rails support, cssbundling-rails support with a proper build configuration, turbo-rails and stimulus-rails support, ExecJS support. See this Pull Request.
Make sure you have up-to-date Ruby. Run bin/setup
to install the nesessary gems, install lefthook and run rake bundlebun:download
to fetch a local version of Bun for tests.
rake rspec
to check if all tests pass.
Open an issue or a PR.
The gem is available as open source under the terms of the MIT License.
See LICENSE.txt.