view_component 3.23.2 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/view_component/preview_actions.rb +11 -14
  3. data/app/controllers/view_components_system_test_controller.rb +15 -20
  4. data/app/views/test_mailer/test_asset_email.html.erb +1 -0
  5. data/app/views/test_mailer/test_url_email.html.erb +1 -0
  6. data/app/views/view_components/preview.html.erb +1 -9
  7. data/docs/CHANGELOG.md +415 -0
  8. data/lib/{rails/generators → generators/view_component}/abstract_generator.rb +2 -2
  9. data/lib/{rails/generators → generators/view_component}/component/component_generator.rb +16 -3
  10. data/lib/{rails/generators → generators/view_component}/component/templates/component.rb.tt +6 -1
  11. data/lib/{rails/generators/erb/component_generator.rb → generators/view_component/erb/erb_generator.rb} +4 -3
  12. data/lib/{rails/generators/haml/component_generator.rb → generators/view_component/haml/haml_generator.rb} +3 -3
  13. data/lib/{rails/generators/locale/component_generator.rb → generators/view_component/locale/locale_generator.rb} +3 -3
  14. data/lib/{rails/generators/preview/component_generator.rb → generators/view_component/preview/preview_generator.rb} +3 -3
  15. data/lib/{rails/generators/rspec/component_generator.rb → generators/view_component/rspec/rspec_generator.rb} +3 -3
  16. data/lib/{rails/generators/slim/component_generator.rb → generators/view_component/slim/slim_generator.rb} +3 -3
  17. data/lib/{rails/generators/stimulus/component_generator.rb → generators/view_component/stimulus/stimulus_generator.rb} +3 -3
  18. data/lib/generators/view_component/tailwindcss/tailwindcss_generator.rb +11 -0
  19. data/lib/{rails/generators/test_unit/component_generator.rb → generators/view_component/test_unit/test_unit_generator.rb} +2 -2
  20. data/lib/view_component/base.rb +160 -155
  21. data/lib/view_component/collection.rb +19 -25
  22. data/lib/view_component/compiler.rb +52 -79
  23. data/lib/view_component/config.rb +51 -85
  24. data/lib/view_component/configurable.rb +1 -1
  25. data/lib/view_component/deprecation.rb +1 -1
  26. data/lib/view_component/engine.rb +37 -107
  27. data/lib/view_component/errors.rb +16 -34
  28. data/lib/view_component/inline_template.rb +3 -4
  29. data/lib/view_component/instrumentation.rb +4 -10
  30. data/lib/view_component/preview.rb +4 -11
  31. data/lib/view_component/request_details.rb +30 -0
  32. data/lib/view_component/slot.rb +6 -13
  33. data/lib/view_component/slotable.rb +82 -77
  34. data/lib/view_component/system_spec_helpers.rb +11 -0
  35. data/lib/view_component/system_test_helpers.rb +1 -2
  36. data/lib/view_component/template.rb +106 -83
  37. data/lib/view_component/test_helpers.rb +37 -44
  38. data/lib/view_component/translatable.rb +33 -32
  39. data/lib/view_component/version.rb +3 -3
  40. data/lib/view_component.rb +8 -6
  41. metadata +31 -559
  42. data/app/assets/vendor/prism.css +0 -4
  43. data/app/assets/vendor/prism.min.js +0 -12
  44. data/app/helpers/preview_helper.rb +0 -85
  45. data/app/views/view_components/_preview_source.html.erb +0 -17
  46. data/lib/rails/generators/tailwindcss/component_generator.rb +0 -11
  47. data/lib/view_component/capture_compatibility.rb +0 -44
  48. data/lib/view_component/component_error.rb +0 -6
  49. data/lib/view_component/rails/tasks/view_component.rake +0 -20
  50. data/lib/view_component/render_component_helper.rb +0 -10
  51. data/lib/view_component/render_component_to_string_helper.rb +0 -9
  52. data/lib/view_component/render_monkey_patch.rb +0 -13
  53. data/lib/view_component/render_to_string_monkey_patch.rb +0 -13
  54. data/lib/view_component/rendering_component_helper.rb +0 -9
  55. data/lib/view_component/rendering_monkey_patch.rb +0 -13
  56. data/lib/view_component/slotable_default.rb +0 -20
  57. data/lib/view_component/use_helpers.rb +0 -42
  58. /data/lib/{rails/generators → generators/view_component}/erb/templates/component.html.erb.tt +0 -0
  59. /data/lib/{rails/generators → generators/view_component}/haml/templates/component.html.haml.tt +0 -0
  60. /data/lib/{rails/generators → generators/view_component}/preview/templates/component_preview.rb.tt +0 -0
  61. /data/lib/{rails/generators → generators/view_component}/rspec/templates/component_spec.rb.tt +0 -0
  62. /data/lib/{rails/generators → generators/view_component}/slim/templates/component.html.slim.tt +0 -0
  63. /data/lib/{rails/generators → generators/view_component}/stimulus/templates/component_controller.js.tt +0 -0
  64. /data/lib/{rails/generators → generators/view_component}/stimulus/templates/component_controller.ts.tt +0 -0
  65. /data/lib/{rails/generators → generators/view_component}/tailwindcss/templates/component.html.erb.tt +0 -0
  66. /data/lib/{rails/generators → generators/view_component}/test_unit/templates/component_test.rb.tt +0 -0
@@ -8,7 +8,7 @@ module ViewComponent
8
8
  # * true (a blocking mode which ensures thread safety when redefining the `call` method for components,
9
9
  # default in Rails development and test mode)
10
10
  # * false(a non-blocking mode, default in Rails production mode)
11
- class_attribute :development_mode, default: false
11
+ class_attribute :__vc_development_mode, default: false
12
12
 
13
13
  def initialize(component)
14
14
  @component = component
@@ -30,8 +30,8 @@ module ViewComponent
30
30
 
31
31
  gather_templates
32
32
 
33
- if self.class.development_mode && @templates.any?(&:requires_compiled_superclass?)
34
- @component.superclass.compile(raise_errors: raise_errors)
33
+ if self.class.__vc_development_mode && @templates.any?(&:requires_compiled_superclass?)
34
+ @component.superclass.__vc_compile(raise_errors: raise_errors)
35
35
  end
36
36
 
37
37
  if template_errors.present?
@@ -42,19 +42,36 @@ module ViewComponent
42
42
  end
43
43
 
44
44
  if raise_errors
45
- @component.validate_initialization_parameters!
46
- @component.validate_collection_parameter!
45
+ @component.__vc_validate_initialization_parameters!
46
+ @component.__vc_validate_collection_parameter!
47
47
  end
48
48
 
49
49
  define_render_template_for
50
50
 
51
- @component.register_default_slots
52
- @component.build_i18n_backend
51
+ @component.__vc_register_default_slots
52
+ @component.__vc_build_i18n_backend
53
53
 
54
54
  CompileCache.register(@component)
55
55
  end
56
56
  end
57
57
 
58
+ # @return all matching compiled templates, in priority order based on the requested details from LookupContext
59
+ #
60
+ # @param [ActionView::TemplateDetails::Requested] requested_details i.e. locales, formats, variants
61
+ def find_templates_for(requested_details)
62
+ filtered_templates = @templates.select do |template|
63
+ template.details.matches?(requested_details)
64
+ end
65
+
66
+ if filtered_templates.count > 1
67
+ filtered_templates.sort_by! do |template|
68
+ template.details.sort_key_for(requested_details)
69
+ end
70
+ end
71
+
72
+ filtered_templates
73
+ end
74
+
58
75
  private
59
76
 
60
77
  attr_reader :templates
@@ -64,40 +81,25 @@ module ViewComponent
64
81
  template.compile_to_component
65
82
  end
66
83
 
67
- method_body =
68
- if @templates.one?
69
- @templates.first.safe_method_name_call
70
- elsif (template = @templates.find(&:inline?))
71
- template.safe_method_name_call
72
- else
73
- branches = []
74
-
75
- @templates.each do |template|
76
- conditional =
77
- if template.inline_call?
78
- "variant&.to_sym == #{template.variant.inspect}"
79
- else
80
- [
81
- template.default_format? ? "(format == #{ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT.inspect} || format.nil?)" : "format == #{template.format.inspect}",
82
- template.variant.nil? ? "variant.nil?" : "variant&.to_sym == #{template.variant.inspect}"
83
- ].join(" && ")
84
- end
85
-
86
- branches << [conditional, template.safe_method_name_call]
87
- end
84
+ @component.silence_redefinition_of_method(:render_template_for)
88
85
 
89
- out = branches.each_with_object(+"") do |(conditional, branch_body), memo|
90
- memo << "#{(!memo.present?) ? "if" : "elsif"} #{conditional}\n #{branch_body}\n"
86
+ if @templates.one?
87
+ template = @templates.first
88
+ safe_call = template.safe_method_name_call
89
+ @component.define_method(:render_template_for) do |_|
90
+ @current_template = template
91
+ instance_exec(&safe_call)
92
+ end
93
+ else
94
+ compiler = self
95
+ @component.define_method(:render_template_for) do |details|
96
+ if (@current_template = compiler.find_templates_for(details).first)
97
+ instance_exec(&@current_template.safe_method_name_call)
98
+ else
99
+ raise MissingTemplateError.new(self.class.name, details)
91
100
  end
92
- out << "else\n #{templates.find { _1.variant.nil? && _1.default_format? }.safe_method_name_call}\nend"
93
101
  end
94
-
95
- @component.silence_redefinition_of_method(:render_template_for)
96
- @component.class_eval <<-RUBY, __FILE__, __LINE__ + 1
97
- def render_template_for(variant = nil, format = nil)
98
- #{method_body}
99
102
  end
100
- RUBY
101
103
  end
102
104
 
103
105
  def template_errors
@@ -106,10 +108,7 @@ module ViewComponent
106
108
 
107
109
  errors << "Couldn't find a template file or inline render method for #{@component}." if @templates.empty?
108
110
 
109
- # We currently allow components to have both an inline call method and a template for a variant, with the
110
- # inline call method overriding the template. We should aim to change this in v4 to instead
111
- # raise an error.
112
- @templates.reject(&:inline_call?)
111
+ @templates
113
112
  .map { |template| [template.variant, template.format] }
114
113
  .tally
115
114
  .select { |_, count| count > 1 }
@@ -168,30 +167,18 @@ module ViewComponent
168
167
 
169
168
  def gather_templates
170
169
  @templates ||=
171
- begin
170
+ if @component.__vc_inline_template.present?
171
+ [Template::Inline.new(
172
+ component: @component,
173
+ inline_template: @component.__vc_inline_template
174
+ )]
175
+ else
176
+ path_parser = ActionView::Resolver::PathParser.new
172
177
  templates = @component.sidecar_files(
173
178
  ActionView::Template.template_handler_extensions
174
179
  ).map do |path|
175
- # Extract format and variant from template filename
176
- this_format, variant =
177
- File
178
- .basename(path) # "variants_component.html+mini.watch.erb"
179
- .split(".")[1..-2] # ["html+mini", "watch"]
180
- .join(".") # "html+mini.watch"
181
- .split("+") # ["html", "mini.watch"]
182
- .map(&:to_sym) # [:html, :"mini.watch"]
183
-
184
- out = Template.new(
185
- component: @component,
186
- type: :file,
187
- path: path,
188
- lineno: 0,
189
- extension: path.split(".").last,
190
- this_format: this_format.to_s.split(".").last&.to_sym, # strip locale from this_format, see #2113
191
- variant: variant
192
- )
193
-
194
- out
180
+ details = path_parser.parse(path).details
181
+ Template::File.new(component: @component, path: path, details: details)
195
182
  end
196
183
 
197
184
  component_instance_methods_on_self = @component.instance_methods(false)
@@ -201,24 +188,10 @@ module ViewComponent
201
188
  ).flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call(_|$)/) }
202
189
  .uniq
203
190
  .each do |method_name|
204
- templates << Template.new(
205
- component: @component,
206
- type: :inline_call,
207
- this_format: ViewComponent::Base::VC_INTERNAL_DEFAULT_FORMAT,
208
- variant: method_name.to_s.include?("call_") ? method_name.to_s.sub("call_", "").to_sym : nil,
209
- method_name: method_name,
210
- defined_on_self: component_instance_methods_on_self.include?(method_name)
211
- )
212
- end
213
-
214
- if @component.inline_template.present?
215
- templates << Template.new(
191
+ templates << Template::InlineCall.new(
216
192
  component: @component,
217
- type: :inline,
218
- path: @component.inline_template.path,
219
- lineno: @component.inline_template.lineno,
220
- source: @component.inline_template.source.dup,
221
- extension: @component.inline_template.language
193
+ method_name: method_name,
194
+ defined_on_self: component_instance_methods_on_self.include?(method_name)
222
195
  )
223
196
  end
224
197
 
@@ -13,19 +13,8 @@ module ViewComponent
13
13
  def defaults
14
14
  ActiveSupport::OrderedOptions.new.merge!({
15
15
  generate: default_generate_options,
16
- preview_controller: "ViewComponentsController",
17
- preview_route: "/rails/view_components",
18
- show_previews_source: false,
19
- instrumentation_enabled: false,
20
- use_deprecated_instrumentation_name: true,
21
- render_monkey_patch_enabled: true,
22
- view_component_path: "app/components",
23
- component_parent_class: nil,
24
- show_previews: Rails.env.development? || Rails.env.test?,
25
- preview_paths: default_preview_paths,
26
- test_controller: "ApplicationController",
27
- default_preview_layout: nil,
28
- capture_compatibility_patch_enabled: false
16
+ previews: default_previews_options,
17
+ instrumentation_enabled: false
29
18
  })
30
19
  end
31
20
 
@@ -36,6 +25,12 @@ module ViewComponent
36
25
  # All options under this namespace default to `false` unless otherwise
37
26
  # stated.
38
27
  #
28
+ # #### `#path`
29
+ #
30
+ # Where to put generated components. Defaults to `app/components`:
31
+ #
32
+ # config.view_component.generate.path = "lib/components"
33
+ #
39
34
  # #### `#sidecar`
40
35
  #
41
36
  # Always generate a component with a sidecar directory:
@@ -83,96 +78,56 @@ module ViewComponent
83
78
  #
84
79
  # Required when there is more than one path defined in preview_paths.
85
80
  # Defaults to `""`. If this is blank, the generator will use
86
- # `ViewComponent.config.preview_paths` if defined,
81
+ # `ViewComponent.config.previews.paths` if defined,
87
82
  # `"test/components/previews"` otherwise
88
83
  #
89
84
  # #### `#use_component_path_for_rspec_tests`
90
85
  #
91
- # Whether to use the `config.view_component_path` when generating new
86
+ # Whether to use `config.generate.path` when generating new
92
87
  # RSpec component tests:
93
88
  #
94
89
  # config.view_component.generate.use_component_path_for_rspec_tests = true
95
90
  #
96
- # When set to `true`, the generator will use the `view_component_path` to
91
+ # When set to `true`, the generator will use the `path` to
97
92
  # decide where to generate the new RSpec component test.
98
- # For example, if the `view_component_path` is
93
+ # For example, if the `path` is
99
94
  # `app/views/components`, then the generator will create a new spec file
100
95
  # in `spec/views/components/` rather than the default `spec/components/`.
101
96
 
102
- # @!attribute preview_controller
103
- # @return [String]
104
- # The controller used for previewing components.
105
- # Defaults to `ViewComponentsController`.
106
-
107
- # @!attribute preview_route
108
- # @return [String]
109
- # The entry route for component previews.
110
- # Defaults to `"/rails/view_components"`.
111
-
112
- # @!attribute show_previews_source
113
- # @return [Boolean]
114
- # Whether to display source code previews in component previews.
115
- # Defaults to `false`.
97
+ # @!attribute previews
98
+ # @return [ActiveSupport::OrderedOptions]
99
+ # The subset of configuration options relating to previews.
100
+ #
101
+ # #### `#controller`
102
+ #
103
+ # The controller used for previewing components. Defaults to `ViewComponentsController`:
104
+ #
105
+ # config.view_component.previews.controller = "MyPreviewController"
106
+ #
107
+ # #### `#route`
108
+ #
109
+ # The entry route for component previews. Defaults to `/rails/view_components`:
110
+ #
111
+ # config.view_component.previews.route = "/my_previews"
112
+ #
113
+ # #### `#enabled`
114
+ #
115
+ # Whether component previews are enabled. Defaults to `true` in development and test environments:
116
+ #
117
+ # config.view_component.previews.enabled = false
118
+ #
119
+ # #### `#default_layout`
120
+ #
121
+ # A custom default layout used for the previews index page and individual previews. Defaults to `nil`:
122
+ #
123
+ # config.view_component.previews.default_layout = "preview_layout"
124
+ #
116
125
 
117
126
  # @!attribute instrumentation_enabled
118
127
  # @return [Boolean]
119
128
  # Whether ActiveSupport notifications are enabled.
120
129
  # Defaults to `false`.
121
130
 
122
- # @!attribute use_deprecated_instrumentation_name
123
- # @return [Boolean]
124
- # Whether ActiveSupport Notifications use the private name `"!render.view_component"`
125
- # or are made more publicly available via `"render.view_component"`.
126
- # Will be removed in next major version.
127
- # Defaults to `true`.
128
-
129
- # @!attribute render_monkey_patch_enabled
130
- # @return [Boolean] Whether the #render method should be monkey patched.
131
- # If this is disabled, use `#render_component` or
132
- # `#render_component_to_string` instead.
133
- # Defaults to `true`.
134
-
135
- # @!attribute view_component_path
136
- # @return [String]
137
- # The path in which components, their templates, and their sidecars should
138
- # be stored.
139
- # Defaults to `"app/components"`.
140
-
141
- # @!attribute component_parent_class
142
- # @return [String]
143
- # The parent class from which generated components will inherit.
144
- # Defaults to `nil`. If this is falsy, generators will use
145
- # `"ApplicationComponent"` if defined, `"ViewComponent::Base"` otherwise.
146
-
147
- # @!attribute show_previews
148
- # @return [Boolean]
149
- # Whether component previews are enabled.
150
- # Defaults to `true` in development and test environments.
151
-
152
- # @!attribute preview_paths
153
- # @return [Array<String>]
154
- # The locations in which component previews will be looked up.
155
- # Defaults to `['test/components/previews']` relative to your Rails root.
156
-
157
- # @!attribute test_controller
158
- # @return [String]
159
- # The controller used for testing components.
160
- # Can also be configured on a per-test basis using `#with_controller_class`.
161
- # Defaults to `ApplicationController`.
162
-
163
- # @!attribute default_preview_layout
164
- # @return [String]
165
- # A custom default layout used for the previews index page and individual
166
- # previews.
167
- # Defaults to `nil`. If this is falsy, `"component_preview"` is used.
168
-
169
- # @!attribute capture_compatibility_patch_enabled
170
- # @return [Boolean]
171
- # Enables the experimental capture compatibility patch that makes ViewComponent
172
- # compatible with forms, capture, and other built-ins.
173
- # previews.
174
- # Defaults to `false`.
175
-
176
131
  def default_preview_paths
177
132
  (default_rails_preview_paths + default_rails_engines_preview_paths).uniq
178
133
  end
@@ -200,6 +155,17 @@ module ViewComponent
200
155
  def default_generate_options
201
156
  options = ActiveSupport::OrderedOptions.new(false)
202
157
  options.preview_path = ""
158
+ options.path = "app/components"
159
+ options
160
+ end
161
+
162
+ def default_previews_options
163
+ options = ActiveSupport::OrderedOptions.new
164
+ options.controller = "ViewComponentsController"
165
+ options.route = "/rails/view_components"
166
+ options.enabled = Rails.env.development? || Rails.env.test?
167
+ options.default_layout = nil
168
+ options.paths = default_preview_paths
203
169
  options
204
170
  end
205
171
  end
@@ -5,7 +5,7 @@ module ViewComponent
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- next if respond_to?(:config) && config.respond_to?(:view_component) && config.respond_to_missing?(:test_controller)
8
+ next if respond_to?(:config) && config.respond_to?(:view_component) && config.respond_to_missing?(:instrumentation_enabled)
9
9
 
10
10
  include ActiveSupport::Configurable
11
11
 
@@ -3,6 +3,6 @@
3
3
  require "active_support/deprecation"
4
4
 
5
5
  module ViewComponent
6
- DEPRECATION_HORIZON = "4.0.0"
6
+ DEPRECATION_HORIZON = "5.0.0"
7
7
  Deprecation = ActiveSupport::Deprecation.new(DEPRECATION_HORIZON, "ViewComponent")
8
8
  end
@@ -8,159 +8,99 @@ module ViewComponent
8
8
  class Engine < Rails::Engine # :nodoc:
9
9
  config.view_component = ViewComponent::Config.current
10
10
 
11
- if Rails.version.to_f < 8.0
12
- rake_tasks do
13
- load "view_component/rails/tasks/view_component.rake"
14
- end
15
- else
16
- initializer "view_component.stats_directories" do |app|
17
- require "rails/code_statistics"
18
-
19
- if Rails.root.join(ViewComponent::Base.view_component_path).directory?
20
- Rails::CodeStatistics.register_directory("ViewComponents", ViewComponent::Base.view_component_path)
21
- end
22
-
23
- if Rails.root.join("test/components").directory?
24
- Rails::CodeStatistics.register_directory("ViewComponent tests", "test/components", test_directory: true)
25
- end
26
- end
27
- end
28
-
29
11
  initializer "view_component.set_configs" do |app|
30
12
  options = app.config.view_component
31
13
 
32
- %i[generate preview_controller preview_route show_previews_source].each do |config_option|
14
+ %i[generate previews].each do |config_option|
33
15
  options[config_option] ||= ViewComponent::Base.public_send(config_option)
34
16
  end
35
17
  options.instrumentation_enabled = false if options.instrumentation_enabled.nil?
36
- options.render_monkey_patch_enabled = true if options.render_monkey_patch_enabled.nil?
37
- options.show_previews = (Rails.env.development? || Rails.env.test?) if options.show_previews.nil?
18
+ options.previews.enabled = (Rails.env.development? || Rails.env.test?) if options.previews.enabled.nil?
38
19
 
39
- if options.show_previews
20
+ if options.previews.enabled
40
21
  # This is still necessary because when `config.view_component` is declared, `Rails.root` is unspecified.
41
- options.preview_paths << "#{Rails.root}/test/components/previews" if defined?(Rails.root) && Dir.exist?(
22
+ options.previews.paths << "#{Rails.root}/test/components/previews" if defined?(Rails.root) && Dir.exist?(
42
23
  "#{Rails.root}/test/components/previews"
43
24
  )
44
-
45
- if options.show_previews_source
46
- require "method_source"
47
-
48
- app.config.to_prepare do
49
- MethodSource.instance_variable_set(:@lines_for_file, {})
50
- end
51
- end
52
25
  end
53
26
  end
54
27
 
55
28
  initializer "view_component.enable_instrumentation" do |app|
56
29
  ActiveSupport.on_load(:view_component) do
57
30
  if app.config.view_component.instrumentation_enabled.present?
58
- # :nocov: Re-executing the below in tests duplicates initializers and causes order-dependent failures.
59
31
  ViewComponent::Base.prepend(ViewComponent::Instrumentation)
60
- if app.config.view_component.use_deprecated_instrumentation_name
61
- ViewComponent::Deprecation.deprecation_warning(
62
- "!render.view_component",
63
- "Use the new instrumentation key `render.view_component` instead. See https://viewcomponent.org/guide/instrumentation.html"
64
- )
65
- end
66
- # :nocov:
67
32
  end
68
33
  end
69
34
  end
70
35
 
71
- # :nocov:
72
- initializer "view_component.enable_capture_patch" do |app|
73
- ActiveSupport.on_load(:view_component) do
74
- ActionView::Base.include(ViewComponent::CaptureCompatibility) if app.config.view_component.capture_compatibility_patch_enabled
75
- end
76
- end
77
- # :nocov:
78
-
79
36
  initializer "view_component.set_autoload_paths" do |app|
80
37
  options = app.config.view_component
81
38
 
82
- if options.show_previews && !options.preview_paths.empty?
83
- paths_to_add = options.preview_paths - ActiveSupport::Dependencies.autoload_paths
39
+ if options.previews.enabled && !options.previews.paths.empty?
40
+ paths_to_add = options.previews.paths - ActiveSupport::Dependencies.autoload_paths
84
41
  ActiveSupport::Dependencies.autoload_paths.concat(paths_to_add) if paths_to_add.any?
85
42
  end
86
43
  end
87
44
 
88
- initializer "view_component.eager_load_actions" do
89
- ActiveSupport.on_load(:after_initialize) do
90
- ViewComponent::Base.descendants.each(&:compile) if Rails.application.config.eager_load
45
+ initializer "view_component.propshaft_support" do |_app|
46
+ ActiveSupport.on_load(:view_component) do
47
+ if defined?(Propshaft)
48
+ include Propshaft::Helper
49
+ end
91
50
  end
92
51
  end
93
52
 
94
- initializer "view_component.monkey_patch_render" do |app|
95
- next if Rails.version.to_f >= 6.1 || !app.config.view_component.render_monkey_patch_enabled
96
-
97
- # :nocov:
98
- ViewComponent::Deprecation.deprecation_warning("Monkey patching `render`", "ViewComponent 4.0 will remove the `render` monkey patch")
99
-
100
- ActiveSupport.on_load(:action_view) do
101
- require "view_component/render_monkey_patch"
102
- ActionView::Base.prepend ViewComponent::RenderMonkeyPatch
103
- end
104
-
105
- ActiveSupport.on_load(:action_controller) do
106
- require "view_component/rendering_monkey_patch"
107
- require "view_component/render_to_string_monkey_patch"
108
- ActionController::Base.prepend ViewComponent::RenderingMonkeyPatch
109
- ActionController::Base.prepend ViewComponent::RenderToStringMonkeyPatch
110
- end
111
- # :nocov:
112
- end
53
+ config.after_initialize do |app|
54
+ ActiveSupport.on_load(:view_component) do
55
+ if defined?(Sprockets::Rails)
56
+ include Sprockets::Rails::Helper
113
57
 
114
- initializer "view_component.include_render_component" do |_app|
115
- next if Rails.version.to_f >= 6.1
58
+ # Copy relevant config to VC context
59
+ # See: https://github.com/rails/sprockets-rails/blob/266ec49f3c7c96018dd75f9dc4f9b62fe3f7eecf/lib/sprockets/railtie.rb#L245
60
+ self.debug_assets = app.config.assets.debug
61
+ self.digest_assets = app.config.assets.digest
62
+ self.assets_prefix = app.config.assets.prefix
63
+ self.assets_precompile = app.config.assets.precompile
116
64
 
117
- # :nocov:
118
- ViewComponent::Deprecation.deprecation_warning("using `render_component`", "ViewComponent 4.0 will remove `render_component`")
65
+ self.assets_environment = app.assets
66
+ self.assets_manifest = app.assets_manifest
119
67
 
120
- ActiveSupport.on_load(:action_view) do
121
- require "view_component/render_component_helper"
122
- ActionView::Base.include ViewComponent::RenderComponentHelper
123
- end
68
+ self.resolve_assets_with = app.config.assets.resolve_with
124
69
 
125
- ActiveSupport.on_load(:action_controller) do
126
- require "view_component/rendering_component_helper"
127
- require "view_component/render_component_to_string_helper"
128
- ActionController::Base.include ViewComponent::RenderingComponentHelper
129
- ActionController::Base.include ViewComponent::RenderComponentToStringHelper
70
+ self.check_precompiled_asset = app.config.assets.check_precompiled_asset
71
+ self.unknown_asset_fallback = app.config.assets.unknown_asset_fallback
72
+ # Expose the app precompiled asset check to the view
73
+ self.precompiled_asset_checker = ->(logical_path) { app.asset_precompiled? logical_path }
74
+ end
130
75
  end
131
- # :nocov:
132
76
  end
133
77
 
134
- initializer "static assets" do |app|
135
- if serve_static_preview_assets?(app.config)
136
- app.middleware.use(::ActionDispatch::Static, "#{root}/app/assets/vendor")
78
+ initializer "view_component.eager_load_actions" do
79
+ ActiveSupport.on_load(:after_initialize) do
80
+ ViewComponent::Base.descendants.each(&:__vc_compile) if Rails.application.config.eager_load
137
81
  end
138
82
  end
139
83
 
140
- def serve_static_preview_assets?(app_config)
141
- app_config.view_component.show_previews && app_config.public_file_server.enabled
142
- end
143
-
144
84
  initializer "compiler mode" do |_app|
145
- ViewComponent::Compiler.development_mode = (Rails.env.development? || Rails.env.test?)
85
+ ViewComponent::Compiler.__vc_development_mode = (Rails.env.development? || Rails.env.test?)
146
86
  end
147
87
 
148
88
  config.after_initialize do |app|
149
89
  options = app.config.view_component
150
90
 
151
- if options.show_previews
91
+ if options.previews.enabled
152
92
  app.routes.prepend do
153
- preview_controller = options.preview_controller.sub(/Controller$/, "").underscore
93
+ preview_controller = options.previews.controller.sub(/Controller$/, "").underscore
154
94
 
155
95
  get(
156
- options.preview_route,
96
+ options.previews.route,
157
97
  to: "#{preview_controller}#index",
158
98
  as: :preview_view_components,
159
99
  internal: true
160
100
  )
161
101
 
162
102
  get(
163
- "#{options.preview_route}/*path",
103
+ "#{options.previews.route}/*path",
164
104
  to: "#{preview_controller}#previews",
165
105
  as: :preview_view_component,
166
106
  internal: true
@@ -174,16 +114,6 @@ module ViewComponent
174
114
  end
175
115
  end
176
116
 
177
- # :nocov:
178
- if RUBY_VERSION < "3.2.0"
179
- ViewComponent::Deprecation.deprecation_warning("Support for Ruby versions < 3.2.0", "ViewComponent v4 will remove support for Ruby versions < 3.2.0 no earlier than April 1, 2025")
180
- end
181
-
182
- if Rails.version.to_f < 7.1
183
- ViewComponent::Deprecation.deprecation_warning("Support for Rails versions < 7.1", "ViewComponent v4 will remove support for Rails versions < 7.1 no earlier than April 1, 2025")
184
- end
185
- # :nocov:
186
-
187
117
  app.executor.to_run :before do
188
118
  CompileCache.invalidate! unless ActionView::Base.cache_template_loading
189
119
  end