New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to configure stimulus using the new rails 7 asset pipeline #1064
Comments
@brunoprietog I'd be happy to add it to the documentation. Are you able to look into this? |
I got this hooked up today. To do this you should:
I was initializing my component with |
I'm struggling to get this working with Rails 7 using the esbuild approach too. So far I've had to put the view_component stimulus controllers within the app/javascripts hierarchy. esbuild complains if I add |
Maybe this needs to be added in |
I think you also need to set the cache_sweeper to refresh the importmap: https://github.com/rails/importmap-rails#sweeping-the-cache-in-development-and-test |
I don't have a problem when using esbuild. In |
I come up with a solution based on https://github.com/hotwired/stimulus-rails/blob/main/lib/tasks/stimulus_tasks.rake#L29-L46. I use esbuild with So I added a # frozen_string_literal: true
namespace :view_component do
namespace :stimulus_manifest do
task display: :environment do
puts Stimulus::Manifest.generate_from(Rails.root.join('app/components'))
end
task update: :environment do
manifest =
Stimulus::Manifest.generate_from(Rails.root.join('app/components'))
File.open(Rails.root.join('app/components/index.js'), 'w+') do |index|
index.puts '// This file is auto-generated by ./bin/rails view_component:stimulus_manifest:update'
index.puts '// Run that command whenever you add a new controller in ViewComponent'
index.puts
index.puts %(import { application } from "../javascript/controllers/application")
index.puts manifest
end
end
end
end
if Rake::Task.task_defined?('stimulus:manifest:update')
Rake::Task['stimulus:manifest:update'].enhance do
Rake::Task['view_component:stimulus_manifest:update'].invoke
end
end And it will generate file And then we can just simple use And it works well for me. |
@chunlea thank you so much for sharing! I've been banging my head on this too many hours! 🥳 |
I have just started a new Rails 7 project, with View Component and Stimulus. I am working with just vanilla Importmap Rails, no jsbundling-rails or esbuild. My file structure is as created by the component generator with the sidecar and stimulus flags as @liaden was using. Has anyone found a solution that automatically loads sidecar stimulus controllers as they are added without having to register them manually, using only I have a feeling this sort of abuses what importmap was built to do, so I wouldn't be surprised if the answer was no. But I also feel like there must be a way to accomplish this. Honestly, this could also be more of a question for the Importmap team, but it's all based on trying to sidecar stimulus controllers with ViewComponents, so here I am... I've tried:
Following @liaden 's suggestions, I can get a stimulus controller working in a sidecar folder only by also using @roelandmoors 's suggestion of manually loading and registering the controller. see below for what I'm starting with. File structure
Rails.application.config.assets.paths << "app/components"
Rails.application.config.assets.debug = true
pin "application", preload: true
# ... Hotwire stuff ...
pin_all_from "app/javascript/controllers", under: "controllers"
pin_all_from "app/components" <- new line
// Import and register all your controllers from the importmap under controllers/*
import { application } from "controllers/application"
// Eager load all controllers defined in the import map under controllers/**/*_controller
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("controllers", application)
import HelloComponentController from "hello_component/hello_component_controller";
application.register("hello-component", HelloComponentController); and I actually didn't need step 5 (updating development.rb). Anyway, I'm excited about ViewComponent, and will use it if I can't get this automatically loading sidecar controllers thing to work. But it would be pretty nice! I'll post back if I figure it out.... |
I've came up with a very dirty (IMHO) solution a while ago, but waited for someone to suggest a cleaner one 😅 My solution doesn't require manual controller registration. The main idea is to add # config/application.rb
initializer "app_assets", after: "importmap.assets" do
Rails.application.config.assets.paths << Rails.root.join('app') # for component sidecar js
end
# Sweep importmap cache for components
config.importmap.cache_sweepers << Rails.root.join('app/components') Then we can add component JS files to the asset pipeline: // app/assets/config/manifest.js
//= link_tree ../../components .js Now importmap can pick them up: # config/importmap.rb
pin_all_from "app/components", under: "components" Optionally, lazy load controllers: // app/javascript/controllers/index.js
import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
lazyLoadControllersFrom("components", application) That's it. My hobby app has all of this in one commit together with a sample component imustafin/sibrowser@12fb4ae. Running this setup for a month, faced no problems yet. Possible drawback I'm not sure if this can be "the officially recommended way", but if so, I could send a PR with the documentation. |
I'm also curious what people think about an install task something like |
@imustafin For me this one is not optional to make it works.
|
@spnv yes, you need to load them somehow. You can do Maybe the word "optional" was wrong there. It should have been "for example" maybe. |
So, @imustafin 's solution is working great, if my controller.js files are directly under the top /components folder. Besides doing a whole lot of looping in importmap.rb, anyone have any ideas for getting it to work with namespaced folders and sidecars? @seanbjornsson , you mentioned you were using sidecar dirs, and it's working for you auto-loading the controller for a view component without adding anything to the .erb for a component? |
@tripptuttle if I understood you correctly, my solution should work. In the mentioned commit imustafin/sibrowser@12fb4ae we have app/components/packages_paginated/component_controller.js which is not directly in |
Thanks for getting back so quick! Yes, you are understanding correctly, and you are right! I forgot to update data-controller, I had only updated data-action with the namespace! :-) Thank you! Everything is working, but do you get the following console errors from stimulus? It seems it's looking at the top level as well for the controller.
|
To be honest, it has been a long time since I've configured all of this :) I don't remember if I had such errors. I believe I had only the the expected shim error on Firefox. I don't remember if I even checked the console in other browsers. It just worked. |
Yeah, it all works, but it just throws an error I think while resolving the request for the controller out of the import map. |
Thanks for this rake, it works very well with esbuild, i have add some lines to automatic import the view component stimulus manifest inside normal stimulus controller manifest Add this lines at the end of update task: File.open(Rails.root.join('app/javascript/controllers/index.js'), 'a') do |index|
index.puts ''
index.puts '// Import view component stimulus controllers'
index.puts %(import "../../components")
end |
I wonder if there is any change we can upstream on Stimulus side to make registering non-standard locations for controllers more straightforward. Otherwise, it just seems hacky for now :( Any ideas? I'd be happy to try to push this forward. |
👋 @progapandist nice to see you here! I'd be happy to spend some time to pair on this and try to figure out the best way forward. Let me know! |
@Spone — small world! 😆 For now we did an ugly workaround with adding |
Hey @Spone, I have created a repo with a test application that demonstrates both the "nested folder" workaround, and the failing attempt to register non-standardly-located Stimulus controllers. I have took time to describe everything in the README. https://github.com/progapandist/importmap-view-component-stimulus/ So far I cannot pinpoint which library is to blame for the incompatibility, but I suspect I would appreciate any further guidance! |
I was trying to achieve this and asked for help on StackOverflow: https://stackoverflow.com/questions/73223634/how-to-make-viewcomponent-works-with-importmap-rails/73228193#73228193 I'm using the first option and it's working like a charm. How do you feel about adding the first option to the documentation? |
It gets a bit messy when using namespaced components and sidecar folders. If I use Granted, that's a fairly long name to start with, but is there a way to make these a little (well, a lot TBH :) less verbose? Having the controller name just be |
@unikitty37 we talk about that in this issue: #1393 |
Building on top of @chunlea 's work, I added a section to the rake task to include any CSS in components folder as well: # frozen_string_literal: true
namespace :view_component do
namespace :stimulus_manifest do
task display: :environment do
puts Stimulus::Manifest.generate_from(Rails.root.join("app/components"))
end
task update: :environment do
manifest =
Stimulus::Manifest.generate_from(Rails.root.join("app/components"))
File.open(Rails.root.join("app/components/index.js"), "w+") do |index|
index.puts "// This file is auto-generated by ./bin/rails view_component:stimulus_manifest:update"
index.puts "// Run that command whenever you add a new controller in ViewComponent"
index.puts
index.puts %(import { application } from "../javascript/controllers/application")
index.puts manifest
end
# get all css files under app/components
css_files = Dir.glob(Rails.root.join("app/components/**/*.css"))
# remove the path
css_files = css_files.map { |file| file.gsub(Rails.root.join("app/components/").to_s, "./") }
# remove self reference
css_files = css_files.reject { |file| file == "./components.css" }
# wrap each item in a css import
css_files = css_files.map { |file| "@import '#{file}';" }
File.open(Rails.root.join("app/components/components.css"), "w+") do |index|
index.puts "/* This file is auto-generated by ./bin/rails view_component:stimulus_manifest:update */"
index.puts "/* Run that command whenever you add a new controller in ViewComponent */"
index.puts
index.puts css_files
end
end
end
end
if Rake::Task.task_defined?("stimulus:manifest:update")
Rake::Task["stimulus:manifest:update"].enhance do
Rake::Task["view_component:stimulus_manifest:update"].invoke
end
end |
@imustafin thank you! I was banging my head against the wall with this, but you're configuration is working for me. I had something very close to that but it was only working in my local Rails |
tldr: RailsByte for easy setup I have found myself returning to this thread several times, so I have created a RailsByte that includes the code mentioned earlier and adds an import example. The steps were taken from @liaden's post and @seanbjornsson's addition of the import example. You can find the RailsByte here: https://railsbytes.com/templates/X6ksy1. I opted not to use the auto import example as it might have performance implications. Usage
|
@maks112v could you please add it to the documentation as well, since this is the first place someone will look when they are having config problems, if you need help adding it I would be glad to help. |
@maks112v hows this coming along, can I help you so we can get this issue closed |
Ive been able to get it working with PR#192 I've submitted to importmap-rails. I currently have it running as a monkey patch working for propshaft and sprockets. # lib/monkey_patches/importmap.rb
module MonkeyPatches
module Importmap
def module_path_from(filename, mapping)
[ mapping.path || mapping.under, filename.to_s ].reject(&:empty?).join("/")
end
end
end # config/initializers/monkey_patches.rb
require_relative "../../lib/monkey_patches/importmap"
Importmap::Map.prepend MonkeyPatches::Importmap # config/initializers/assets.rb
Rails.application.config.assets.paths << "app/components" # config/importmap.rb
pin_all_from "app/components", under: "controllers", to: "" Propshaft - just ensure controllers are imported, should be there in default install // app/javascript/application.js
import "controllers"; Sprockets - link the components directory // app/assets/config/manifest.js
//= link_tree ../../components .js Note: I haven't tested this in a production setup but running |
Does anyone know how to automatically run |
Feature request
Hello, how could this be done? In the javascript documentation the configuration needed to use webpack is indicated, but I am interested in using stimulus using importmap and sprockets, as it will be in rails 7 by default, using the asset pipeline.
Could this be added to the documentation?
Thanks!
Motivation
Motivated by those post by DHH:
The text was updated successfully, but these errors were encountered: