Skip to content
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

Fixes support for generators as well as manifest and install tasks when working in a Rails engine. #143

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions lib/generators/stimulus/stimulus_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@ class StimulusGenerator < Rails::Generators::NamedBase # :nodoc:
class_option :skip_manifest, type: :boolean, default: false, desc: "Don't update the stimulus manifest"

def copy_view_files
@attribute = stimulus_attribute_value(controller_name)
template "controller.js", "app/javascript/controllers/#{controller_name}_controller.js"
@attribute = stimulus_attribute_value(File.join(class_path, file_name))
template "controller.js", File.join("app/javascript/controllers", class_path, "#{file_name}_controller.js")
rails_command "stimulus:manifest:update" unless Rails.root.join("config/importmap.rb").exist? || options[:skip_manifest]
end

private
def controller_name
name.underscore.gsub(/_controller$/, "")

def file_name
@_file_name ||= remove_possible_suffix(super)
end

def remove_possible_suffix(name)
name.sub(/_?controller$/i, "")
end

def stimulus_attribute_value(controller_name)
controller_name.gsub(/\//, "--").gsub("_", "-")
controller_name.sub(/\A\/+/, "").sub(/\/+\z/, "").gsub(/\//, "--").gsub("_", "-")
end
end
7 changes: 0 additions & 7 deletions lib/install/app/javascript/controllers/hello_controller.js

This file was deleted.

8 changes: 0 additions & 8 deletions lib/install/app/javascript/controllers/index_for_node.js

This file was deleted.

33 changes: 17 additions & 16 deletions lib/install/stimulus_with_bun.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
say "Create controllers directory"
empty_directory "app/javascript/controllers"
copy_file "#{__dir__}/app/javascript/controllers/index_for_node.js",
"app/javascript/controllers/index.js"
copy_file "#{__dir__}/app/javascript/controllers/application.js",
"app/javascript/controllers/application.js"
copy_file "#{__dir__}/app/javascript/controllers/hello_controller.js",
"app/javascript/controllers/hello_controller.js"
say "Installing Stimulus (for bun) into #{destination_root}"
inside destination_root do
say "Create controllers directory"
empty_directory "app/javascript/controllers"
copy_file "#{__dir__}/app/javascript/controllers/application.js", "app/javascript/controllers/application.js"
run "rails generate stimulus hello --without-manifest"
run "rails stimulus:manifest:update"

if (Rails.root.join("app/javascript/application.js")).exist?
say "Import Stimulus controllers"
append_to_file "app/javascript/application.js", %(import "./controllers"\n)
else
say %(Couldn't find "app/javascript/application.js".\nYou must import "./controllers" in your JavaScript entrypoint file), :red
end
if File.exist?("app/javascript/application.js")
say "Import Stimulus controllers"
append_to_file "app/javascript/application.js", %(import "./controllers"\n)
else
say %(Couldn't find "app/javascript/application.js".), :red
say %(You must import "./controllers" in your JavaScript entrypoint file), :red
end

say "Install Stimulus"
run "bun add @hotwired/stimulus"
say "Install Stimulus"
run "bun add @hotwired/stimulus"
end
41 changes: 23 additions & 18 deletions lib/install/stimulus_with_importmap.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
say "Create controllers directory"
empty_directory "app/javascript/controllers"
copy_file "#{__dir__}/app/javascript/controllers/index_for_importmap.js",
"app/javascript/controllers/index.js"
copy_file "#{__dir__}/app/javascript/controllers/application.js",
"app/javascript/controllers/application.js"
copy_file "#{__dir__}/app/javascript/controllers/hello_controller.js",
"app/javascript/controllers/hello_controller.js"
say "Installing Stimulus (for importmap-rails) into #{destination_root}"
inside destination_root do
say "Create controllers directory"
empty_directory "app/javascript/controllers"
copy_file "#{__dir__}/app/javascript/controllers/index_for_importmap.js", "app/javascript/controllers/index.js"
copy_file "#{__dir__}/app/javascript/controllers/application.js", "app/javascript/controllers/application.js"
run "rails generate stimulus hello --without-manifest"

say "Import Stimulus controllers"
append_to_file "app/javascript/application.js", %(import "controllers"\n)
if File.exist?("app/javascript/application.js")
say "Import Stimulus controllers"
append_to_file "app/javascript/application.js", %(import "controllers"\n)
else
say %(Couldn't find "app/javascript/application.js".), :red
say %(You must import "controllers" in your JavaScript entrypoint file), :red
end

say "Pin Stimulus"
say %(Appending: pin "@hotwired/stimulus", to: "stimulus.min.js")
append_to_file "config/importmap.rb", %(pin "@hotwired/stimulus", to: "stimulus.min.js"\n)
say "Pin Stimulus"
say %(Appending: pin "@hotwired/stimulus", to: "stimulus.min.js")
append_to_file "config/importmap.rb", %(pin "@hotwired/stimulus", to: "stimulus.min.js"\n)

say %(Appending: pin "@hotwired/stimulus-loading", to: "stimulus-loading.js")
append_to_file "config/importmap.rb", %(pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"\n)
say %(Appending: pin "@hotwired/stimulus-loading", to: "stimulus-loading.js")
append_to_file "config/importmap.rb", %(pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"\n)

say "Pin all controllers"
say %(Appending: pin_all_from "app/javascript/controllers", under: "controllers")
append_to_file "config/importmap.rb", %(pin_all_from "app/javascript/controllers", under: "controllers"\n)
say "Pin all controllers"
say %(Appending: pin_all_from "#{javascript_root}/controllers", under: "controllers")
append_to_file "config/importmap.rb", %(pin_all_from "#{javascript_root}/controllers", under: "controllers"\n)
end
33 changes: 15 additions & 18 deletions lib/install/stimulus_with_node.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
say "Create controllers directory"
empty_directory "app/javascript/controllers"
copy_file "#{__dir__}/app/javascript/controllers/index_for_node.js",
"app/javascript/controllers/index.js"
copy_file "#{__dir__}/app/javascript/controllers/application.js",
"app/javascript/controllers/application.js"
copy_file "#{__dir__}/app/javascript/controllers/hello_controller.js",
"app/javascript/controllers/hello_controller.js"
say "Installing Stimulus (for node) into #{destination_root}"
inside destination_root do
say "Create controllers directory"
empty_directory "app/javascript/controllers"
copy_file "#{__dir__}/app/javascript/controllers/application.js", "app/javascript/controllers/application.js"
run "rails generate stimulus hello --without-manifest"
run "rails stimulus:manifest:update"

if (Rails.root.join("app/javascript/application.js")).exist?
say "Import Stimulus controllers"
append_to_file "app/javascript/application.js", %(import "./controllers"\n)
else
say %(Couldn't find "app/javascript/application.js".\nYou must import "./controllers" in your JavaScript entrypoint file), :red
end
if File.exist?("app/javascript/application.js")
say "Import Stimulus controllers"
append_to_file "app/javascript/application.js", %(import "./controllers"\n)
else
say %(Couldn't find "app/javascript/application.js".), :red
say %(You must import "./controllers" in your JavaScript entrypoint file), :red
end

say "Install Stimulus"
if (Rails.root.join("bun.config.js")).exist?
run "bun add @hotwired/stimulus"
else
say "Install Stimulus"
run "yarn add @hotwired/stimulus"
end
23 changes: 23 additions & 0 deletions lib/rake/extensions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Extend Rake to allow unscoping from within a scope/namespace.
# This allows engine tasks to unscope from :app and define top-level tasks.
module Rake

module TaskManager
def unscoped
current_scope = @scope
@scope = Scope.make
ns = NameSpace.new(self, @scope)
yield(ns)
ns
ensure
@scope = current_scope
end
end

module DSL
def unscoped(&block)
Rake.application.unscoped(&block)
end
end

end
99 changes: 81 additions & 18 deletions lib/tasks/stimulus_tasks.rake
Original file line number Diff line number Diff line change
@@ -1,46 +1,55 @@
require "stimulus/manifest"
require "rake/extensions"
require "rails/generators"
require "rails/generators/rails/app/app_generator"

module Stimulus
module Tasks
extend self
def run_stimulus_install_template(path)
system RbConfig.ruby, "./bin/rails", "app:template", "LOCATION=#{File.expand_path("../install/#{path}.rb", __dir__)}"

def detect_install_template(root)
if root.join("config/importmap.rb").exist?
"importmap"
elsif root.join("package.json").exist?
if root.join("bun.config.js").exist?
"bun"
else
"node"
end
end
end

def using_bun?
Rails.root.join("bun.config.js").exist?
def self.run_stimulus_install_template(path, root)
Rails::Generators::AppGenerator.apply_rails_template(File.expand_path("../install/#{path}.rb", __dir__), root)
end

end
end

namespace :stimulus do
desc "Install Stimulus into the app"
task :install do
if Rails.root.join("config/importmap.rb").exist?
Rake::Task["stimulus:install:importmap"].invoke
elsif Rails.root.join("package.json").exist? && Stimulus::Tasks.using_bun?
Rake::Task["stimulus:install:bun"].invoke
elsif Rails.root.join("package.json").exist?
Rake::Task["stimulus:install:node"].invoke
if (install_template = Stimulus::Tasks.detect_install_template(Rails.root))
Stimulus::Tasks.run_stimulus_install_template("stimulus_with_#{install_template}", Rails.root)
else
puts "You must either be running with node (package.json) or importmap-rails (config/importmap.rb) to use this gem."
end
end

namespace :install do
desc "Install Stimulus on an app running importmap-rails"
desc "Install Stimulus in an app running importmap-rails"
task :importmap do
Stimulus::Tasks.run_stimulus_install_template "stimulus_with_importmap"
Stimulus::Tasks.run_stimulus_install_template("stimulus_with_importmap", Rails.root)
end

desc "Install Stimulus on an app running node"
desc "Install Stimulus in an app running node"
task :node do
Stimulus::Tasks.run_stimulus_install_template "stimulus_with_node"
Stimulus::Tasks.run_stimulus_install_template("stimulus_with_node", Rails.root)
end

desc "Install Stimulus on an app running bun"
desc "Install Stimulus in an app running bun"
task :bun do
Stimulus::Tasks.run_stimulus_install_template "stimulus_with_bun"
Stimulus::Tasks.run_stimulus_install_template("stimulus_with_bun", Rails.root)
end
end

Expand All @@ -52,8 +61,7 @@ namespace :stimulus do

desc "Update the Stimulus manifest (will overwrite controllers/index.js)"
task :update do
manifest =
Stimulus::Manifest.generate_from(Rails.root.join("app/javascript/controllers"))
manifest = Stimulus::Manifest.generate_from(Rails.root.join("app/javascript/controllers"))

File.open(Rails.root.join("app/javascript/controllers/index.js"), "w+") do |index|
index.puts "// This file is auto-generated by ./bin/rails stimulus:manifest:update"
Expand All @@ -66,3 +74,58 @@ namespace :stimulus do
end
end
end

if defined?(ENGINE_ROOT) && (engine = Rails::Engine.find(ENGINE_ROOT))
unscoped do
namespace :stimulus do

desc "Install Stimulus into the engine"
task :install do
if (install_template = Stimulus::Tasks.detect_install_template(engine.root))
Stimulus::Tasks.run_stimulus_install_template("stimulus_with_#{install_template}", engine.root)
else
puts "You must either be running with node/bun (package.json) or importmap-rails (config/importmap.rb) to use this gem."
end
end

namespace :install do
desc "Install Stimulus in an engine running importmap-rails"
task :importmap do
Stimulus::Tasks.run_stimulus_install_template("stimulus_with_importmap", Rails.root)
end

desc "Install Stimulus in an engine running node"
task :node do
Stimulus::Tasks.run_stimulus_install_template("stimulus_with_node", Rails.root)
end

desc "Install Stimulus in an engine running bun"
task :bun do
Stimulus::Tasks.run_stimulus_install_template("stimulus_with_bun", Rails.root)
end
end

namespace :manifest do

desc "Show the current engine Stimulus manifest (all installed controllers)"
task :display do
puts Stimulus::Manifest.generate_from(engine.root.join("app/javascript/controllers"))
end

desc "Update the engine Stimulus manifest (will overwrite controllers/index.js)"
task :update do
manifest = Stimulus::Manifest.generate_from(engine.root.join("app/javascript/controllers"))
File.open(engine.root.join("app/javascript/controllers/index.js"), "w+") do |index|
index.puts "// This file is auto-generated by ./bin/rails stimulus:manifest:update"
index.puts "// Run that command whenever you add a new controller or create them with"
index.puts "// ./bin/rails generate stimulus controllerName"
index.puts
index.puts %(import { application } from "./application")
index.puts manifest
end
end

end
end
end
end
5 changes: 2 additions & 3 deletions test/generator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class StimulusGeneratorTest < Rails::Generators::TestCase
assert_file "app/javascript/controllers/hello_world_controller.js", /data-controller="hello-world"/
end


test "generating with camelized name and lower case first letter" do
run_generator ["helloWorld"]

Expand All @@ -46,9 +45,9 @@ class StimulusGeneratorTest < Rails::Generators::TestCase
end

test "generating with namespaced name" do
run_generator ["hello/world"]
run_generator ["hello/happy/world"]

assert_file "app/javascript/controllers/hello/world_controller.js", /data-controller="hello--world"/
assert_file "app/javascript/controllers/hello/happy/world_controller.js", /data-controller="hello--happy--world"/
end

test "generating with namespaced and camelized name" do
Expand Down