Using Ruby 3, Rails 7+ and Sprockets V4 I'm having trouble compiling the css assets from gems.
I've created a gem (as a Rails Engine) and it contains some .css assets in app/assets/stylesheets/my_gem
(note that this directory is located inside the my_gem project not in the main Rails application) and also it has a app/assets/config/my_gem_manifest.js
file that includes the actual .css files I need.
The only way I can use my_gem assets into the main Rails application is to explicitly set the gem's path and manually add the css file on the main Rail application's load path like:
(on main app application.rb )
config.assets.paths << '/usr/local/bundle/gems/my_gem-0.1.7/app/assets/stylesheets/my_gem'
By doing this I can actually require my css without errors but my goal is to add only the "my_gem"'s manifest file and have Sprockets to actually compile the gem's css assets and make it available to the main Rails application.
I've tried also to manually add the directory in which the gem's manifest file lives and even tried to add the manifest file to the precompile list of the main app but without success, like this:
config.assets.paths << '/usr/local/bundle/gems/my_gem-0.1.7/app/assets/config'
config.assets.precompile << "my_gem_manifest.js"
Struggling with this for days! Any help appreciated. Thank you.
Setup:
bin/rails plugin new my_gem
# my_gem/lib/my_gem/railtie.rb
module MyGem
class Railtie < ::Rails::Railtie
def root
@root ||= Pathname.new(__dir__).parent.parent
end
initializer :my_gem_assets do |app|
# This is to be able to require your styles from main app application.css
# like this:
#
# /* =require my_gem/application.css */
#
app.config.assets.paths << root.join("app/assets/stylesheets")
# This is to be able to directly link your styles from your templates:
#
# <%= stylesheet_link_tag "my_gem/application.css" %>
#
# this path is relative to any `app.config.assets.paths`
app.config.assets.precompile << "my_gem/application.css"
end
end
end
If you want to use manifest:
# my_gem/lib/my_gem/railtie.rb
module MyGem
class Railtie < ::Rails::Railtie
def root
@root ||= Pathname.new(__dir__).parent.parent
end
initializer :my_gem_assets do |app|
app.config.assets.paths << root.join("app/assets/stylesheets")
app.config.assets.paths << root.join("app/assets/config") # <-----------------------.
app.config.assets.precompile << "my_gem_manifest.js" # relative to asset path -'
end
end
end
// my_gem/app/assets/config/my_gem_manifest.js
//= link my_gem/application.css
https://github.com/rails/sprockets#directives
Setup:
bin/rails plugin new my_engine --mountable
Unlike Railtie, Engine takes care of a lot of stuff for you:
# my_engine/lib/my_engine/engine.rb
module MyEngine
class Engine < ::Rails::Engine
isolate_namespace MyEngine
initializer :my_engine_assets do |app|
# This is automatically done by Rails::Engine
# app.config.assets.paths << root.join("app/assets/stylesheets")
# so you can just require files without extra config
#
# /* =require my_engine/application.css */
# If you want to link directly:
#
# <%= stylesheet_link_tag "my_engine/application.css" %>
#
# add that file to be precompiled
# app.config.assets.precompile << "my_engine/application.css"
#
# or use manifest
# ('app/assets/config' is automatically added to assets paths)
app.config.assets.precompile << "my_engine_manifest.js"
end
end
end
// my_engine/app/assets/config/my_engine_manifest.js
//= link_directory ../stylesheets/my_engine .css
Now you can use your gem/engine assets from the main app:
# app/views/layouts/application.html.erb
# we can do this because these files are in
# Rails.application.config.assets.paths and
# Rails.application.config.assets.precompile
<%= stylesheet_link_tag "my_gem/application.css" %>
<%= stylesheet_link_tag "my_engine/application.css" %>
or you can require files from main app application.css:
/* app/assets/stylesheets/application.css */
/* in this case you don't have to precompile them
* =require my_gem/application.css
* =require my_engine/application.css
*/