Last active
October 16, 2023 15:38
-
-
Save amkisko/bfca789c699362a8e5b7cf92b3421a20 to your computer and use it in GitHub Desktop.
ViewAsset Rails assets autoloading for views by applying single convention for assets paths
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<%= vite_client_tag %> | |
<%= view_asset_render_head %> | |
</head> | |
<body> | |
<%= yield %> | |
<%= view_asset_render_body %> | |
<% if Rails.env.development? %> | |
<%= view_asset_render_debug %> | |
<% end %> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# AUTHOR: Andrei Makarov (github.com/amkisko) | |
class ApplicationController < ActionController::Base | |
before_action do | |
ViewAsset.setup do |config| | |
config.path_filter { |path| Rails.root.join("app/assets", path).exist? } | |
config.path_prefix "views/" | |
config.head_tag_method "_controller.scss", :vite_stylesheet_tag | |
config.head_tag_method "_controller.css", :vite_stylesheet_tag | |
config.body_tag_method "_controller.ts", :vite_typescript_tag | |
config.body_tag_method "_controller.js", :vite_javascript_tag | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# AUTHOR: Andrei Makarov (github.com/amkisko) | |
class CustomController < ApplicationController | |
before_action { ViewAsset << "custom/_additional" } | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# AUTHOR: Andrei Makarov (github.com/amkisko) | |
class ViewAsset | |
def self.setup | |
Rails.logger.debug { "#{name}.#{__method__}" } | |
yield self | |
reset | |
self | |
end | |
def self.head_tag_method(*argv) | |
tag_method(:head, *argv) | |
end | |
def self.body_tag_method(*argv) | |
tag_method(:body, *argv) | |
end | |
def self.tag_method(location, suffix, method_name) | |
location = location.to_s | |
@tag_methods ||= {} | |
@tag_methods[location] ||= {} | |
@tag_methods[location][suffix] = method_name | |
end | |
def self.path_filter(&block) | |
@path_filter = block | |
end | |
path_filter { |path| Rails.root.join("app/assets", path).exist? } | |
def self.path_prefix(prefix) | |
@path_prefix = prefix | |
end | |
path_prefix "views/" | |
def self.add_template(template_instance) | |
templates << template_instance.virtual_path | |
Rails.logger.debug do | |
"#{name}.#{__method__} #{template_instance.virtual_path}" | |
end | |
end | |
def self.<<(path) | |
Rails.logger.debug { "#{name}.#{__method__} #{path}" } | |
templates << path | |
end | |
def self.reset | |
Rails.logger.debug { "#{name}.#{__method__}" } | |
@templates = [] | |
@assets = {} | |
self | |
end | |
def self.templates | |
@templates ||= [] | |
end | |
def self.build_assets | |
result = {} | |
templates.each do |template| | |
@tag_methods&.each do |location, suffixes| | |
suffixes.each do |suffix, method_name| | |
path = "#{@path_prefix}#{template}#{suffix}" | |
result[location] ||= {} | |
result[location][path] = method_name | |
end | |
end | |
end | |
result | |
end | |
def self.assets | |
@assets = build_assets | |
end | |
def self.render_debug(_view) | |
return unless Rails.env.development? | |
Rails.logger.debug { "#{name}.#{__method__}" } | |
<<-HTML.html_safe # rubocop:disable Rails/OutputSafety | |
<script>window.viewAssets = #{assets.to_json}; console.log('ViewAsset.assets', window.viewAssets);</script> | |
HTML | |
end | |
def self.render_head(view) | |
render(view, :head) | |
end | |
def self.render_body(view) | |
render(view, :body) | |
end | |
def self.render(view, location) | |
view_assets = assets[location.to_s] | |
return unless view_assets | |
result = ["<!-- ViewAsset #{location} begin -->"] | |
result += | |
view_assets.filter_map do |path, method_def| | |
next if !@path_filter.call(path) | |
Rails.logger.debug do | |
"#{name}.#{__method__} #{location} #{path} #{method_def}" | |
end | |
if method_def.is_a?(Proc) | |
method_def.call(view, path) | |
elsif method_def.is_a?(Symbol) | |
view.send(method_def, path) | |
end | |
rescue StandardError | |
nil | |
end | |
result += ["<!-- ViewAsset #{location} end -->"] | |
result.join("\n").html_safe # rubocop:disable Rails/OutputSafety | |
end | |
end | |
module ActionView | |
class Template | |
alias render_without_view_asset render | |
def render(*args, **kwargs, &block) | |
ViewAsset.add_template(self) | |
render_without_view_asset(*args, **kwargs, &block) | |
end | |
end | |
end | |
module ViewAssetHelpers | |
def view_asset_include(*args) | |
args.each { |arg| ViewAsset << arg } | |
end | |
def view_asset_render_head | |
ViewAsset.render_head(self) | |
end | |
def view_asset_render_body | |
ViewAsset.render_body(self) | |
end | |
def view_asset_render_debug | |
ViewAsset.render_debug(self) | |
end | |
end | |
ActiveSupport.on_load(:action_controller) do | |
ActionController::Base.helper(ViewAssetHelpers) | |
end | |
ActiveSupport.on_load(:action_view) { include ViewAssetHelpers } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment