hotwire-spark 0.1.9 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,31 @@
1
+ import { log } from "../logger.js"
2
+
3
+ export class ReplaceHtmlReloader {
4
+ static async reload() {
5
+ return new ReplaceHtmlReloader().reload()
6
+ }
7
+
8
+ async reload() {
9
+ await this.#reloadHtml()
10
+ }
11
+
12
+ async #reloadHtml() {
13
+ log("Reload html with Turbo...")
14
+
15
+ this.#keepScrollPosition()
16
+ await this.#visitCurrentPage()
17
+ }
18
+
19
+ #keepScrollPosition() {
20
+ document.addEventListener("turbo:before-render", () => {
21
+ Turbo.navigator.currentVisit.scrolled = true
22
+ }, { once: true })
23
+ }
24
+
25
+ #visitCurrentPage() {
26
+ return new Promise(resolve => {
27
+ document.addEventListener("turbo:load", () => resolve(document), { once: true })
28
+ window.Turbo.visit(window.location)
29
+ })
30
+ }
31
+ }
@@ -2,14 +2,23 @@ import { log } from "../logger.js"
2
2
  import { cacheBustedUrl, reloadHtmlDocument } from "../helpers.js"
3
3
 
4
4
  export class StimulusReloader {
5
- static async reload(filePattern) {
5
+ static async reload(changedFilePath) {
6
6
  const document = await reloadHtmlDocument()
7
- return new StimulusReloader(document, filePattern).reload()
7
+ return new StimulusReloader(document, changedFilePath).reload()
8
8
  }
9
9
 
10
- constructor(document, filePattern = /./) {
10
+ static async reloadAll() {
11
+ Stimulus.controllers.forEach(controller => {
12
+ Stimulus.unload(controller.identifier)
13
+ Stimulus.register(controller.identifier, controller.constructor)
14
+ })
15
+
16
+ return Promise.resolve()
17
+ }
18
+
19
+ constructor(document, changedFilePath) {
11
20
  this.document = document
12
- this.filePattern = filePattern
21
+ this.changedFilePath = changedFilePath
13
22
  this.application = window.Stimulus
14
23
  }
15
24
 
@@ -40,7 +49,12 @@ export class StimulusReloader {
40
49
  }
41
50
 
42
51
  #shouldReloadController(path) {
43
- return this.filePattern.test(path)
52
+ return this.#extractControllerName(path) === this.#changedControllerIdentifier
53
+ }
54
+
55
+ get #changedControllerIdentifier() {
56
+ this.changedControllerIdentifier = this.changedControllerIdentifier || this.#extractControllerName(this.changedFilePath)
57
+ return this.changedControllerIdentifier
44
58
  }
45
59
 
46
60
  get #stimulusPathsByModule() {
@@ -72,7 +86,7 @@ export class StimulusReloader {
72
86
  if (this.#didChangeTriggerAReload) {
73
87
  return []
74
88
  } else {
75
- return this.application.controllers.filter(controller => this.filePattern.test(`${controller.identifier}_controller`))
89
+ return this.application.controllers.filter(controller => this.#changedControllerIdentifier === controller.identifier)
76
90
  }
77
91
  }
78
92
 
@@ -86,10 +100,12 @@ export class StimulusReloader {
86
100
 
87
101
  #extractControllerName(path) {
88
102
  return path
89
- .replace(/^.*\//, "")
103
+ .replace(/^\/+/, "")
104
+ .replace(/^controllers\//, "")
90
105
  .replace("_controller", "")
91
106
  .replace(/\//g, "--")
92
107
  .replace(/_/g, "-")
108
+ .replace(/\.js$/, "")
93
109
  }
94
110
 
95
111
  #registerController(name, module) {
data/config/routes.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  Hotwire::Spark::Engine.routes.draw do
2
+ get "/source_files", to: "source_files#show"
2
3
  end
@@ -0,0 +1,37 @@
1
+ class Hotwire::Spark::Change
2
+ attr_reader :paths, :extensions, :changed_path, :action
3
+
4
+ def initialize(paths, extensions, changed_path, action)
5
+ @paths = paths
6
+ @extensions = extensions
7
+ @changed_path = changed_path
8
+ @action = action
9
+ end
10
+
11
+ def broadcast
12
+ broadcast_reload_action if should_broadcast?
13
+ end
14
+
15
+ private
16
+ def broadcast_reload_action
17
+ Hotwire::Spark.cable_server.broadcast "hotwire_spark", reload_message
18
+ end
19
+
20
+ def reload_message
21
+ { action: action, path: canonical_changed_path }
22
+ end
23
+
24
+ def canonical_changed_path
25
+ canonical_changed_path = changed_path
26
+ paths.each { |path| canonical_changed_path = canonical_changed_path.to_s.gsub(/^#{path}/, "") }
27
+ canonical_changed_path
28
+ end
29
+
30
+ def should_broadcast?
31
+ changed_path.to_s =~ extension_regexp
32
+ end
33
+
34
+ def extension_regexp
35
+ /#{extensions.map { |ext| "\\." + ext }.join("|")}$/
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ class Hotwire::Spark::DefaultOptions
2
+ def initialize
3
+ @config = base_options
4
+
5
+ build
6
+ end
7
+
8
+ def to_h
9
+ @config
10
+ end
11
+
12
+ private
13
+ def base_options
14
+ {
15
+ enabled: Rails.env.development?,
16
+ css_paths: File.directory?("app/assets/builds") ? %w[ app/assets/builds ] : %w[ app/assets/stylesheets ],
17
+ css_extensions: %w[ css ],
18
+ html_paths: %w[ app/controllers app/helpers app/models app/views ],
19
+ html_extensions: %w[ rb erb ],
20
+ stimulus_paths: %w[ app/javascript/controllers ],
21
+ stimulus_extensions: %w[ js ],
22
+ html_reload_method: :morph
23
+ }
24
+ end
25
+
26
+ def build
27
+ configure_jsbundling if defined?(Jsbundling)
28
+ end
29
+
30
+ def configure_jsbundling
31
+ @config[:stimulus_paths] = []
32
+ @config[:html_paths] << "app/assets/builds"
33
+ @config[:html_extensions] << "js"
34
+ @config[:html_reload_method] = :replace
35
+ end
36
+ end
@@ -1,4 +1,5 @@
1
1
  require "action_cable/server/base"
2
+ require "hotwire/spark/default_options"
2
3
 
3
4
  module Hotwire::Spark
4
5
  class Engine < ::Rails::Engine
@@ -6,11 +7,7 @@ module Hotwire::Spark
6
7
 
7
8
  config.hotwire = ActiveSupport::OrderedOptions.new unless config.respond_to?(:hotwire)
8
9
  config.hotwire.spark = ActiveSupport::OrderedOptions.new
9
- config.hotwire.spark.merge! \
10
- enabled: Rails.env.development?,
11
- css_paths: File.directory?("app/assets/builds") ? %w[ app/assets/builds ] : %w[ app/assets/stylesheets ],
12
- html_paths: %w[ app/controllers app/helpers app/models app/views ],
13
- stimulus_paths: %w[ app/javascript/controllers ]
10
+ config.hotwire.spark.merge! Hotwire::Spark::DefaultOptions.new.to_h
14
11
 
15
12
  initializer "hotwire_spark.config" do |application|
16
13
  config.hotwire.spark.each do |key, value|
@@ -36,9 +36,13 @@ class Hotwire::Spark::FileWatcher
36
36
  changed_files.each do |file|
37
37
  @callbacks_by_path.each do |path, callbacks|
38
38
  if file.to_s.start_with?(path.to_s)
39
- callbacks.each { |callback| callback.call(file) }
39
+ callbacks.each { |callback| callback.call(as_relative_path(file)) }
40
40
  end
41
41
  end
42
42
  end
43
43
  end
44
+
45
+ def as_relative_path(path)
46
+ Pathname.new(path).relative_path_from(Rails.application.root)
47
+ end
44
48
  end
@@ -29,25 +29,20 @@ class Hotwire::Spark::Installer
29
29
  end
30
30
 
31
31
  def register_monitored_paths
32
- monitor :css_paths, action: :reload_css
33
- monitor :html_paths, action: :reload_html
34
- monitor :stimulus_paths, action: :reload_stimulus
32
+ monitor :css_paths, action: :reload_css, extensions: Hotwire::Spark.css_extensions
33
+ monitor :html_paths, action: :reload_html, extensions: Hotwire::Spark.html_extensions
34
+ monitor :stimulus_paths, action: :reload_stimulus, extensions: Hotwire::Spark.stimulus_extensions
35
35
  end
36
36
 
37
- def monitor(paths_name, action:)
38
- file_watcher.monitor Hotwire::Spark.public_send(paths_name) do |file_path|
39
- broadcast_reload_action(action, file_path)
37
+ def monitor(paths_name, action:, extensions:)
38
+ paths = Hotwire::Spark.public_send(paths_name)
39
+ if paths.present?
40
+ file_watcher.monitor paths do |file_path|
41
+ Hotwire::Spark::Change.new(paths, extensions, file_path, action).broadcast
42
+ end
40
43
  end
41
44
  end
42
45
 
43
- def broadcast_reload_action(action, file_path)
44
- Hotwire::Spark.cable_server.broadcast "hotwire_spark", reload_message_for(action, file_path)
45
- end
46
-
47
- def reload_message_for(action, file_path)
48
- { action: action, path: file_path }
49
- end
50
-
51
46
  def file_watcher
52
47
  @file_watches ||= Hotwire::Spark::FileWatcher.new
53
48
  end
@@ -7,6 +7,7 @@ class Hotwire::Spark::Middleware
7
7
  status, headers, response = @app.call(env)
8
8
 
9
9
  if html_response?(headers)
10
+ @request = ActionDispatch::Request.new(env)
10
11
  html = html_from(response)
11
12
  html = inject_javascript(html)
12
13
  html = inject_options(html)
@@ -38,18 +39,22 @@ class Hotwire::Spark::Middleware
38
39
  end
39
40
 
40
41
  def view_helpers
41
- ActionController::Base.helpers
42
+ @request.controller_instance.helpers
42
43
  end
43
44
 
44
45
  def inject_options(html)
45
- if Hotwire::Spark.logging
46
- html.sub("</head>", "#{logging_option}</head>")
47
- else
48
- html
49
- end
46
+ html.sub("</head>", "#{options}</head>")
47
+ end
48
+
49
+ def options
50
+ [ logging_option, html_reload_method_option ].compact.join("\n")
50
51
  end
51
52
 
52
53
  def logging_option
53
- view_helpers.tag.meta(name: "hotwire-spark:logging", content: "true")
54
+ view_helpers.tag.meta(name: "hotwire-spark:logging", content: "true") if Hotwire::Spark.logging
55
+ end
56
+
57
+ def html_reload_method_option
58
+ view_helpers.tag.meta(name: "hotwire-spark:html-reload-method", content: Hotwire::Spark.html_reload_method)
54
59
  end
55
60
  end
@@ -1,5 +1,5 @@
1
1
  module Hotwire
2
2
  module Spark
3
- VERSION = "0.1.9"
3
+ VERSION = "0.1.11"
4
4
  end
5
5
  end
data/lib/hotwire-spark.rb CHANGED
@@ -8,10 +8,13 @@ loader.ignore("#{__dir__}/hotwire/spark/version.rb")
8
8
  loader.setup
9
9
 
10
10
  module Hotwire::Spark
11
- mattr_accessor :css_paths, default: []
12
- mattr_accessor :html_paths, default: []
13
- mattr_accessor :stimulus_paths, default: []
11
+ %i[ css html stimulus ].each do |type|
12
+ mattr_accessor "#{type}_paths".to_sym, default: []
13
+ mattr_accessor "#{type}_extensions".to_sym, default: []
14
+ end
15
+
14
16
  mattr_accessor :logging, default: false
17
+ mattr_accessor :html_reload_method, default: :morph
15
18
 
16
19
  mattr_accessor :enabled, default: Rails.env.development?
17
20
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hotwire-spark
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jorge Manrubia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-22 00:00:00.000000000 Z
11
+ date: 2024-12-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 8.0.0
19
+ version: 7.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 8.0.0
26
+ version: 7.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: zeitwerk
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -131,11 +131,14 @@ files:
131
131
  - app/javascript/hotwire/spark/index.js
132
132
  - app/javascript/hotwire/spark/logger.js
133
133
  - app/javascript/hotwire/spark/reloaders/css_reloader.js
134
- - app/javascript/hotwire/spark/reloaders/html_reloader.js
134
+ - app/javascript/hotwire/spark/reloaders/morph_html_reloader.js
135
+ - app/javascript/hotwire/spark/reloaders/replace_html_reloader.js
135
136
  - app/javascript/hotwire/spark/reloaders/stimulus_reloader.js
136
137
  - config/routes.rb
137
138
  - lib/hotwire-spark.rb
138
139
  - lib/hotwire/spark/action_cable/server.rb
140
+ - lib/hotwire/spark/change.rb
141
+ - lib/hotwire/spark/default_options.rb
139
142
  - lib/hotwire/spark/engine.rb
140
143
  - lib/hotwire/spark/file_watcher.rb
141
144
  - lib/hotwire/spark/installer.rb