Sprocket Rails V4 link to manifest files of external gems

132 Views Asked by At

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.

1

There are 1 best solutions below

2
On BEST ANSWER

Rails::Railtie

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


Rails::Engine

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

Main app

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
 */