Skip to content

Use bun by default in css:install:* when generating a new app from a template #183

@tagliala

Description

@tagliala

Hello,

This is related to #169, #171, and #179, but I believe it's a distinct problem.

On a freshly generated Rails app created from a template, cssbundling-rails never picks bun as the default bundler, even when bun is installed and available.

Instead, it falls back to yarn because there is no existing bun.lock* file yet.

How to reproduce

  1. Create template.rb:

    gem "cssbundling-rails"
    rails_command "css:install:tailwind"
  2. Generate a new app with that template:

    rails _8.1.1_ new test-bun -m template.rb

    (Assume bun is already installed and on PATH.)

Expected behavior

Because:

  • bun is installed and available, and
  • this is a brand-new app with no existing lockfiles of any kind,

I would expect cssbundling-rails to prefer bun over yarn as the default bundler in this case.

Actual behavior

cssbundling-rails ends up using yarn during installation. The log shows:

$ rails _8.1.1_ new test-bun -m template.rb 

# ...

  Install Tailwind
      create    app/assets/stylesheets/application.tailwind.css
         run    yarn add tailwindcss@latest @tailwindcss/cli@latest from "."
                ^^^^

So even though bun is present, the installer still runs yarn.

Where this comes from in the code

For the installer templates, bun detection and bundler choice are defined in lib/install/helpers.rb:

def using_bun?
tool_exists?('bun') && (File.exist?('bun.lockb') ||
File.exist?('bun.lock'))
end

Because using_bun? requires both:

  1. bun to exist on PATH, and
  2. an existing bun.lockb or bun.lock,

a newly generated app without any bun lockfile will always fall back to yarn, even when bun is available and would be a perfectly valid default.

The build task follows the same pattern via LOCK_FILES and using_tool? in lib/tasks/cssbundling/build.rake.

Workaround (and its problem)

If I force creation of a bun.lock in the template:

gem "cssbundling-rails"
create_file "bun.lock" # <-- force bun detection
rails_command "css:install:tailwind"

then using_bun? returns true, and the installer uses bun. However, that fake bun.lock then causes an error when bun actually tries to read it:

error: Missing lockfile version
    at bun.lock:1:1
InvalidLockfileVersion: failed to parse lockfile: 'bun.lock'

warn: Ignoring lockfile

So this workaround both feels wrong and emits confusing errors for a brand-new app.

Requested change / discussion

Would it be possible to adjust the detection logic so that, for a freshly generated app:

  • If bun is installed and available on PATH, and
  • There are no existing lockfiles (bun.lock*, yarn.lock, pnpm-lock.yaml, package-lock.json),

then cssbundling-rails defaults to bun instead of yarn?

Concretely, that might mean:

  • Allowing using_bun? (or an equivalent decision point) to return true when bun exists and there is no competing lockfile yet, rather than requiring a pre-existing bun.lock*.
  • Or introducing a "no lockfiles yet, prefer bun if available" branch in the installer logic, so new apps can start with bun by default without having to fabricate a lockfile.

I understand the desire to respect existing lockfiles when they’re present, but in the new app from template scenario there aren't any yet, so preferring bun in that case would make it much easier to start with bun-first apps without hacks.

Thanks for considering this!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions