Skip to content

[Rails 6→7 + jsbundling/esbuild] Duplicate 'extend' identifier breaks filtering/sorting #3729

@rosswgray

Description

@rosswgray

Bug Report: Duplicate 'extend' identifier in Rails Admin JavaScript with Rails 7 + jsbundling-rails (esbuild)

Environment

  • Rails: 7.1
  • Rails Admin: 3.3.0 (also tested with 3.2.x - same issue)
  • Ruby: 3.1.2
  • JavaScript Bundler: jsbundling-rails with esbuild
  • Asset Pipeline: Sprockets 4.2.1
  • Other relevant gems: turbo-rails, stimulus_reflex, tailwindcss-rails

Description

Rails Admin filtering and sorting features are completely non-functional due to a JavaScript syntax error. The duplicate identifier error occurs in Rails Admin's own compiled JavaScript file, preventing all JavaScript-dependent features from working.

Error Message

Uncaught SyntaxError: Identifier 'extend' has already been declared
at application-61ed2d5f1ba7beeb653ee0e0858a724970b2294197a7109d85a35dae7ee7426d.js:45348:7

The error occurs in the compiled Rails Admin JavaScript file served by Sprockets:

http://localhost:3000/assets/rails_admin/application-61ed2d5f1ba7beeb653ee0e0858a724970b2294197a7109d85a35dae7ee7426d.js

CRITICAL FINDING: Only Affects Rails 6→7 Upgrades

This bug does NOT occur in fresh Rails 7 apps. The duplicate extend declaration only appears in applications that were upgraded from Rails 6 to Rails 7.

This significantly narrows down the root cause to migration artifacts or legacy configurations from Rails 6.

Steps to Reproduce

IMPORTANT: This requires a Rails 6 app upgraded to Rails 7. Fresh Rails 7 apps do NOT exhibit this issue.

  1. Start with a Rails 6.x app using jsbundling-rails (esbuild)
  2. Upgrade the app to Rails 7.1
  3. Have rails_admin gem in Gemfile
  4. Run bundle install
  5. Configure config.asset_source = :sprockets in config/initializers/rails_admin.rb
  6. Start Rails server
  7. Navigate to /admin
  8. Open browser DevTools Console
  9. Try to use filter or sort features

Contrast: Creating a fresh Rails 7.1 app and installing Rails Admin does NOT produce this error.

Expected Behavior

  • Rails Admin dashboard should load without JavaScript errors
  • Filter button should open filter panel
  • Column headers should be sortable
  • All JavaScript-dependent features should work

Actual Behavior

  • JavaScript console shows: Uncaught SyntaxError: Identifier 'extend' has already been declared
  • Filter buttons are visible but non-functional (clicking does nothing)
  • Sort functionality is broken
  • All JavaScript features fail silently

Investigation Findings

1. Only Rails Admin JS loads (verified via View Source)

The HTML source shows only Rails Admin's JavaScript loading:

<script src="http://localhost:3000/assets/rails_admin/application-[hash].js" defer="defer" data-turbo-track="reload"></script>

The main application JavaScript bundle from esbuild does NOT load on admin pages.

2. Duplicate is INSIDE Rails Admin's compiled file

The duplicate extend identifier is within the Rails Admin JavaScript file itself, not caused by multiple files loading or conflicts with application JavaScript.

3. Consistent file hash across recompilations

Despite clearing all caches and forcing recompilation, the same file hash appears, suggesting:

  • The compilation process consistently produces the duplicate
  • OR the source files contain duplicates that get compiled

4. No external conflicts

  • Rails Admin is only in Gemfile (not in package.json)
  • No jQuery or Bootstrap conflicts
  • Application JavaScript successfully isolated from admin pages

Solutions Attempted (All Failed)

  1. asset_source configurations: Tried :sprockets, :webpack, :importmap, and auto-detection
  2. Custom layout override: Created custom Rails Admin layout to prevent application.js loading
  3. Asset manifest modifications: Added/removed explicit Rails Admin asset links
  4. Cache clearing: Deleted public/assets/, tmp/cache/, forced asset recompilation
  5. Version downgrade: Tested with Rails Admin 3.2.x, 3.1.x
  6. Parent controller override: Set config.parent_controller = 'ActionController::Base'

Configuration Files

config/initializers/rails_admin.rb

RailsAdmin.config do |config|
  config.asset_source = :sprockets

  config.authenticate_with do
    warden.authenticate! scope: :user
  end

  config.authorize_with do
    if !current_user || !current_user.superadmin?
      redirect_to(main_app.root_path, alert: "You are not permitted to view this page")
    end
  end

  # ... model configurations
end

Gemfile (relevant parts)

gem 'rails', '7.1'
gem 'jsbundling-rails'
gem 'sassc-rails'
gem 'rails_admin'
gem 'turbo-rails'

esbuild.config.mjs

const entryPoints = ["application.js"]

const config = {
  absWorkingDir: path.join(process.cwd(), "app/javascript"),
  bundle: true,
  entryPoints: entryPoints,
  minify: process.env.RAILS_ENV == "production",
  outdir: path.join(process.cwd(), "app/assets/builds"),
  plugins: [rails()],
  sourcemap: process.env.RAILS_ENV != "production"
}

Potential Root Cause

Since this only affects Rails 6→7 upgrades and NOT fresh Rails 7 apps, the root cause is likely related to migration artifacts or legacy configurations from Rails 6.

Likely Causes (Rails 6→7 Specific):

  1. Legacy Asset Pipeline Configuration

    • Rails 6 apps often have Sprockets-specific settings in config/application.rb and config/initializers/assets.rb
    • These configurations may conflict with Rails 7's updated asset handling
    • Fresh Rails 7 apps have cleaner, modern asset configurations
  2. Dual Asset Pipeline (Sprockets + esbuild)

    • Upgraded apps may have both Rails 6-style Sprockets config AND Rails 7-style esbuild
    • This dual configuration might cause Rails Admin assets to be processed incorrectly
    • Fresh Rails 7 apps typically use only one asset approach
  3. Initializer Load Order Changes

    • Rails 6→7 upgrades often accumulate additional initializers (like custom Rails Admin fixes)
    • The presence of extra initializers can change initialization order
    • This may cause Rails Admin to be extended or initialized multiple times
  4. Framework Defaults Files

    • Upgraded apps have config/initializers/new_framework_defaults_7_1.rb with commented-out settings
    • These gradual migration settings might interact poorly with Rails Admin asset compilation
    • Fresh Rails 7 apps don't have these migration files
  5. Legacy node_modules Asset Paths

    • Rails 6 apps often added node_modules to config.assets.paths
    • This legacy configuration might cause asset resolution conflicts in Rails 7

Evidence from Upgraded App:

  • Presence of config/initializers/new_framework_defaults_7_1.rb (only exists in upgraded apps)
  • Custom config/initializers/rails_admin_asset_fix.rb (workaround created during migration)
  • Mixed asset configuration with both Sprockets and esbuild settings
  • Legacy asset path configurations (node_modules in asset paths)

Files to Investigate in Upgraded Apps:

If you're debugging this issue, check these files for Rails 6 legacy configurations:

  • config/application.rb - Look for config.assets.* settings
  • config/initializers/assets.rb - Check for node_modules in asset paths or custom precompile settings
  • config/initializers/new_framework_defaults_*.rb - Migration transition files
  • Any custom config/initializers/rails_admin_*.rb files created as workarounds
  • config/environments/development.rb - Asset compilation settings

Impact

This completely breaks Rails Admin's JavaScript functionality in Rails 6→7 upgraded apps using jsbundling-rails with esbuild, making the gem unusable for its primary purpose (admin CRUD operations with filtering/sorting).

Scope: This affects teams upgrading from Rails 6 to Rails 7, which is a common migration path. Fresh Rails 7 apps are unaffected.

Workaround

None found. Users are forced to either:

  1. Switch to a different admin panel (Avo, Motor Admin, ActiveAdmin)
  2. Deactivate Trix/ActionText (and thus lose rich_text support)

Request

Could the Rails Admin team:

  1. Test with a Rails 6→7 upgraded app (not a fresh Rails 7 app, as fresh apps don't exhibit this bug)
  2. Investigate how legacy asset configurations from Rails 6 might cause duplicate extend declarations during Sprockets compilation
  3. Provide guidance on which Rails 6 configurations should be removed/updated for Rails Admin to work correctly in Rails 7
  4. Consider adding a "Upgrading from Rails 6" section to documentation addressing this issue
  5. Potentially add a diagnostic that detects problematic Rails 6 legacy configurations and warns users

Additional Context

We spent approximately 4+ hours investigating this issue and trying various solutions. Every approach failed to resolve the duplicate identifier error.

The issue appears to be in how Sprockets compiles Rails Admin's JavaScript when used in a Rails 6→7 upgraded app with jsbundling-rails, likely due to conflicting asset pipeline configurations left over from the Rails 6 era.

This is blocking our Rails 7 upgrade and we're currently evaluating alternative admin panels (Avo, Motor Admin) as workarounds.

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