Breaking change in 5.3.2: dropping dependencies
I have a tutorial that I wrote recently (against 5.3.1) with bundle add bootstrap -v '~> 5.3.1' (pessimistic version constraint). After bundle, rails server now (after release of 5.3.2) fails to start due to failing to load sassc-rails and dartsass-sprockets (see full stack traces below).
Does this qualify as a breaking change that should have been released with a new major version rather than a patch release? Would it be worthwhile to rollback the change by releasing a 5.3.3 that still depends on sassc and then a 6.0.0 with the dropped dependency?
I did confirm that changing my process to run bundle add bootstrap -v '= 5.3.1' (exact version match) resolves my issue. That fix is easy enough for me, but other people may see their processes break. I suspect this would not affect everyone using the gem: if I already had a Gemfile.lock, I think rails might still load prior sassc dependency. But, as mentioned, this is happening in a tutorial, where I want a learner to repeatably install the gem in a project for the first time (so no prior sassc in Gemfile.lock). And I can't imagine I have the only such tutorial.
I believe the change that breaks is the removal of the sassc dependency from this gem. I see an alternate, non-deprecated gem was added to replace it, but as a dev dependency.
$ rails server -b 0.0.0.0
<internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require': cannot load such file -- sassc-rails (LoadError)
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:17:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootstrap-5.3.2/lib/bootstrap/engine.rb:7:in `rescue in <main>'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootstrap-5.3.2/lib/bootstrap/engine.rb:4:in `<main>'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootstrap-5.3.2/lib/bootstrap.rb:61:in `register_rails_engine'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootstrap-5.3.2/lib/bootstrap.rb:11:in `load!'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootstrap-5.3.2/lib/bootstrap.rb:75:in `<main>'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:60:in `block (2 levels) in require'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:55:in `each'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:55:in `block in require'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:44:in `each'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:44:in `require'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler.rb:196:in `require'
from /root/example-app/config/application.rb:7:in `<main>'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/commands/server/server_command.rb:139:in `block in perform'
from <internal:kernel>:90:in `tap'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/commands/server/server_command.rb:136:in `perform'
from /usr/local/rvm/gems/ruby-3.2.2/gems/thor-1.3.0/lib/thor/command.rb:28:in `run'
from /usr/local/rvm/gems/ruby-3.2.2/gems/thor-1.3.0/lib/thor/invocation.rb:127:in `invoke_command'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command/base.rb:178:in `invoke_command'
from /usr/local/rvm/gems/ruby-3.2.2/gems/thor-1.3.0/lib/thor.rb:527:in `dispatch'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command/base.rb:73:in `perform'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command.rb:71:in `block in invoke'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command.rb:149:in `with_argv'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command.rb:69:in `invoke'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/commands.rb:18:in `<main>'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
from bin/rails:4:in `<main>'
<internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require': cannot load such file -- dartsass-sprockets (LoadError)
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:17:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootstrap-5.3.2/lib/bootstrap/engine.rb:5:in `<main>'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootstrap-5.3.2/lib/bootstrap.rb:61:in `register_rails_engine'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootstrap-5.3.2/lib/bootstrap.rb:11:in `load!'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootstrap-5.3.2/lib/bootstrap.rb:75:in `<main>'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:60:in `block (2 levels) in require'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:55:in `each'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:55:in `block in require'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:44:in `each'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler/runtime.rb:44:in `require'
from /usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/bundler.rb:196:in `require'
from /root/example-app/config/application.rb:7:in `<main>'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/commands/server/server_command.rb:139:in `block in perform'
from <internal:kernel>:90:in `tap'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/commands/server/server_command.rb:136:in `perform'
from /usr/local/rvm/gems/ruby-3.2.2/gems/thor-1.3.0/lib/thor/command.rb:28:in `run'
from /usr/local/rvm/gems/ruby-3.2.2/gems/thor-1.3.0/lib/thor/invocation.rb:127:in `invoke_command'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command/base.rb:178:in `invoke_command'
from /usr/local/rvm/gems/ruby-3.2.2/gems/thor-1.3.0/lib/thor.rb:527:in `dispatch'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command/base.rb:73:in `perform'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command.rb:71:in `block in invoke'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command.rb:149:in `with_argv'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/command.rb:69:in `invoke'
from /usr/local/rvm/gems/ruby-3.2.2/gems/railties-7.1.1/lib/rails/commands.rb:18:in `<main>'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from <internal:/usr/local/rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from /usr/local/rvm/gems/ruby-3.2.2/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
from bin/rails:4:in `<main>'
(Yes, I know that running as root is not a best practice, but it aligns with the containerized environment that my learners are using.)
The new release allows you to choose which Sass compiler to use. We already expect this for JavaScript.
So simply add one of the 2 gems (the deprecated sassrc-rails or the new dartsass-sprockets) and you're good to go.
Yes, I was able to achieve the work around; I just wondered if there was value in fixing the underlying issue. Thanks!
bundle add bootstrap -v '~> 5.3.1'
bundle add dartsass-sprockets -v '~> 3.0.0'
The requirement to add a Sass gem is now thoroughly documented in the readme: https://github.com/twbs/bootstrap-rubygem?tab=readme-ov-file#a-ruby-on-rails