stimulus-rails 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05707ec2f2a7863922adeaa958375491a7aa2cabb57edd897f0570e0939f5d59
4
- data.tar.gz: e511d168ccfba80d881dbeb95a7c1f27b6d230f3e9d37f85db0459d91778d791
3
+ metadata.gz: 89d46eae3d2f08243301a422cd4c81aceb024d2c9ad5d03c9c48d816bd3c0616
4
+ data.tar.gz: bcc92cdbbf0f10beb7bfae41100674e16a64864db47bfda5c16a586f5395e8f7
5
5
  SHA512:
6
- metadata.gz: 48db2e25592f6803fbf716a2a15ed6fe91a3dc1e4605c207644f1b31611e3719ca79fa4ae8b604738060b14b6d9f6af8433cec682633b0870934e6ea69e55e43
7
- data.tar.gz: 881aa4dc01270b88d5ca70081323891f7289f63b8c3598c907805822236bddb63ce9685e338715ebb58317ae149c6b5dd505b7af07dc18674a4ed423f2a23a2e
6
+ metadata.gz: 46f93ef00d23543f8ad325115d8a7c992fb2e9d231ec7fb42452aaabc4f3b629cb3fa4177a878f5c31596fec8aafe0d97a4908730d641c439cc39597d4336bca
7
+ data.tar.gz: 02a943d267d807a0981f65d82084e215e47ca35160eb14e67da6af5015598c16caac400304e66e1d377922a3854414945bdc7500f818740237b411266b92be67
data/README.md CHANGED
@@ -12,19 +12,25 @@ If you want to use Stimulus with a bundler, you should use [Webpacker](https://g
12
12
  2. Run `./bin/bundle install`.
13
13
  3. Run `./bin/rails stimulus:install`
14
14
 
15
- The last command will:
15
+ If using the asset pipeline to manage JavaScript, the last command will:
16
16
 
17
- 1. Create an example controller in app/assets/javascripts/controllers/hello_controller.js
18
- 2. Append the include tags to the `<head>` of your application.html.erb.
19
- 3. Initialize your importmap.json in app/assets/javascripts/importmap.json.erb.
20
- 4. Ensure JavaScript is included in your app/config/manifest.js file for compilation.
17
+ 1. Create an example controller in `app/assets/javascripts/controllers/hello_controller.js`.
18
+ 2. Append the include tags to the `<head>` of your `app/views/layouts/application.html.erb`.
19
+ 3. Initialize your `importmap.json` in `app/assets/javascripts/importmap.json.erb`.
20
+ 4. Ensure JavaScript is included in your `app/assets/config/manifest.js` file for compilation.
21
21
 
22
+ If using Webpacker to manage JavaScript, the last command will:
23
+
24
+ 1. Import the controllers directory in the application pack.
25
+ 2. Create a controllers directory at `app/javascripts/controllers`.
26
+ 3. Create an example controller in `app/javascripts/controllers/hello_controller.js`.
27
+ 4. Install the Stimulus NPM package.
22
28
 
23
29
  ## Usage
24
30
 
25
31
  With the Stimulus include tags added, you'll automatically have activated Stimulus through the controller autoloader. You can now easily add new Stimulus controllers that'll be loaded via ESM dynamic imports.
26
32
 
27
- For example, a more advanced hello_controller could look like this:
33
+ For example, a more advanced `hello_controller` could look like this:
28
34
 
29
35
  ```javascript
30
36
  // app/assets/javascripts/controllers/hello_controller.js
@@ -43,13 +49,13 @@ And it'll be activated and registered automatically when encountering the data-c
43
49
 
44
50
  ```html
45
51
  <div data-controller="hello">
46
- <input data-target="hello.name" type="text">
52
+ <input data-hello-target="name" type="text">
47
53
 
48
54
  <button data-action="click->hello#greet">
49
55
  Greet
50
56
  </button>
51
57
 
52
- <span data-target="hello.output">
58
+ <span data-hello-target="output">
53
59
  </span>
54
60
  </div>
55
61
  ```
@@ -1,21 +1,52 @@
1
1
  import { Application } from "stimulus"
2
2
 
3
3
  const application = Application.start()
4
+ const { controllerAttribute } = application.schema
5
+ const registeredControllers = {}
4
6
 
5
- function autoload() {
6
- Array.from(document.querySelectorAll('[data-controller]')).forEach((element) => {
7
- const controllerNames = element.attributes["data-controller"].value.split(" ")
7
+ function autoloadControllersWithin(element) {
8
+ queryControllerNamesWithin(element).forEach(loadController)
9
+ }
10
+
11
+ function queryControllerNamesWithin(element) {
12
+ return Array.from(element.querySelectorAll(`[${controllerAttribute}]`)).map(extractControllerNamesFrom).flat()
13
+ }
14
+
15
+ function extractControllerNamesFrom(element) {
16
+ return element.getAttribute(controllerAttribute).split(/\s+/).filter(content => content.length)
17
+ }
8
18
 
9
- controllerNames.forEach((controllerName) => {
10
- let controllerFilename = `${controllerName}_controller`
19
+ function loadController(name) {
20
+ import(controllerFilename(name))
21
+ .then(module => registerController(name, module))
22
+ .catch(error => console.log(`Failed to autoload controller: ${name}`, error))
23
+ }
11
24
 
12
- import(controllerFilename).then((controllerModule) => {
13
- application.register(controllerName, controllerModule.default)
14
- }).catch(error => console.log(`Failed to autoload controller: ${controllerName}`))
15
- })
16
- })
25
+ function controllerFilename(name) {
26
+ return `${name.replace(/--/g, "/").replace(/-/g, "_")}_controller`
17
27
  }
18
28
 
19
- autoload()
29
+ function registerController(name, module) {
30
+ if (name in registeredControllers) return
31
+
32
+ application.register(name, module.default)
33
+ registeredControllers[name] = true
34
+ }
35
+
36
+
37
+ new MutationObserver((mutationsList) => {
38
+ for (const { attributeName, target, type } of mutationsList) {
39
+ switch (type) {
40
+ case "attributes": {
41
+ if (attributeName == controllerAttribute && target.hasAttribute(controllerAttribute)) {
42
+ extractControllerNamesFrom(target).forEach(loadController)
43
+ }
44
+ }
45
+ case "childList": {
46
+ autoloadControllersWithin(target)
47
+ }
48
+ }
49
+ }
50
+ }).observe(document.body, { attributeFilter: [controllerAttribute], subtree: true, childList: true })
20
51
 
21
- window.addEventListener("turbo:load", autoload)
52
+ autoloadControllersWithin(document)
@@ -1,10 +1,10 @@
1
1
  module Stimulus::StimulusHelper
2
2
  def stimulus_include_tags
3
- [
3
+ safe_join [
4
4
  javascript_include_tag("stimulus/libraries/es-module-shims", type: "module"),
5
5
  tag.script(type: "importmap-shim", src: asset_path("importmap.json")),
6
6
  javascript_include_tag("stimulus/libraries/stimulus", type: "module-shim"),
7
7
  javascript_include_tag("stimulus/loaders/autoloader", type: "module-shim")
8
- ].join("\n").html_safe
8
+ ], "\n"
9
9
  end
10
10
  end
@@ -0,0 +1 @@
1
+ import "controllers"
@@ -0,0 +1,23 @@
1
+ say "Copying Stimulus JavaScript"
2
+ directory "#{__dir__}/app/assets/javascripts", "app/assets/javascripts"
3
+ empty_directory_with_keep_file "app/assets/javascripts/libraries"
4
+
5
+ say "Add app/assets/javascripts to asset pipeline manifest"
6
+ append_to_file Rails.root.join("app/assets/config/manifest.js").to_s, "//= link_tree ../javascripts\n"
7
+
8
+ APPLICATION_LAYOUT_PATH = Rails.root.join("app/views/layouts/application.html.erb")
9
+
10
+ if APPLICATION_LAYOUT_PATH.exist?
11
+ say "Add Stimulus include tags in application layout"
12
+ insert_into_file Rails.root.join("app/views/layouts/application.html.erb").to_s, "\n <%= stimulus_include_tags %>", before: /\s*<\/head>/
13
+ else
14
+ say "Default application.html.erb is missing!", :red
15
+ say " Add <%= stimulus_include_tags %> within the <head> tag in your custom layout."
16
+ end
17
+
18
+ say "Turn off development debug mode"
19
+ comment_lines Rails.root.join("config/environments/development.rb"), /config.assets.debug = true/
20
+
21
+ say "Turn off rack-mini-profiler"
22
+ comment_lines Rails.root.join("Gemfile"), /rack-mini-profiler/
23
+ run "bin/bundle", capture: true
@@ -0,0 +1,10 @@
1
+ say "Appending Stimulus setup code to #{Webpacker.config.source_entry_path}/application.js"
2
+ append_to_file "#{Webpacker.config.source_entry_path}/application.js" do
3
+ "\n" + open("#{__dir__}/application.js").read
4
+ end
5
+
6
+ say "Creating controllers directory"
7
+ directory "#{__dir__}/app/assets/javascripts/controllers", "#{Webpacker.config.source_path}/controllers"
8
+
9
+ say "Installing all Stimulus dependencies"
10
+ run "yarn add stimulus"
@@ -1,5 +1,5 @@
1
- require "stimulus/version"
2
- require "stimulus/engine"
3
-
4
1
  module Stimulus
5
2
  end
3
+
4
+ require "stimulus/version"
5
+ require "stimulus/engine"
@@ -2,8 +2,7 @@ require "stimulus/importmap_helper"
2
2
 
3
3
  module Stimulus
4
4
  class Engine < ::Rails::Engine
5
- isolate_namespace Stimulus
6
- config.eager_load_namespaces << Stimulus
5
+ config.autoload_once_paths = %w( #{root}/app/helpers )
7
6
 
8
7
  initializer "stimulus.assets" do
9
8
  Rails.application.config.assets.precompile += %w( importmap.json stimulus/manifest )
@@ -11,7 +10,7 @@ module Stimulus
11
10
 
12
11
  initializer "stimulus.helpers" do
13
12
  ActiveSupport.on_load(:action_controller_base) do
14
- helper Stimulus::Engine.helpers
13
+ helper Stimulus::StimulusHelper
15
14
  end
16
15
 
17
16
  Rails.application.config.assets.configure do |env|
@@ -5,19 +5,25 @@ module Stimulus::ImportmapHelper
5
5
 
6
6
  def importmap_list_from(*paths)
7
7
  Array(paths).flat_map do |path|
8
- absolute_path = Rails.root.join(path)
9
- dirname = absolute_path.basename.to_s
8
+ if (absolute_path = Rails.root.join(path)).exist?
9
+ find_javascript_files_in_tree(absolute_path).collect do |filename|
10
+ module_filename = filename.relative_path_from(absolute_path)
11
+ module_name = importmap_module_name_from(module_filename)
12
+ module_path = asset_path(absolute_path.basename.join(module_filename))
10
13
 
11
- absolute_path.children.collect do |module_filename|
12
- module_name = importmap_module_name_from(module_filename)
13
- %("#{module_name}": "#{asset_path("#{dirname}/#{module_filename.basename}")}")
14
+ %("#{module_name}": "#{module_path}")
15
+ end
14
16
  end
15
- end.join(",\n")
17
+ end.compact.join(",\n")
16
18
  end
17
19
 
18
20
  private
19
21
  # Strip off the extension and any versioning data for an absolute module name.
20
22
  def importmap_module_name_from(filename)
21
- filename.basename.to_s.remove(filename.extname).split("@").first
23
+ filename.to_s.remove(filename.extname).split("@").first
24
+ end
25
+
26
+ def find_javascript_files_in_tree(path)
27
+ Dir[path.join("**/*.js{,m}")].collect { |file| Pathname.new(file) }.select(&:file?)
22
28
  end
23
29
  end
@@ -1,3 +1,3 @@
1
1
  module Stimulus
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -1,6 +1,24 @@
1
+ def run_stimulus_install_template(path) system "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{File.expand_path("../install/#{path}.rb", __dir__)}" end
2
+
1
3
  namespace :stimulus do
2
4
  desc "Install Stimulus into the app"
3
5
  task :install do
4
- system "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{File.expand_path("../install/stimulus.rb", __dir__)}"
6
+ if defined?(Webpacker::Engine)
7
+ Rake::Task["stimulus:install:webpacker"].invoke
8
+ else
9
+ Rake::Task["stimulus:install:asset_pipeline"].invoke
10
+ end
11
+ end
12
+
13
+ namespace :install do
14
+ desc "Install Stimulus on the app with the asset pipeline"
15
+ task :asset_pipeline do
16
+ run_stimulus_install_template "stimulus_with_asset_pipeline"
17
+ end
18
+
19
+ desc "Install Stimulus on the app with webpacker"
20
+ task :webpacker do
21
+ run_stimulus_install_template "stimulus_with_webpacker"
22
+ end
5
23
  end
6
24
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stimulus-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
8
8
  - Javan Mahkmali
9
9
  - David Heinemeier Hansson
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-12-23 00:00:00.000000000 Z
13
+ date: 2021-01-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -26,7 +26,7 @@ dependencies:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  version: 6.0.0
29
- description:
29
+ description:
30
30
  email: david@loudthinking.com
31
31
  executables: []
32
32
  extensions: []
@@ -40,12 +40,13 @@ files:
40
40
  - app/assets/javascripts/stimulus/libraries/stimulus.js
41
41
  - app/assets/javascripts/stimulus/libraries/stimulus@2.js
42
42
  - app/assets/javascripts/stimulus/loaders/autoloader.js
43
- - app/assets/javascripts/stimulus/loaders/preloader.js.erb
44
43
  - app/assets/javascripts/stimulus/manifest.js
45
44
  - app/helpers/stimulus/stimulus_helper.rb
46
45
  - lib/install/app/assets/javascripts/controllers/hello_controller.js
47
46
  - lib/install/app/assets/javascripts/importmap.json.erb
48
- - lib/install/stimulus.rb
47
+ - lib/install/application.js
48
+ - lib/install/stimulus_with_asset_pipeline.rb
49
+ - lib/install/stimulus_with_webpacker.rb
49
50
  - lib/stimulus-rails.rb
50
51
  - lib/stimulus/engine.rb
51
52
  - lib/stimulus/importmap_helper.rb
@@ -57,7 +58,7 @@ licenses:
57
58
  metadata:
58
59
  homepage_uri: https://stimulus.hotwire.dev
59
60
  source_code_uri: https://github.com/hotwired/stimulus-rails
60
- post_install_message:
61
+ post_install_message:
61
62
  rdoc_options: []
62
63
  require_paths:
63
64
  - lib
@@ -73,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
74
  version: '0'
74
75
  requirements: []
75
76
  rubygems_version: 3.1.2
76
- signing_key:
77
+ signing_key:
77
78
  specification_version: 4
78
79
  summary: A modest JavaScript framework for the HTML you already have.
79
80
  test_files: []
@@ -1,20 +0,0 @@
1
- // Experimental: Not currently exposed.
2
- import { Application } from "stimulus"
3
-
4
- const application = Application.start()
5
-
6
- async function preloadControllers() {
7
- const imports = await fetch("<%= asset_path "importmap.json" %>").then(r => r.json()).then(json => json.imports)
8
-
9
- for (const name in imports) {
10
- if (name.startsWith("controllers/")) {
11
- let controllerName = name.replace(/controllers\//, "").replace("_controller", "")
12
-
13
- import(imports[name]).then((module) => {
14
- application.register(controllerName, module.default)
15
- }).catch(error => console.log(error))
16
- }
17
- }
18
- }
19
-
20
- preloadControllers()
@@ -1,16 +0,0 @@
1
- say "Copying Stimulus JavaScript"
2
- directory "#{__dir__}/app/assets/javascripts", "app/assets/javascripts"
3
- empty_directory "app/assets/javascripts/libraries"
4
-
5
- say "Add app/javascripts to asset pipeline manifest"
6
- append_to_file Rails.root.join("app/assets/config/manifest.js").to_s, "//= link_tree ../javascripts\n"
7
-
8
- say "Add Stimulus include tags in application layout"
9
- insert_into_file Rails.root.join("app/views/layouts/application.html.erb").to_s, "\n <%= stimulus_include_tags %>", before: /\s*<\/head>/
10
-
11
- say "Turn off development debug mode"
12
- comment_lines Rails.root.join("config/environments/development.rb"), /config.assets.debug = true/
13
-
14
- say "Turn off rack-mini-profiler"
15
- comment_lines Rails.root.join("Gemfile"), /rack-mini-profiler/
16
- run "bin/bundle", capture: true