Techioz Blog

Sprocket Rails V4 の外部 gem のマニフェスト ファイルへのリンク

概要

Ruby 3、Rails 7+、および Sprockets V4 を使用していると、gem から CSS アセットをコンパイルするのに問題が発生します。

gem を (Rails エンジンとして) 作成しました。それには app/assets/stylesheets/my_gem にいくつかの .css アセットが含まれています (このディレクトリはメインの Rails アプリケーションではなく my_gem プロジェクト内にあることに注意してください)。 app/assets/config/my_gem_manifest.js ファイルには、必要な実際の .css ファイルが含まれています。

my_gem アセットをメインの Rails アプリケーションで使用できる唯一の方法は、Gem のパスを明示的に設定し、次のようにメインの Rail アプリケーションのロード パスに css ファイルを手動で追加することです。

(メインアプリ application.rb 上)

config.assets.paths << '/usr/local/bundle/gems/my_gem-0.1.7/app/assets/stylesheets/my_gem'

これを行うことで、実際にエラーなしで CSS を要求できますが、私の目標は、「my_gem」のマニフェスト ファイルのみを追加し、Sprockets で実際に gem の CSS アセットをコンパイルし、それをメインの Rails アプリケーションで利用できるようにすることです。

また、Gem のマニフェスト ファイルが存在するディレクトリを手動で追加しようとしたり、マニフェスト ファイルをメイン アプリのプリコンパイル リストに追加しようとしたりしましたが、次のように成功しませんでした。

config.assets.paths << '/usr/local/bundle/gems/my_gem-0.1.7/app/assets/config'
config.assets.precompile << "my_gem_manifest.js"

何日もこれと格闘中!助けていただければ幸いです。ありがとう。

解決策

設定:

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

マニフェストを使用する場合:

# 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://translate.google.com/translate?hl=ja&sl=en&tl=ja&u=https://github.com/rails/sprockets#directives

設定:

bin/rails plugin new my_engine --mountable

Railtie とは異なり、Engine は多くのことを処理します。

# 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

これで、メイン アプリから gem/engine アセットを使用できるようになりました。

# 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" %>

または、メインアプリの 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
 */