Project

railpack

0.0
The project is in a healthy, maintained state
Choose your JavaScript bundler - Bun, esbuild, Rollup, Webpack. Unified Rails integration with hot module replacement and production builds.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 5.0

Runtime

 Project Readme

Railpack 🎒

Multi-bundler asset pipeline for Rails - Choose your bundler, unified Rails integration.

Installation

  1. Add to Gemfile: gem "railpack"
  2. Run: bin/rails railpack:install # Generator + initial dependencies
  3. Edit config/railpack.yml to configure/switch bundlers (Railpack creates config/railpack.yml with sensible defaults for your Rails app.)
  4. Commands:
    • bin/rails railpack:install # Dependencies (auto on deploy)
    • bin/rails railpack:build # Assets
    • bin/rails railpack:watch # Dev live reload
    • bin/rails railpack:reload # Reload config without restart

Features

  • 🚀 Multiple Bundlers: Bun, esbuild, Rollup, Webpack support
  • 🔧 Unified API: Same interface regardless of bundler
  • 🎯 Rails Integration: Seamless asset pipeline integration
  • âš¡ Hot Module Replacement: Development server with live reload
  • 🎣 Event Hooks: Build lifecycle callbacks
  • 📦 Production Ready: Optimized builds for all bundlers

Configuration

Create config/railpack.yml:

# Choose your bundler
bundler: bun  # or 'rollup', 'webpack', 'esbuild'

# Global defaults
default:
  target: browser
  format: esm
  minify: false
  sourcemap: false
  entrypoint: "./app/javascript/application.js"
  outdir: "app/assets/builds"
  analyze_bundle: false  # Enable for gzip size reporting

# Bundler-specific config
bun:
  target: browser
  format: esm

# Environment overrides
development:
  sourcemap: true
  analyze_bundle: true  # Show gzip sizes in dev

production:
  minify: true
  analyze_bundle: true  # Production bundle analysis

Advanced Configuration

Per-Bundler Command Overrides

Override default commands for specific bundlers:

bundlers:
  esbuild:
    commands:
      build: "esbuild-custom --special-flag"
      watch: "esbuild-custom --watch --dev-mode"
      version: "esbuild-custom --version-check"
  bun:
    commands:
      build: "bunx custom-build"
  rollup:
    commands:
      build: "rollup --config custom-config.js"
  webpack:
    commands:
      build: "webpack --config custom-webpack.config.js"

Watch Flags Configuration

Configure watch-specific flags (different from build flags):

esbuild:
  target: browser
  format: esm
  watch_flags: ["--watch", "--serve=3000"]  # Custom watch flags

rollup:
  format: esm
  sourcemap: true
  watch_flags: ["--watch"]

webpack:
  mode: production
  target: web
  watch_flags: ["--watch"]

Dynamic Bundler Switching

Switch bundlers per environment or dynamically:

# Switch bundlers per environment
development:
  bundler: bun  # Fast for development

production:
  bundler: esbuild  # Speed for production

# Or use different bundlers for different tasks
bundlers:
  esbuild:
    commands:
      build: "esbuild --production"
  webpack:
    commands:
      build: "webpack --config webpack.prod.js"

Custom Entry Points and Outputs

Configure multiple entry points and custom outputs:

default:
  entrypoints: ["./app/javascript/application.js", "./app/javascript/admin.js"]
  outdir: "app/assets/builds"

# Or single entrypoint
default:
  entrypoint: "./app/javascript/application.js"
  outdir: "app/assets/builds"

Usage

Basic Commands

# Build for production
rails railpack:build

# Watch and rebuild during development
rails railpack:watch

# Reload configuration without server restart
rails railpack:reload

# Install dependencies
rails railpack:install

# Check current bundler
rails railpack:bundler

Programmatic API

# Build assets
Railpack.build!

# Watch for changes
Railpack.watch

# Install packages
Railpack.install!

# Add dependencies
Railpack.add('lodash', 'axios')

Rails Integration

Railpack automatically integrates with Rails asset pipeline:

# config/initializers/railpack.rb
require 'railpack'

# Override config at runtime
Railpack.config.sourcemap = true

# Setup logging
Railpack.logger = Rails.logger

# Build event hooks
Railpack.on_build_complete do |result|
  Rails.logger.info "Build completed: #{result[:success]}"
end

Advanced Usage

Bundle Analysis with Gzip

Enable analyze_bundle: true to see both uncompressed and gzipped bundle sizes:

# config/railpack.yml
default:
  analyze_bundle: true

Output example:

✅ Build completed successfully in 45.23ms (1.23 MB (0.45 MB gzipped))

Build Hooks with Payload Details

Hook payloads provide detailed information about build results:

# config/initializers/railpack.rb
Railpack.on_build_complete do |payload|
  if payload[:success]
    # Success payload: { success: true, config: {...}, duration: 45.23, bundle_size: "1.23 MB" }
    Rails.logger.info "Build succeeded in #{payload[:duration]}ms - #{payload[:bundle_size]}"
  else
    # Error payload: { success: false, error: #<Error>, config: {...}, duration: 12.34 }
    Rails.logger.error "Build failed after #{payload[:duration]}ms: #{payload[:error].message}"
  end
end

Railpack.on_build_start do |config|
  # Config hash contains all current settings
  Rails.logger.info "Starting #{config['bundler']} build for #{Rails.env}"
end

Manifest Generation

Railpack automatically detects your asset pipeline and generates appropriate manifests:

# For Propshaft (Rails 7+ default)
# Generates: app/assets/builds/.manifest.json
Railpack::Manifest::Propshaft.generate(config)

# For Sprockets (Rails < 7)
# Generates: app/assets/builds/.sprockets-manifest-*.json
Railpack::Manifest::Sprockets.generate(config)

The manifest generation is handled automatically after each build, but you can trigger it manually if needed.

Supported Bundlers

Bun (Default)

  • Fast builds - Lightning-quick bundling
  • All-in-one - Runtime, bundler, package manager
  • Great DX - Excellent development experience

Rollup

  • Tree shaking - Optimal bundle sizes
  • Plugin ecosystem - Extensive customization
  • ESM focus - Modern module system

Webpack

  • Enterprise - Battle-tested in production
  • Feature-rich - Extensive plugin ecosystem
  • Legacy support - Handles all module types

esbuild

  • Speed demon - 10-100x faster than alternatives
  • Simple API - Minimal configuration
  • Modern features - ESM, minification, sourcemaps

Switching Bundlers

Change the bundler setting in config/railpack.yml:

bundler: esbuild  # Switch to esbuild for speed

Or use esbuild:

bundler: esbuild

esbuild:
  platform: browser
  target: es2015
  minify: true

Railpack handles the rest - same API, different bundler under the hood.

Development

Adding a New Bundler

  1. Create bundler class:
# lib/railpack/bundlers/my_bundler.rb
class Railpack::MyBundler < Railpack::Bundler
  def commands
    { build: "my-build", watch: "my-watch" }
  end
  
  def build!(args = [])
    execute!([commands[:build], *args])
  end
end
  1. Register in Manager:
BUNDLERS = {
  'bun' => BunBundler,
  'my' => MyBundler  # Add here
}

Contributing

  1. Fork the repo
  2. Add your bundler implementation
  3. Update documentation
  4. Submit a PR

Changelog

See CHANGELOG.md for version history.

License

MIT License - see LICENSE.txt

Credits

Built by 21tycoons LLC for the Rails community.