Rails8 ViewComponent load css and stimulus JS files from components folder
Rails
ViewComponent
In Rails 8 with Propshaft & Importmaps
I use ViewComponent (3.21.0) and I would like to store Stimulus JS controllers and vanilla CSS files from within component folder
Someting like this :
app/
components/
tag_component.rb
tag_component.html.erb
tag_component_controller.js
tag_component.cssExample content:
/* app/components/tag_component.css */
.tag {
display: inline-block;
padding: 0.5em 1em;
background: #f44336;
color: #fff;
}// app/components/tag_component_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
connect() {
alert("Hello World!")
}
}# app/components/tag_component.rb
class TagComponent < ApplicationComponent
def initialize(title:)
@title = title
end
end# app/components/tag_component.html.erb <div class="tag" data-controller="tag-component"> <%= @title %> </div>
# app/views/pages/index.html.erb <%= render(TagComponent.new(title: "Foo") %>
To achieve this I need to tell Propshaft and Importmaps to include `app/components` folder
# config/initializers/assets.rb
# ...
+Rails.application.config.assets.paths << "app/components"
+Rails.application.config.importmap.cache_sweepers << Rails.root.join("app/components")# config/importmap.rb # ... pin_all_from "app/components", under: "controllers", to: ""
Importmaps will recognize the JS file and Alert will pop (sofar code is production ready)
One more improvement we can do is to define
One more improvement we can do is to define
# app/components/application_component.rb
class ApplicationComponent < ViewComponent::Base
def stimulus_controller
"#{self.class.name.underscore.dasherize.gsub('/', '--')}"
end
end# app/components/tag_component.html.erb <div class="tag" data-controller="<%= stimulus_controller %>"> <%= @title %> </div>
Everything sofar is heavily inspired by article https://blog.theamazingrando.com/posts/rails-propshaft-stimulus-viewcomponent.html
When it comes to our CSS Propshaft needs explicitly load the component css from <style> tag. Sofar I got this ( following is not production ready)
# app/views/layouts/application.html.erb
#...
<head>
<%# Includes all stylesheet files in app/assets/stylesheets %>
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
<% Dir.glob("app/components/**/*.css").map{ File.basename(it, ".css") }.each do %>
<%= stylesheet_link_tag it, "data-turbo-track": "reload" %>
<% end %>
<%= javascript_importmap_tags %>
</head>
#...