Requiring JS assets from an engine

I’ve been trying to extract a gem from an app at work for a while now. It’s called Kommandant and it is a command palette built with Hotwire, TailwindCSS and Meilisearch.

Getting acces to all the Ruby code and view partials was pretty easy and straightforward. The CSS was easy as well, but I was hung up for a long time on including the pair of Stimulus controllers that I use to control the command palette. I could not find any documentation or blog posts to help me. But we finally managed to solve it! In the end the solution was relatively simple.

Place your JS in vendor/assets/javascripts/

Create a JS file in this folder named after your gem. In my case it is called kommandant.js. This is where you define, what will be exported.

// In vendor/assets/kommandant.js
export { default as CommandPalette } from './command_palette'
export { default as KeyboardNavigation } from './keyboard_navigation'

Add the the vendor folder to your gemspec’s files

# in kommandant.gemspec
spec.files = Dir.chdir(File.expand_path(__dir__)) do
  Dir["{app,config,lib,vendor}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
end

Looking at the source code of turbo-rails led me to the final step - precompiling the assets.

In the gem’s engine.rb, you need to add an initializer:

# lib/kommandant/engine.rb
PRECOMPILE_ASSETS = %w( kommandant.js )
  initializer "kommandant.assets" do |app|
    if Rails.application.config.respond_to?(:assets)
      Rails.application.config.assets.precompile += PRECOMPILE_ASSETS
    end
  end

That should be all!