rails: Rails 7.1 breaks assets compilation (Terser::Error: "extend" is redeclared)
Steps to reproduce
Rails 7.1 breaks assets compilation (Terser::Error: “extend” is redeclared)
I updated Rails 7.0.8 to Rails 7.1.1.
I use the terser 1.1.18 gem.
# config/environments/production.rb
config.assets.js_compressor = :terser
When I deploy the Rails app to Heroku I’m getting the following error for the assets compilation step.
https://eslint.org/docs/latest/rules/no-redeclare
...
remote: rake aborted!
remote: Terser::Error: "extend" is redeclared
remote: --
remote: 44142 }
remote: 44143
remote: 44144 };
remote: 44145
remote: 44146 const ZERO_WIDTH_SPACE = "\uFEFF";
remote: 44147 const NON_BREAKING_SPACE = "\u00A0";
remote: 44148 const OBJECT_REPLACEMENT_CHARACTER = "\uFFFC";
remote: 44149
remote: => const extend = function (properties) {
remote: 44151 for (const key in properties) {
remote: 44152 const value = properties[key];
remote: 44153 this[key] = value;
remote: 44154 }
remote: 44155
remote: 44156 return this;
remote: 44157 };
remote: 44158
remote: ==
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/terser-1.1.18/lib/terser.rb:284:in `parse_result'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/terser-1.1.18/lib/terser.rb:228:in `run_terserjs'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/terser-1.1.18/lib/terser.rb:180:in `compile_with_map'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/terser-1.1.18/lib/terser/compressor.rb:36:in `call'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/terser-1.1.18/lib/terser/compressor.rb:23:in `call'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:84:in `call_processor'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:66:in `block in call_processors'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:65:in `reverse_each'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:65:in `call_processors'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/loader.rb:184:in `load_from_unloaded'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/loader.rb:59:in `block in load'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/loader.rb:339:in `fetch_asset_from_dependency_cache'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/loader.rb:43:in `load'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/cached_environment.rb:44:in `block in load'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/map.rb:207:in `block in fetch_or_store'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/map.rb:187:in `fetch'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/concurrent-ruby-1.2.2/lib/concurrent-ruby/concurrent/map.rb:206:in `fetch_or_store'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/cached_environment.rb:44:in `load'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/base.rb:81:in `find_asset'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/base.rb:88:in `find_all_linked_assets'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/manifest.rb:125:in `each'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/manifest.rb:125:in `to_a'
remote: /tmp/build_6cc64a5b/vendor/bundle/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/manifest.rb:125:in `block (2 levels) in find'
...
I suspect the issue is related to actioncable but I could not find the exact line of code that is failing.
There are a few similar lines, for example rails/actioncable/app/assets/javascripts/actioncable.js
:
https://github.com/search?q=repo%3Arails%2Frails++const+extend+%3D+function+(properties)+{&type=code
When I run bundle exec rake assets:precompile
in development then there is no error.
I’d appreciate your help. I’m not sure if this is the issue with Rails or maybe it’s our Heroku environment issue. Thank you.
Expected behavior
Assets compilation should be successful.
Actual behavior
Assets compilation is failing during Heroku deployment.
System configuration
Rails version: 7.1.1 (also the same issue on Rails 7.1.0)
Ruby version: 3.2.2
terser version: 1.1.18
About this issue
- Original URL
- State: closed
- Created 9 months ago
- Comments: 24 (10 by maintainers)
Commits related to this issue
- Don't define global const `extend` in Action Cable JS Trix also defines the same constant, so if both Trix and Action Cable files and minified with Terser, we will get an error. Fixes #49599. — committed to rails/rails by rafaelfranca 9 months ago
- Use rails fix from skipkayhil/rails repo When you visit http://127.0.0.1:3000/admin/article then you see an error: application-e6e574ead20b988071b313d8efec112ad6dce277097ae1b32a45b7bbd6d5e7b8.js:566... — committed to ArturT/rails7-issue-49599 by ArturT 8 months ago
Sorry, no, I just haven’t had time to look into it yet. The linked PR fixed the original issue here, so let me open a new issue for the second problem
I managed to reproduce the issue on a new Rails 7 app. I installed the rails_admin gem with sprockets. You can see step by step in git commit messages what I did.
https://github.com/ArturT/rails7-issue-49599/commits/master
Amazing! Thanks. I think we need to fix trix. I’ll take a look on doing that.
Yes. I think you are doing the right thing to point to the commit, but the problem is that both trix included in Rails and the one included in rails_admin are defining the same constant. Trix should not be exposing a global constant. It works fine when se use
imports
, but not in the assets pipeline.If you don’t add
config.assets.js_compressor = :terser
you can generate an unminified, but concatenated file which would need to have two or moreconst extend
definitions, and we could use the code around them to know where they are defined.