Enable caching in development, but discard on each request.

This is the same strategy as followed by ActionView.

This prevents multiple recompiles during the same request

Closes: #345
This commit is contained in:
Felipe Sateler 2020-06-10 23:32:00 -04:00
Родитель 990b9bae7c
Коммит f1215bec05
9 изменённых файлов: 97 добавлений и 50 удалений

Просмотреть файл

@ -1,5 +1,9 @@
# master
* Cache components per-request in development, preventing unnecessary recompilation during a single request.
*Felipe Sateler*
# 2.8.0
* Add `before_render`, deprecating `before_render_check`.

Просмотреть файл

@ -778,10 +778,10 @@ ViewComponent is built by:
|@blakewilliams|@seanpdoyle|@tclem|@nashby|@jaredcwhite|
|Boston, MA|New York, NY|San Francisco, CA|Minsk|Portland, OR|
|<img src="https://avatars.githubusercontent.com/simonrand?s=256" alt="simonrand" width="128" />|<img src="https://avatars.githubusercontent.com/fugufish?s=256" alt="fugufish" width="128" />|<img src="https://avatars.githubusercontent.com/cover?s=256" alt="cover" width="128" />|<img src="https://avatars.githubusercontent.com/franks921?s=256" alt="franks921" width="128" />|
|:---:|:---:|:---:|:---:|
|@simonrand|@fugufish|@cover|@franks921|
|Dublin, Ireland|Salt Lake City, Utah|Barcelona|South Africa|
|<img src="https://avatars.githubusercontent.com/simonrand?s=256" alt="simonrand" width="128" />|<img src="https://avatars.githubusercontent.com/fugufish?s=256" alt="fugufish" width="128" />|<img src="https://avatars.githubusercontent.com/cover?s=256" alt="cover" width="128" />|<img src="https://avatars.githubusercontent.com/franks921?s=256" alt="franks921" width="128" />|<img src="https://avatars.githubusercontent.com/fsateler?s=256" alt="fsateler" width="128" />|
|:---:|:---:|:---:|:---:|:---:|
|@simonrand|@fugufish|@cover|@franks921|fsateler|
|Dublin, Ireland|Salt Lake City, Utah|Barcelona|South Africa|Chile|
## License

Просмотреть файл

@ -3,8 +3,8 @@ Incomplete test coverage
--------------------------------------------------------------------------------
/app/controllers/view_components_controller.rb: 97.22% (missed: 49)
/lib/view_component/base.rb: 97.75% (missed: 169,254,282,332)
/lib/view_component/base.rb: 97.78% (missed: 170,253,281,331)
/lib/view_component/preview.rb: 92.31% (missed: 32,42,78)
/lib/view_component/render_to_string_monkey_patch.rb: 83.33% (missed: 9)
/lib/view_component/test_helpers.rb: 95.45% (missed: 17)
/test/view_component/integration_test.rb: 97.16% (missed: 14,15,16,18,20)
/lib/view_component/test_helpers.rb: 95.65% (missed: 17)
/test/view_component/integration_test.rb: 97.55% (missed: 14,15,16,18,20)

Просмотреть файл

@ -3,6 +3,7 @@
require "action_view"
require "active_support/configurable"
require "view_component/collection"
require "view_component/compile_cache"
require "view_component/previewable"
module ViewComponent
@ -192,9 +193,7 @@ module ViewComponent
end
def compiled?
@compiled ||= false
@compiled && ActionView::Base.cache_template_loading
CompileCache.compiled?(self)
end
# Compile templates to instance methods, assuming they haven't been compiled already.
@ -270,7 +269,7 @@ module ViewComponent
RUBY
end
@compiled = true
CompileCache.register self
end
# we'll eventually want to update this to support other types

Просмотреть файл

@ -0,0 +1,24 @@
# frozen_string_literal: true
module ViewComponent
# Keeps track of which templates have already been compiled
# This is not part of the public API
module CompileCache
mattr_accessor :cache, instance_reader: false, instance_accessor: false do
Set.new
end
module_function
def register(klass)
cache << klass
end
def compiled?(klass)
cache.include? klass
end
def invalidate!
cache.clear
end
end
end

Просмотреть файл

@ -69,6 +69,10 @@ module ViewComponent
get "#{options.preview_route}/*path", to: "view_components#previews", as: :preview_view_component, internal: true
end
end
app.executor.to_run :before do
CompileCache.invalidate! unless ActionView::Base.cache_template_loading
end
end
end
end

Просмотреть файл

@ -30,3 +30,14 @@ def with_preview_route(new_value)
Rails.application.config.view_component.preview_route = old_value
app.reloader.reload!
end
def modify_file(file, content)
filename = Rails.root.join(file)
old_content = File.read(filename)
begin
File.open(filename, "wb+") { |f| f.write(content) }
yield
ensure
File.open(filename, "wb+") { |f| f.write(old_content) }
end
end

Просмотреть файл

@ -38,6 +38,49 @@ class IntegrationTest < ActionDispatch::IntegrationTest
assert_includes inline_response, baseline_response
end
test "template changes are not reflected on new request when cache_template_loading is true" do
# cache_template_loading is set to true on the initializer
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
modify_file "app/components/controller_inline_component.html.erb", "<div>Goodbye world!</div>" do
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
end
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
end
test "template changes are reflected on new request when cache_template_loading is false" do
begin
old_cache = ViewComponent::CompileCache.cache
ViewComponent::CompileCache.cache = Set.new
ActionView::Base.cache_template_loading = false
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
modify_file "app/components/controller_inline_component.html.erb", "<div>Goodbye world!</div>" do
get "/controller_inline"
assert_select("div", "Goodbye world!")
assert_response :success
end
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
ensure
ActionView::Base.cache_template_loading = true
ViewComponent::CompileCache.cache = old_cache
end
end
test "rendering component in a controller using #render_to_string" do
get "/controller_inline_baseline"

Просмотреть файл

@ -275,9 +275,7 @@ class ViewComponentTest < ViewComponent::TestCase
assert_text(%r{http://assets.example.com/assets/application-\w+.css})
end
def test_template_changes_are_not_reflected_in_production
old_value = ActionView::Base.cache_template_loading
ActionView::Base.cache_template_loading = true
def test_template_changes_are_not_reflected_if_cache_is_not_cleared
render_inline(MyComponent.new)
@ -290,29 +288,6 @@ class ViewComponentTest < ViewComponent::TestCase
end
render_inline(MyComponent.new)
ActionView::Base.cache_template_loading = old_value
end
def test_template_changes_are_reflected_outside_production
old_value = ActionView::Base.cache_template_loading
ActionView::Base.cache_template_loading = false
render_inline(MyComponent.new)
assert_text("hello,world!")
modify_file "app/components/my_component.html.erb", "<div>Goodbye world!</div>" do
render_inline(MyComponent.new)
assert_text("Goodbye world!")
end
render_inline(MyComponent.new)
assert_text("hello,world!")
ActionView::Base.cache_template_loading = old_value
end
def test_that_it_has_a_version_number
@ -548,17 +523,4 @@ class ViewComponentTest < ViewComponent::TestCase
assert_match(/MissingDefaultCollectionParameterComponent initializer must accept `missing_default_collection_parameter` collection parameter/, exception.message)
end
private
def modify_file(file, content)
filename = Rails.root.join(file)
old_content = File.read(filename)
begin
File.open(filename, "wb+") { |f| f.write(content) }
yield
ensure
File.open(filename, "wb+") { |f| f.write(old_content) }
end
end
end