proscenium 0.13.0-x86_64-darwin → 0.15.0.beta.1-x86_64-darwin

Sign up to get free protection for your applications and to get access to all the features.
@@ -72,8 +72,8 @@ module Proscenium
72
72
  end
73
73
  end
74
74
 
75
- JS_EXTENSIONS.find(&import_if_exists)
76
- CSS_EXTENSIONS.find(&import_if_exists)
75
+ JS_EXTENSIONS.find(&import_if_exists) unless options[:js] == false
76
+ CSS_EXTENSIONS.find(&import_if_exists) unless options[:css] == false
77
77
  end
78
78
 
79
79
  def each_stylesheet(delete: false)
@@ -109,10 +109,6 @@ module Proscenium
109
109
  imported&.keys&.any? { |x| x.end_with?(*JS_EXTENSIONS) }
110
110
  end
111
111
 
112
- def multiple_js_imported?
113
- imported&.keys&.many? { |x| x.end_with?(*JS_EXTENSIONS) }
114
- end
115
-
116
112
  def imported?(filepath = nil)
117
113
  filepath ? imported&.key?(filepath) : !imported.blank?
118
114
  end
@@ -1,18 +1,70 @@
1
1
  window.Proscenium = window.Proscenium || { lazyScripts: {} };
2
+ const pathAttribute = "data-proscenium-component-path";
2
3
 
4
+ // Find lazyscripts JSON already in the DOM.
3
5
  const element = document.querySelector("#prosceniumLazyScripts");
4
6
  if (element) {
5
- const scripts = JSON.parse(element.text);
6
7
  window.Proscenium.lazyScripts = {
7
8
  ...window.Proscenium.lazyScripts,
8
- ...scripts,
9
+ ...JSON.parse(element.text),
9
10
  };
10
11
  }
11
12
 
12
- const elements = document.querySelectorAll("[data-proscenium-component-path]");
13
+ // Find components already in the DOM.
14
+ const elements = document.querySelectorAll(`[${pathAttribute}]`);
13
15
  elements.length > 0 && init(elements);
14
16
 
15
- function init() {
17
+ new MutationObserver((mutationsList) => {
18
+ for (const { addedNodes } of mutationsList) {
19
+ for (const ele of addedNodes) {
20
+ if (ele.tagName === "SCRIPT" && ele.id === "prosceniumLazyScripts") {
21
+ window.Proscenium.lazyScripts = {
22
+ ...window.Proscenium.lazyScripts,
23
+ ...JSON.parse(ele.text),
24
+ };
25
+ } else if (ele.matches(`[${pathAttribute}]`)) {
26
+ init([ele]);
27
+ }
28
+ }
29
+ }
30
+ }).observe(document, {
31
+ subtree: true,
32
+ childList: true,
33
+ });
34
+
35
+ function init(elements) {
36
+ Array.from(elements, (element) => {
37
+ const path = element.dataset.prosceniumComponentPath;
38
+ const isLazy = "prosceniumComponentLazy" in element.dataset;
39
+ const props = JSON.parse(element.dataset.prosceniumComponentProps);
40
+
41
+ if (proscenium.env.RAILS_ENV === "development") {
42
+ console.groupCollapsed(
43
+ `[proscenium/react/manager] ${isLazy ? "💤" : "⚡️"} %o`,
44
+ path
45
+ );
46
+ console.log("element: %o", element);
47
+ console.log("props: %o", props);
48
+ console.groupEnd();
49
+ }
50
+
51
+ if (isLazy) {
52
+ const observer = new IntersectionObserver((entries) => {
53
+ entries.forEach((entry) => {
54
+ if (entry.isIntersecting) {
55
+ observer.unobserve(element);
56
+
57
+ mount(element, path, props);
58
+ }
59
+ });
60
+ });
61
+
62
+ observer.observe(element);
63
+ } else {
64
+ mount(element, path, props);
65
+ }
66
+ });
67
+
16
68
  /**
17
69
  * Mounts component located at `path`, into the DOM `element`.
18
70
  *
@@ -66,36 +118,4 @@ function init() {
66
118
  console.error("[proscenium/react/manager] %o - %o", path, error);
67
119
  });
68
120
  }
69
-
70
- Array.from(elements, (element) => {
71
- const path = element.dataset.prosceniumComponentPath;
72
- const isLazy = "prosceniumComponentLazy" in element.dataset;
73
- const props = JSON.parse(element.dataset.prosceniumComponentProps);
74
-
75
- if (proscenium.env.RAILS_ENV === "development") {
76
- console.groupCollapsed(
77
- `[proscenium/react/manager] ${isLazy ? "💤" : "⚡️"} %o`,
78
- path
79
- );
80
- console.log("element: %o", element);
81
- console.log("props: %o", props);
82
- console.groupEnd();
83
- }
84
-
85
- if (isLazy) {
86
- const observer = new IntersectionObserver((entries) => {
87
- entries.forEach((entry) => {
88
- if (entry.isIntersecting) {
89
- observer.unobserve(element);
90
-
91
- mount(element, path, props);
92
- }
93
- });
94
- });
95
-
96
- observer.observe(element);
97
- } else {
98
- mount(element, path, props);
99
- }
100
- });
101
121
  }
@@ -10,12 +10,24 @@ module Proscenium
10
10
  end
11
11
  end
12
12
 
13
- def build(event)
13
+ def build_to_path(event)
14
14
  path = event.payload[:identifier]
15
+ cached = event.payload[:cached] ? ' | Cached!' : ''
15
16
  path = CGI.unescape(path) if path.start_with?(/https?%3A%2F%2F/)
16
17
 
17
18
  info do
18
- message = +"[Proscenium] Building #{path}"
19
+ message = +" #{color('[Proscenium]', nil, bold: true)} Building (to path) #{path}"
20
+ message << " (Duration: #{event.duration.round(1)}ms | " \
21
+ "Allocations: #{event.allocations}#{cached})"
22
+ end
23
+ end
24
+
25
+ def build_to_string(event)
26
+ path = event.payload[:identifier]
27
+ path = CGI.unescape(path) if path.start_with?(/https?%3A%2F%2F/)
28
+
29
+ info do
30
+ message = +" #{color('[Proscenium]', nil, bold: true)} Building #{path}"
19
31
  message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
20
32
  end
21
33
  end
@@ -20,8 +20,8 @@ module Proscenium
20
20
  end
21
21
 
22
22
  def attempt
23
- render_response Builder.build(path_to_build, root: Rails.root.to_s,
24
- base_url: @request.base_url)
23
+ render_response Builder.build_to_string(path_to_build, root: Rails.root.to_s,
24
+ base_url: @request.base_url)
25
25
  rescue Builder::CompileError => e
26
26
  raise self.class::CompileError, { file: @request.fullpath, detail: e.message }, caller
27
27
  end
@@ -3,42 +3,52 @@
3
3
  module Proscenium
4
4
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
5
5
  module Monkey
6
- module DebugView
7
- def initialize(assigns)
8
- paths = [RESCUES_TEMPLATE_PATH, Rails.root.join('lib', 'templates').to_s]
9
- lookup_context = ActionView::LookupContext.new(paths)
10
- super(lookup_context, assigns, nil)
11
- end
12
- end
13
-
14
6
  module TemplateRenderer
15
7
  private
16
8
 
17
- def render_template(view, template, layout_name, locals)
18
- return super unless Proscenium.config.side_load
9
+ def render_template(view, template, layout_name, locals) # rubocop:disable Metrics/*
10
+ result = super
11
+ return result if !view.controller || !Proscenium.config.side_load
19
12
 
20
- layout = find_layout(layout_name, locals.keys, [formats.first])
21
13
  renderable = template.instance_variable_get(:@renderable)
22
14
 
23
- if Object.const_defined?(:ViewComponent) &&
24
- template.is_a?(ActionView::Template::Renderable) &&
25
- renderable.class < ::ViewComponent::Base && renderable.class.format == :html
26
- # Side load controller rendered ViewComponent
27
- Importer.sideload "app/views/#{layout.virtual_path}" if layout
28
- Importer.sideload "app/views/#{renderable.virtual_path}"
29
- elsif template.respond_to?(:virtual_path) &&
30
- template.respond_to?(:type) && template.type == :html
31
- Importer.sideload "app/views/#{layout.virtual_path}" if layout
32
-
33
- # Try side loading the variant template
34
- if template.respond_to?(:variant) && template.variant
35
- Importer.sideload "app/views/#{template.virtual_path}+#{template.variant}"
36
- end
37
-
38
- Importer.sideload "app/views/#{template.virtual_path}"
15
+ to_sideload = if Object.const_defined?(:ViewComponent) &&
16
+ template.is_a?(ActionView::Template::Renderable) &&
17
+ renderable.class < ::ViewComponent::Base &&
18
+ renderable.class.format == :html
19
+ renderable
20
+ elsif template.respond_to?(:virtual_path) &&
21
+ template.respond_to?(:type) && template.type == :html
22
+ template
23
+ end
24
+ if to_sideload
25
+ options = view.controller.sideload_assets_options
26
+ layout = find_layout(layout_name, locals.keys, [formats.first])
27
+ sideload_template_assets layout, view.controller, options if layout
28
+ sideload_template_assets to_sideload, view.controller, options
29
+ end
30
+
31
+ result
32
+ end
33
+
34
+ def sideload_template_assets(tpl, controller, options)
35
+ options = {} if options.nil?
36
+ options = { js: options, css: options } unless options.is_a?(Hash)
37
+
38
+ if tpl.instance_variable_defined?(:@sideload_assets_options)
39
+ tpl_options = tpl.instance_variable_get(:@sideload_assets_options)
40
+ options = case tpl_options
41
+ when Hash then options.deep_merge(tpl_options)
42
+ else
43
+ { js: tpl_options, css: tpl_options }
44
+ end
45
+ end
46
+
47
+ %i[css js].each do |k|
48
+ options[k] = controller.instance_eval(&options[k]) if options[k].is_a?(Proc)
39
49
  end
40
50
 
41
- super
51
+ Importer.sideload "app/views/#{tpl.virtual_path}", **options
42
52
  end
43
53
  end
44
54
 
@@ -46,13 +56,38 @@ module Proscenium
46
56
  private
47
57
 
48
58
  def render_partial_template(view, locals, template, layout, block)
49
- if Proscenium.config.side_load && template.respond_to?(:virtual_path) &&
59
+ result = super
60
+
61
+ return result if !view.controller || !Proscenium.config.side_load
62
+
63
+ if template.respond_to?(:virtual_path) &&
50
64
  template.respond_to?(:type) && template.type == :html
51
- Importer.sideload "app/views/#{layout.virtual_path}" if layout
52
- Importer.sideload "app/views/#{template.virtual_path}"
65
+ options = view.controller.sideload_assets_options
66
+ sideload_template_assets layout, options if layout
67
+ sideload_template_assets template, options
68
+ end
69
+
70
+ result
71
+ end
72
+
73
+ def sideload_template_assets(tpl, options)
74
+ options = {} if options.nil?
75
+ options = { js: options, css: options } unless options.is_a?(Hash)
76
+
77
+ if tpl.instance_variable_defined?(:@sideload_assets_options)
78
+ tpl_options = tpl.instance_variable_get(:@sideload_assets_options)
79
+ options = if tpl_options.is_a?(Hash)
80
+ options.deep_merge tpl_options
81
+ else
82
+ { js: tpl_options, css: tpl_options }
83
+ end
84
+ end
85
+
86
+ %i[css js].each do |k|
87
+ options[k] = controller.instance_eval(&options[k]) if options[k].is_a?(Proc)
53
88
  end
54
89
 
55
- super
90
+ Importer.sideload "app/views/#{tpl.virtual_path}", **options
56
91
  end
57
92
  end
58
93
  end
@@ -1,96 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Proscenium::Phlex::AssetInclusions
4
- include Phlex::Rails::Helpers::ContentFor
5
- include Phlex::Rails::Helpers::StyleSheetPath
6
- include Phlex::Rails::Helpers::JavaScriptPath
7
-
8
4
  def include_stylesheets
9
5
  comment { '[PROSCENIUM_STYLESHEETS]' }
10
6
  end
11
7
 
12
- def include_javascripts(defer_lazy_scripts: false)
13
- comment { '[PROSCENIUM_JAVASCRIPTS]' }
14
- !defer_lazy_scripts && include_lazy_javascripts
15
- end
16
-
17
- def include_lazy_javascripts
8
+ def include_javascripts
18
9
  comment { '[PROSCENIUM_LAZY_SCRIPTS]' }
10
+ comment { '[PROSCENIUM_JAVASCRIPTS]' }
19
11
  end
20
12
 
21
- def include_assets(defer_lazy_scripts: false)
13
+ def include_assets
22
14
  include_stylesheets
23
- include_javascripts(defer_lazy_scripts: defer_lazy_scripts)
24
- end
25
-
26
- def after_template
27
- super
28
-
29
- @_buffer.gsub! '<!-- [PROSCENIUM_STYLESHEETS] -->', capture_stylesheets!
30
- @_buffer.gsub! '<!-- [PROSCENIUM_JAVASCRIPTS] -->', capture_javascripts!
31
-
32
- if content_for?(:proscenium_lazy_scripts)
33
- flush
34
- @_buffer.gsub!('<!-- [PROSCENIUM_LAZY_SCRIPTS] -->', capture do
35
- content_for(:proscenium_lazy_scripts)
36
- end)
37
- else
38
- @_buffer.gsub! '<!-- [PROSCENIUM_LAZY_SCRIPTS] -->', ''
39
- end
40
- end
41
-
42
- private
43
-
44
- def capture_stylesheets!
45
- capture do
46
- Proscenium::Importer.each_stylesheet(delete: true) do |path, _path_options|
47
- link rel: 'stylesheet', href: stylesheet_path(path, extname: false)
48
- end
49
- end
50
- end
51
-
52
- def capture_javascripts! # rubocop:disable Metrics/*
53
- unless Rails.application.config.proscenium.code_splitting &&
54
- Proscenium::Importer.multiple_js_imported?
55
- return capture do
56
- Proscenium::Importer.each_javascript(delete: true) do |path, _|
57
- script(src: javascript_path(path, extname: false), type: :module)
58
- end
59
- end
60
- end
61
-
62
- imports = Proscenium::Importer.imported.dup
63
- paths_to_build = []
64
- Proscenium::Importer.each_javascript(delete: true) do |x, _|
65
- paths_to_build << x.delete_prefix('/')
66
- end
67
-
68
- result = Proscenium::Builder.build(paths_to_build.join(';'), base_url: helpers.request.base_url)
69
-
70
- # Remove the react components from the results, so they are not side loaded. Instead they
71
- # are lazy loaded by the component manager.
72
-
73
- capture do
74
- scripts = {}
75
- result.split(';').each do |x|
76
- inpath, outpath = x.split('::')
77
- inpath.prepend '/'
78
- outpath.delete_prefix! 'public'
79
-
80
- next unless imports.key?(inpath)
81
-
82
- if (import = imports[inpath]).delete(:lazy)
83
- scripts[inpath] = import.merge(outpath: outpath)
84
- else
85
- script(src: javascript_path(outpath, extname: false), type: :module)
86
- end
87
- end
88
-
89
- content_for :proscenium_lazy_scripts do
90
- script type: 'application/json', id: 'prosceniumLazyScripts' do
91
- unsafe_raw scripts.to_json
92
- end
93
- end
94
- end
15
+ include_javascripts
95
16
  end
96
17
  end
@@ -12,15 +12,19 @@ module Proscenium
12
12
 
13
13
  include Proscenium::SourcePath
14
14
  include CssModules
15
+ include AssetInclusions
15
16
 
16
17
  module Sideload
17
18
  def before_template
18
- Proscenium::SideLoad.sideload_inheritance_chain self
19
+ Proscenium::SideLoad.sideload_inheritance_chain self,
20
+ helpers.controller.sideload_assets_options
19
21
 
20
22
  super
21
23
  end
22
24
  end
23
25
 
26
+ class_attribute :sideload_assets_options
27
+
24
28
  class << self
25
29
  attr_accessor :abstract_class
26
30
 
@@ -29,6 +33,10 @@ module Proscenium
29
33
 
30
34
  super
31
35
  end
36
+
37
+ def sideload_assets(value)
38
+ self.sideload_assets_options = value
39
+ end
32
40
  end
33
41
  end
34
42
  end
@@ -6,12 +6,6 @@ require 'proscenium/log_subscriber'
6
6
  ENV['RAILS_ENV'] = Rails.env
7
7
 
8
8
  module Proscenium
9
- class << self
10
- def config
11
- @config ||= Railtie.config.proscenium
12
- end
13
- end
14
-
15
9
  class Railtie < ::Rails::Engine
16
10
  isolate_namespace Proscenium
17
11
 
@@ -20,6 +14,14 @@ module Proscenium
20
14
  config.proscenium.side_load = true
21
15
  config.proscenium.code_splitting = true
22
16
 
17
+ # Cache asset paths when building to path. Enabled by default in production.
18
+ # @see Proscenium::Builder#build_to_path
19
+ config.proscenium.cache = if Rails.env.local?
20
+ ActiveSupport::Cache::NullStore.new
21
+ else
22
+ ActiveSupport::Cache::MemoryStore.new
23
+ end
24
+
23
25
  # TODO: implement!
24
26
  config.proscenium.cache_query_string = Rails.env.production? && ENV.fetch('REVISION', nil)
25
27
  config.proscenium.cache_max_age = 2_592_000 # 30 days
@@ -45,6 +47,12 @@ module Proscenium
45
47
  'Proscenium::Builder::BuildError' => 'build_error'
46
48
  }
47
49
 
50
+ config.after_initialize do |_app|
51
+ ActiveSupport.on_load(:action_view) do
52
+ include Proscenium::Helper
53
+ end
54
+ end
55
+
48
56
  initializer 'proscenium.debugging' do
49
57
  if Rails.gem_version >= Gem::Version.new('7.1.0')
50
58
  tpl_path = root.join('lib', 'proscenium', 'templates').to_s
@@ -58,20 +66,17 @@ module Proscenium
58
66
  app.middleware.insert_after ActionDispatch::Static, Rack::ConditionalGet
59
67
  end
60
68
 
61
- initializer 'proscenium.monkey_patches' do
62
- ActiveSupport.on_load(:action_view) do
63
- ActionView::TemplateRenderer.prepend Monkey::TemplateRenderer
64
- ActionView::PartialRenderer.prepend Monkey::PartialRenderer
69
+ initializer 'proscenium.sideloading' do
70
+ ActiveSupport.on_load(:action_controller) do
71
+ ActionController::Base.include EnsureLoaded
72
+ ActionController::Base.include SideLoad::Controller
65
73
  end
66
74
  end
67
75
 
68
- initializer 'proscenium.helper' do
76
+ initializer 'proscenium.monkey_patches' do
69
77
  ActiveSupport.on_load(:action_view) do
70
- ActionView::Base.include Helper
71
- end
72
-
73
- ActiveSupport.on_load(:action_controller) do
74
- ActionController::Base.include EnsureLoaded
78
+ ActionView::TemplateRenderer.prepend Monkey::TemplateRenderer
79
+ ActionView::PartialRenderer.prepend Monkey::PartialRenderer
75
80
  end
76
81
  end
77
82
  end
@@ -44,9 +44,9 @@ module Proscenium
44
44
  end
45
45
 
46
46
  class_methods do
47
- def sideload
48
- Importer.import manager
49
- Importer.sideload source_path, lazy: true
47
+ def sideload(options)
48
+ Importer.import manager, **options, js: { type: 'module' }
49
+ Importer.sideload source_path, lazy: true, **options
50
50
  end
51
51
  end
52
52
 
@@ -2,21 +2,135 @@
2
2
 
3
3
  module Proscenium
4
4
  class SideLoad
5
+ module Controller
6
+ def self.included(child)
7
+ child.class_eval do
8
+ class_attribute :sideload_assets_options
9
+ child.extend ClassMethods
10
+
11
+ append_after_action :capture_and_replace_proscenium_stylesheets,
12
+ :capture_and_replace_proscenium_javascripts,
13
+ if: -> { request.format.html? && !response.redirect? }
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+ def sideload_assets(value)
19
+ self.sideload_assets_options = value
20
+ end
21
+ end
22
+
23
+ def capture_and_replace_proscenium_stylesheets # rubocop:disable Metrics/AbcSize
24
+ return if response_body.first.blank? || !Proscenium::Importer.css_imported?
25
+ return unless response_body.first.include? '<!-- [PROSCENIUM_STYLESHEETS] -->'
26
+
27
+ imports = Proscenium::Importer.imported.dup
28
+ paths_to_build = []
29
+ Proscenium::Importer.each_stylesheet(delete: true) do |x, _|
30
+ paths_to_build << x.delete_prefix('/')
31
+ end
32
+
33
+ result = Proscenium::Builder.build_to_path(paths_to_build.join(';'),
34
+ base_url: helpers.request.base_url)
35
+
36
+ out = []
37
+ result.split(';').each do |x|
38
+ inpath, outpath = x.split('::')
39
+ inpath.prepend '/'
40
+ outpath.delete_prefix! 'public'
41
+
42
+ next unless imports.key?(inpath)
43
+
44
+ import = imports[inpath]
45
+ opts = import[:css].is_a?(Hash) ? import[:css] : {}
46
+ out << helpers.stylesheet_link_tag(outpath, extname: false, **opts)
47
+ end
48
+
49
+ response_body.first.gsub! '<!-- [PROSCENIUM_STYLESHEETS] -->', out.join.html_safe
50
+ end
51
+
52
+ def capture_and_replace_proscenium_javascripts # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/PerceivedComplexity
53
+ return if response_body.first.blank? || !Proscenium::Importer.js_imported?
54
+
55
+ imports = Proscenium::Importer.imported.dup
56
+ paths_to_build = []
57
+ Proscenium::Importer.each_javascript(delete: true) do |x, _|
58
+ paths_to_build << x.delete_prefix('/')
59
+ end
60
+
61
+ result = Proscenium::Builder.build_to_path(paths_to_build.join(';'),
62
+ base_url: helpers.request.base_url)
63
+
64
+ if response_body.first.include? '<!-- [PROSCENIUM_JAVASCRIPTS] -->'
65
+ out = []
66
+ scripts = {}
67
+ result.split(';').each do |x|
68
+ inpath, outpath = x.split('::')
69
+ inpath.prepend '/'
70
+ outpath.delete_prefix! 'public'
71
+
72
+ next unless imports.key?(inpath)
73
+
74
+ if (import = imports[inpath]).delete(:lazy)
75
+ scripts[inpath] = import.merge(outpath: outpath)
76
+ else
77
+ opts = import[:js].is_a?(Hash) ? import[:js] : {}
78
+ out << helpers.javascript_include_tag(outpath, extname: false, **opts)
79
+ end
80
+ end
81
+
82
+ response_body.first.gsub! '<!-- [PROSCENIUM_JAVASCRIPTS] -->', out.join.html_safe
83
+ end
84
+
85
+ return unless response_body.first.include? '<!-- [PROSCENIUM_LAZY_SCRIPTS] -->'
86
+
87
+ lazy_script = ''
88
+ if scripts.present?
89
+ lazy_script = helpers.content_tag 'script', type: 'application/json',
90
+ id: 'prosceniumLazyScripts' do
91
+ scripts.to_json.html_safe
92
+ end
93
+ end
94
+
95
+ response_body.first.gsub! '<!-- [PROSCENIUM_LAZY_SCRIPTS] -->', lazy_script
96
+ end
97
+ end
98
+
5
99
  class << self
6
100
  # Side loads the class, and its super classes that respond to `.source_path`.
7
101
  #
8
- # Assign the `abstract_class` class variable to any abstract class, and it will not be side
9
- # loaded. Additionally, if the class responds to `#sideload?`, and it returns false, it will
10
- # not be side loaded.
102
+ # Set the `abstract_class` class variable to true in any class, and it will not be side
103
+ # loaded.
11
104
  #
12
105
  # If the class responds to `.sideload`, it will be called instead of the regular side loading.
13
106
  # You can use this to customise what is side loaded.
14
- def sideload_inheritance_chain(obj)
15
- return if !Proscenium.config.side_load || (obj.respond_to?(:sideload?) && !obj.sideload?)
107
+ def sideload_inheritance_chain(obj, options) # rubocop:disable Metrics/*
108
+ return unless Proscenium.config.side_load
109
+
110
+ options = {} if options.nil?
111
+ options = { js: options, css: options } unless options.is_a?(Hash)
112
+
113
+ unless obj.sideload_assets_options.nil?
114
+ tpl_options = obj.sideload_assets_options
115
+ options = if tpl_options.is_a?(Hash)
116
+ options.deep_merge tpl_options
117
+ else
118
+ { js: tpl_options, css: tpl_options }
119
+ end
120
+ end
121
+
122
+ %i[css js].each do |k|
123
+ options[k] = obj.instance_eval(&options[k]) if options[k].is_a?(Proc)
124
+ end
16
125
 
17
126
  klass = obj.class
18
127
  while klass.respond_to?(:source_path) && klass.source_path && !klass.abstract_class
19
- klass.respond_to?(:sideload) ? klass.sideload : Importer.sideload(klass.source_path)
128
+ if klass.respond_to?(:sideload)
129
+ klass.sideload options
130
+ else
131
+ Importer.sideload klass.source_path, **options
132
+ end
133
+
20
134
  klass = klass.superclass
21
135
  end
22
136
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Proscenium
4
- VERSION = '0.13.0'
4
+ VERSION = '0.15.0.beta.1'
5
5
  end