proscenium 0.10.0-arm64-darwin → 0.11.0-arm64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +207 -45
  3. data/lib/proscenium/builder.rb +41 -19
  4. data/lib/proscenium/css_module/path.rb +31 -0
  5. data/lib/proscenium/css_module/transformer.rb +82 -0
  6. data/lib/proscenium/css_module.rb +12 -25
  7. data/lib/proscenium/ensure_loaded.rb +27 -0
  8. data/lib/proscenium/ext/proscenium +0 -0
  9. data/lib/proscenium/ext/proscenium.h +3 -2
  10. data/lib/proscenium/helper.rb +85 -0
  11. data/lib/proscenium/importer.rb +110 -0
  12. data/lib/proscenium/libs/react-manager/index.jsx +101 -0
  13. data/lib/proscenium/libs/react-manager/react.js +2 -0
  14. data/lib/proscenium/libs/test.js +1 -0
  15. data/lib/proscenium/middleware/base.rb +7 -7
  16. data/lib/proscenium/middleware/engines.rb +37 -0
  17. data/lib/proscenium/middleware/esbuild.rb +3 -5
  18. data/lib/proscenium/middleware/runtime.rb +18 -0
  19. data/lib/proscenium/middleware.rb +14 -4
  20. data/lib/proscenium/{side_load/monkey.rb → monkey.rb} +19 -15
  21. data/lib/proscenium/phlex/{resolve_css_modules.rb → css_modules.rb} +28 -16
  22. data/lib/proscenium/phlex/react_component.rb +26 -27
  23. data/lib/proscenium/phlex.rb +11 -30
  24. data/lib/proscenium/railtie.rb +44 -46
  25. data/lib/proscenium/react_componentable.rb +95 -0
  26. data/lib/proscenium/resolver.rb +37 -0
  27. data/lib/proscenium/side_load.rb +13 -73
  28. data/lib/proscenium/source_path.rb +15 -0
  29. data/lib/proscenium/templates/rescues/build_error.html.erb +30 -0
  30. data/lib/proscenium/utils.rb +13 -0
  31. data/lib/proscenium/version.rb +1 -1
  32. data/lib/proscenium/view_component/css_modules.rb +11 -0
  33. data/lib/proscenium/view_component/react_component.rb +15 -15
  34. data/lib/proscenium/view_component/sideload.rb +4 -0
  35. data/lib/proscenium/view_component.rb +8 -38
  36. data/lib/proscenium.rb +22 -68
  37. metadata +23 -30
  38. data/lib/proscenium/componentable.rb +0 -63
  39. data/lib/proscenium/css_module/class_names_resolver.rb +0 -66
  40. data/lib/proscenium/css_module/resolver.rb +0 -76
  41. data/lib/proscenium/current.rb +0 -9
  42. data/lib/proscenium/phlex/component_concerns.rb +0 -9
  43. data/lib/proscenium/phlex/page.rb +0 -62
  44. data/lib/proscenium/side_load/ensure_loaded.rb +0 -25
  45. data/lib/proscenium/side_load/helper.rb +0 -41
  46. data/lib/proscenium/view_component/tag_builder.rb +0 -23
@@ -3,41 +3,28 @@
3
3
  module Proscenium::CssModule
4
4
  extend ActiveSupport::Autoload
5
5
 
6
- class StylesheetNotFound < StandardError
7
- def initialize(pathname)
8
- @pathname = pathname
9
- super
10
- end
11
-
12
- def message
13
- "Stylesheet is required, but does not exist: #{@pathname}"
14
- end
15
- end
6
+ autoload :Path
7
+ autoload :Transformer
16
8
 
17
- autoload :ClassNamesResolver
18
- autoload :Resolver # deprecated
9
+ class TransformError < StandardError
10
+ def initialize(name, additional_msg = nil)
11
+ msg = "Failed to transform CSS module `#{name}`"
12
+ msg << ' - ' << additional_msg if additional_msg
19
13
 
20
- # Like `css_modules`, but will raise if the stylesheet cannot be found.
21
- #
22
- # @param name [Array, String]
23
- def css_module!(names)
24
- cssm.class_names!(names).join ' '
14
+ super msg
15
+ end
25
16
  end
26
17
 
27
18
  # Accepts one or more CSS class names, and transforms them into CSS module names.
28
19
  #
29
- # @param name [Array, String]
30
- def css_module(names)
31
- cssm.class_names(names).join ' '
20
+ # @param name [String,Symbol,Array<String,Symbol>]
21
+ def css_module(*names)
22
+ cssm.class_names(*names, require_prefix: false).map { |name, _| name }.join(' ')
32
23
  end
33
24
 
34
25
  private
35
26
 
36
- def path
37
- self.class.path
38
- end
39
-
40
27
  def cssm
41
- @cssm ||= Resolver.new(path)
28
+ @cssm ||= Transformer.new(self.class.css_module_path)
42
29
  end
43
30
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Proscenium
4
+ NotIncludedError = Class.new(StandardError)
5
+
6
+ module EnsureLoaded
7
+ def self.included(child)
8
+ child.class_eval do
9
+ append_after_action do
10
+ if request.format.html? && Importer.imported?
11
+ if Importer.js_imported?
12
+ raise NotIncludedError, 'There are javascripts to be included, but they have ' \
13
+ 'not been included in the page. Did you forget to add the ' \
14
+ '`#include_javascripts` helper in your views?'
15
+ end
16
+
17
+ if Importer.css_imported?
18
+ raise NotIncludedError, 'There are stylesheets to be included, but they have ' \
19
+ 'not been included in the page. Did you forget to add the ' \
20
+ '`#include_stylesheets` helper in your views?'
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
Binary file
@@ -97,7 +97,7 @@ extern "C" {
97
97
  // - codeSpitting?
98
98
  // - debug?
99
99
  //
100
- extern struct Result build(char* filepath, char* baseUrl, char* importMap, char* envVars, char* root, unsigned int env, GoUint8 codeSplitting, GoUint8 debug);
100
+ extern struct Result build(char* filepath, char* baseUrl, char* importMap, char* envVars, char* appRoot, char* gemPath, unsigned int env, GoUint8 codeSplitting, char* engines, GoUint8 debug);
101
101
 
102
102
  // Resolve the given `path` relative to the `root`.
103
103
  //
@@ -107,8 +107,9 @@ extern struct Result build(char* filepath, char* baseUrl, char* importMap, char*
107
107
  // Config
108
108
  // - root - The working directory.
109
109
  // - env - The environment (1 = development, 2 = test, 3 = production)
110
+ // - debug?
110
111
  //
111
- extern struct Result resolve(char* path, char* importMap, char* root, unsigned int env);
112
+ extern struct Result resolve(char* path, char* importMap, char* appRoot, char* gemPath, unsigned int env, GoUint8 debug);
112
113
 
113
114
  #ifdef __cplusplus
114
115
  }
@@ -15,5 +15,90 @@ module Proscenium
15
15
 
16
16
  super
17
17
  end
18
+
19
+ # Accepts one or more CSS class names, and transforms them into CSS module names.
20
+ #
21
+ # @see CssModule::Transformer#class_names
22
+ # @param name [String,Symbol,Array<String,Symbol>]
23
+ def css_module(*names)
24
+ path = Pathname.new(@lookup_context.find(@virtual_path).identifier).sub_ext('')
25
+ CssModule::Transformer.new(path).class_names(*names, require_prefix: false).map do |name, _|
26
+ name
27
+ end.join(' ')
28
+ end
29
+
30
+ def include_stylesheets(**options)
31
+ out = []
32
+ Importer.each_stylesheet(delete: true) do |path, _path_options|
33
+ out << stylesheet_link_tag(path, extname: false, **options)
34
+ end
35
+ out.join("\n").html_safe
36
+ end
37
+ alias side_load_stylesheets include_stylesheets
38
+ deprecate side_load_stylesheets: 'Use `include_stylesheets` instead', deprecator: Deprecator.new
39
+
40
+ # Includes all javascripts that have been imported and side loaded.
41
+ #
42
+ # @param extract_lazy_scripts [Boolean] if true, any lazy scripts will be extracted using
43
+ # `content_for` to `:proscenium_lazy_scripts` for later use. Be sure to include this in your
44
+ # page with the `declare_lazy_scripts` helper, or simply
45
+ # `content_for :proscenium_lazy_scripts`.
46
+ # @return [String] the HTML tags for the javascripts.
47
+ def include_javascripts(extract_lazy_scripts: false, **options) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
48
+ out = []
49
+
50
+ if Rails.application.config.proscenium.code_splitting && Importer.multiple_js_imported?
51
+ imports = Importer.imported.dup
52
+
53
+ paths_to_build = []
54
+ Importer.each_javascript(delete: true) do |x, _|
55
+ paths_to_build << x.delete_prefix('/')
56
+ end
57
+
58
+ result = Builder.build(paths_to_build.join(';'), base_url: request.base_url)
59
+
60
+ # Remove the react components from the results, so they are not side loaded. Instead they
61
+ # are lazy loaded by the component manager.
62
+
63
+ scripts = {}
64
+ result.split(';').each do |x|
65
+ inpath, outpath = x.split('::')
66
+ inpath.prepend '/'
67
+ outpath.delete_prefix! 'public'
68
+
69
+ next unless imports.key?(inpath)
70
+
71
+ if (import = imports[inpath]).delete(:lazy)
72
+ scripts[inpath] = import.merge(outpath: outpath)
73
+ else
74
+ out << javascript_include_tag(outpath, extname: false, **options)
75
+ end
76
+ end
77
+
78
+ if extract_lazy_scripts
79
+ content_for :proscenium_lazy_scripts do
80
+ tag.script type: 'application/json', id: 'prosceniumLazyScripts' do
81
+ raw scripts.to_json
82
+ end
83
+ end
84
+ else
85
+ out << tag.script(type: 'application/json', id: 'prosceniumLazyScripts') do
86
+ raw scripts.to_json
87
+ end
88
+ end
89
+ else
90
+ Importer.each_javascript(delete: true) do |path, _|
91
+ out << javascript_include_tag(path, extname: false, **options)
92
+ end
93
+ end
94
+
95
+ out.join("\n").html_safe
96
+ end
97
+ alias side_load_javascripts include_javascripts
98
+ deprecate side_load_javascripts: 'Use `include_javascripts` instead', deprecator: Deprecator.new
99
+
100
+ def declare_lazy_scripts
101
+ content_for :proscenium_lazy_scripts
102
+ end
18
103
  end
19
104
  end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/current_attributes'
4
+
5
+ module Proscenium
6
+ class Importer < ActiveSupport::CurrentAttributes
7
+ JS_EXTENSIONS = %w[.tsx .ts .jsx .js].freeze
8
+ CSS_EXTENSIONS = %w[.module.css .css].freeze
9
+
10
+ # Holds the JS and CSS files to include in the current request.
11
+ #
12
+ # Example:
13
+ # {
14
+ # '/path/to/input/file.js': {
15
+ # output: '/path/to/compiled/file.js',
16
+ # **options
17
+ # }
18
+ # }
19
+ attribute :imported
20
+
21
+ class << self
22
+ # Import the given `filepath`. This is idempotent - it will never include duplicates.
23
+ #
24
+ # @param filepath [String] Absolute URL path (relative to Rails root) of the file to import.
25
+ # Should be the actual asset file, eg. app.css, some/component.js.
26
+ # @param resolve [String] description of the file to resolve and import.
27
+ # @return [String] the digest of the imported file path if a css module (*.module.css).
28
+ def import(filepath = nil, resolve: nil, **options)
29
+ self.imported ||= {}
30
+
31
+ filepath = Resolver.resolve(resolve) if !filepath && resolve
32
+ css_module = filepath.end_with?('.module.css')
33
+
34
+ unless self.imported.key?(filepath)
35
+ # ActiveSupport::Notifications.instrument('sideload.proscenium', identifier: value)
36
+
37
+ self.imported[filepath] = { **options }
38
+ self.imported[filepath][:digest] = Utils.digest(filepath) if css_module
39
+ end
40
+
41
+ css_module ? self.imported[filepath][:digest] : nil
42
+ end
43
+
44
+ # Sideloads JS and CSS assets for the given Ruby filepath.
45
+ #
46
+ # Any files with the same base name and matching a supported extension will be sideloaded.
47
+ # Only one JS and one CSS file will be sideloaded, with the first match used in the following
48
+ # order:
49
+ # - JS extensions: .tsx, .ts, .jsx, and .js.
50
+ # - CSS extensions: .css.module, and .css.
51
+ #
52
+ # Example:
53
+ # - `app/views/layouts/application.rb`
54
+ # - `app/views/layouts/application.css`
55
+ # - `app/views/layouts/application.js`
56
+ # - `app/views/layouts/application.tsx`
57
+ #
58
+ # A request to sideload `app/views/layouts/application.rb` will result in `application.css`
59
+ # and `application.tsx` being sideloaded. `application.js` will not be sideloaded because the
60
+ # `.tsx` extension is matched first.
61
+ #
62
+ # @param filepath [Pathname] Absolute file system path of the Ruby file to sideload.
63
+ def sideload(filepath, **options)
64
+ return unless Proscenium.config.side_load
65
+
66
+ filepath = Rails.root.join(filepath) unless filepath.is_a?(Pathname)
67
+ filepath = filepath.sub_ext('')
68
+
69
+ import_if_exists = lambda do |x|
70
+ if (fp = filepath.sub_ext(x)).exist?
71
+ import(Resolver.resolve(fp.to_s), sideloaded: true, **options)
72
+ end
73
+ end
74
+
75
+ JS_EXTENSIONS.find(&import_if_exists)
76
+ CSS_EXTENSIONS.find(&import_if_exists)
77
+ end
78
+
79
+ def each_stylesheet(delete: false)
80
+ return if imported.blank?
81
+
82
+ blk = proc { |key, options| key.end_with?(*CSS_EXTENSIONS) && yield(key, options) }
83
+ delete ? imported.delete_if(&blk) : imported.each(&blk)
84
+ end
85
+
86
+ def each_javascript(delete: false)
87
+ return if imported.blank?
88
+
89
+ blk = proc { |key, options| key.end_with?(*JS_EXTENSIONS) && yield(key, options) }
90
+ delete ? imported.delete_if(&blk) : imported.each(&blk)
91
+ end
92
+
93
+ def css_imported?
94
+ imported&.keys&.any? { |x| x.end_with?(*CSS_EXTENSIONS) }
95
+ end
96
+
97
+ def js_imported?
98
+ imported&.keys&.any? { |x| x.end_with?(*JS_EXTENSIONS) }
99
+ end
100
+
101
+ def multiple_js_imported?
102
+ imported&.keys&.many? { |x| x.end_with?(*JS_EXTENSIONS) }
103
+ end
104
+
105
+ def imported?(filepath = nil)
106
+ filepath ? imported&.key?(filepath) : !imported.blank?
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,101 @@
1
+ window.Proscenium = window.Proscenium || { lazyScripts: {} };
2
+
3
+ const element = document.querySelector("#prosceniumLazyScripts");
4
+ if (element) {
5
+ const scripts = JSON.parse(element.text);
6
+ window.Proscenium.lazyScripts = {
7
+ ...window.Proscenium.lazyScripts,
8
+ ...scripts,
9
+ };
10
+ }
11
+
12
+ const elements = document.querySelectorAll("[data-proscenium-component-path]");
13
+ elements.length > 0 && init(elements);
14
+
15
+ function init() {
16
+ /**
17
+ * Mounts component located at `path`, into the DOM `element`.
18
+ *
19
+ * The element at which the component is mounted must have the following data attributes:
20
+ *
21
+ * - `data-proscenium-component-path`: The URL path to the component's source file.
22
+ * - `data-proscenium-component-props`: JSON object of props to pass to the component.
23
+ * - `data-proscenium-component-lazy`: If present, will lazily load the component when in view
24
+ * using IntersectionObserver.
25
+ * - `data-proscenium-component-forward-children`: If the element should forward its `innerHTML`
26
+ * as the component's children prop.
27
+ */
28
+ function mount(element, path, { children, ...props }) {
29
+ // For testing and simulation of slow connections.
30
+ // const sim = new Promise((resolve) => setTimeout(resolve, 5000));
31
+
32
+ if (!window.Proscenium.lazyScripts[path]) {
33
+ throw `[proscenium/react/manager] Cannot load component ${path} (not found in Proscenium.lazyScripts)`;
34
+ }
35
+
36
+ const react = import("@proscenium/react-manager/react");
37
+ const Component = import(window.Proscenium.lazyScripts[path].outpath);
38
+
39
+ const forwardChildren =
40
+ "prosceniumComponentForwardChildren" in element.dataset &&
41
+ element.innerHTML !== "";
42
+
43
+ Promise.all([react, Component])
44
+ .then(([r, c]) => {
45
+ if (proscenium.env.RAILS_ENV === "development") {
46
+ console.groupCollapsed(
47
+ `[proscenium/react/manager] 🔥 %o mounted!`,
48
+ path
49
+ );
50
+ console.log("props: %o", props);
51
+ console.groupEnd();
52
+ }
53
+
54
+ let component;
55
+ if (forwardChildren) {
56
+ component = r.createElement(c.default, props, element.innerHTML);
57
+ } else if (children) {
58
+ component = r.createElement(c.default, props, children);
59
+ } else {
60
+ component = r.createElement(c.default, props);
61
+ }
62
+
63
+ r.createRoot(element).render(component);
64
+ })
65
+ .catch((error) => {
66
+ console.error("[proscenium/react/manager] %o - %o", path, error);
67
+ });
68
+ }
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
+ }
@@ -0,0 +1,2 @@
1
+ export { createElement } from "react";
2
+ export { createRoot } from "react-dom/client";
@@ -0,0 +1 @@
1
+ console.log("/@proscenium/test.js");
@@ -34,12 +34,12 @@ module Proscenium
34
34
  private
35
35
 
36
36
  def real_path
37
- @request.path
37
+ @real_path ||= @request.path
38
38
  end
39
39
 
40
40
  # @return [String] the path to the file without the leading slash which will be built.
41
41
  def path_to_build
42
- @request.path[1..]
42
+ @path_to_build ||= @request.path[1..]
43
43
  end
44
44
 
45
45
  def sourcemap?
@@ -53,22 +53,22 @@ module Proscenium
53
53
  def file_readable?
54
54
  return false unless (path = clean_path(sourcemap? ? real_path[0...-4] : real_path))
55
55
 
56
- file_stat = File.stat(Pathname(root).join(path.delete_prefix('/').b).to_s)
56
+ file_stat = File.stat(root_for_readable.join(path.delete_prefix('/').b).to_s)
57
57
  rescue SystemCallError
58
58
  false
59
59
  else
60
60
  file_stat.file? && file_stat.readable?
61
61
  end
62
62
 
63
+ def root_for_readable
64
+ Rails.root
65
+ end
66
+
63
67
  def clean_path(file)
64
68
  path = Rack::Utils.unescape_path file.chomp('/').delete_prefix('/')
65
69
  Rack::Utils.clean_path_info path if Rack::Utils.valid_path? path
66
70
  end
67
71
 
68
- def root
69
- @root ||= Rails.root.to_s
70
- end
71
-
72
72
  def content_type
73
73
  case ::File.extname(path_to_build)
74
74
  when '.js', '.mjs', '.ts', '.tsx', '.jsx' then 'application/javascript'
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Proscenium
4
+ class Middleware
5
+ # This middleware handles requests for assets in Rails engines. An engine that wants to expose
6
+ # its assets via Proscenium to the application must add itself to the list of engines in the
7
+ # Proscenium config options `Proscenium.config.engines`.
8
+ #
9
+ # For example, we have a gem that exposes a Rails engine.
10
+ #
11
+ # module Gem1
12
+ # class Engine < ::Rails::Engine
13
+ # config.proscenium.engines << self
14
+ # end
15
+ # end
16
+ #
17
+ # When this gem is installed in any Rails application, its assets will be available at the URL
18
+ # `/gem1/...`. For example, if the gem has a file `lib/styles.css`, it can be requested at
19
+ # `/gem1/lib/styles.css`.
20
+ #
21
+ class Engines < Esbuild
22
+ def real_path
23
+ @real_path ||= Pathname.new(@request.path.delete_prefix("/#{engine.engine_name}")).to_s
24
+ end
25
+
26
+ def root_for_readable
27
+ engine.root
28
+ end
29
+
30
+ def engine
31
+ @engine ||= Proscenium.config.engines.find do |engine|
32
+ @request.path.start_with?("/#{engine.engine_name}")
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -20,11 +20,9 @@ module Proscenium
20
20
  end
21
21
 
22
22
  def attempt
23
- ActiveSupport::Notifications.instrument('build.proscenium', identifier: path_to_build) do
24
- render_response Proscenium::Builder.build(path_to_build, root: root,
25
- base_url: @request.base_url)
26
- end
27
- rescue Proscenium::Builder::CompileError => e
23
+ render_response Builder.build(path_to_build, root: Rails.root.to_s,
24
+ base_url: @request.base_url)
25
+ rescue Builder::CompileError => e
28
26
  raise self.class::CompileError, { file: @request.fullpath, detail: e.message }, caller
29
27
  end
30
28
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Proscenium
4
+ class Middleware
5
+ class Runtime < Esbuild
6
+ private
7
+
8
+ def real_path
9
+ @real_path ||= Pathname.new(@request.path.sub(%r{^/@proscenium},
10
+ '/lib/proscenium/libs')).to_s
11
+ end
12
+
13
+ def root_for_readable
14
+ Proscenium::Railtie.root
15
+ end
16
+ end
17
+ end
18
+ end
@@ -9,6 +9,8 @@ module Proscenium
9
9
 
10
10
  autoload :Base
11
11
  autoload :Esbuild
12
+ autoload :Engines
13
+ autoload :Runtime
12
14
  autoload :Url
13
15
 
14
16
  def initialize(app)
@@ -40,12 +42,20 @@ module Proscenium
40
42
 
41
43
  def find_type(request)
42
44
  return Url if request.path.match?(%r{^/https?%3A%2F%2F})
43
- return Esbuild if Pathname.new(request.path).fnmatch?(path_glob, File::FNM_EXTGLOB)
45
+ return Runtime if request.path.match?(%r{^/@proscenium/})
46
+ return Esbuild if Pathname.new(request.path).fnmatch?(app_path_glob, File::FNM_EXTGLOB)
47
+
48
+ Engines if Pathname.new(request.path).fnmatch?(engines_path_glob, File::FNM_EXTGLOB)
49
+ end
50
+
51
+ def app_path_glob
52
+ "/{#{Proscenium::ALLOWED_DIRECTORIES}}/**.{#{FILE_EXTENSIONS.join(',')}}"
44
53
  end
45
54
 
46
- def path_glob
47
- paths = Rails.application.config.proscenium.include_paths.join(',')
48
- "/{#{paths}}/**.{#{FILE_EXTENSIONS.join(',')}}"
55
+ def engines_path_glob
56
+ names = Proscenium.config.engines.map(&:engine_name)
57
+
58
+ "/{#{names.join(',')}}/{#{Proscenium::ALLOWED_DIRECTORIES}}/**.{#{FILE_EXTENSIONS.join(',')}}"
49
59
  end
50
60
 
51
61
  # TODO: handle precompiled assets
@@ -1,12 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Proscenium::SideLoad
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
+
6
14
  module TemplateRenderer
7
15
  private
8
16
 
9
17
  def render_template(view, template, layout_name, locals)
18
+ return super unless Proscenium.config.side_load
19
+
10
20
  layout = find_layout(layout_name, locals.keys, [formats.first])
11
21
  renderable = template.instance_variable_get(:@renderable)
12
22
 
@@ -14,18 +24,18 @@ class Proscenium::SideLoad
14
24
  template.is_a?(ActionView::Template::Renderable) &&
15
25
  renderable.class < ::ViewComponent::Base && renderable.class.format == :html
16
26
  # Side load controller rendered ViewComponent
17
- Proscenium::SideLoad.append "app/views/#{layout.virtual_path}" if layout
18
- Proscenium::SideLoad.append "app/views/#{renderable.virtual_path}"
27
+ Importer.sideload "app/views/#{layout.virtual_path}" if layout
28
+ Importer.sideload "app/views/#{renderable.virtual_path}"
19
29
  elsif template.respond_to?(:virtual_path) &&
20
30
  template.respond_to?(:type) && template.type == :html
21
- Proscenium::SideLoad.append "app/views/#{layout.virtual_path}" if layout
31
+ Importer.sideload "app/views/#{layout.virtual_path}" if layout
22
32
 
23
33
  # Try side loading the variant template
24
34
  if template.respond_to?(:variant) && template.variant
25
- Proscenium::SideLoad.append "app/views/#{template.virtual_path}+#{template.variant}"
35
+ Importer.sideload "app/views/#{template.virtual_path}+#{template.variant}"
26
36
  end
27
37
 
28
- Proscenium::SideLoad.append "app/views/#{template.virtual_path}"
38
+ Importer.sideload "app/views/#{template.virtual_path}"
29
39
  end
30
40
 
31
41
  super
@@ -36,20 +46,14 @@ class Proscenium::SideLoad
36
46
  private
37
47
 
38
48
  def render_partial_template(view, locals, template, layout, block)
39
- if template.respond_to?(:virtual_path) &&
49
+ if Proscenium.config.side_load && template.respond_to?(:virtual_path) &&
40
50
  template.respond_to?(:type) && template.type == :html
41
- Proscenium::SideLoad.append "app/views/#{layout.virtual_path}" if layout
42
- Proscenium::SideLoad.append "app/views/#{template.virtual_path}"
51
+ Importer.sideload "app/views/#{layout.virtual_path}" if layout
52
+ Importer.sideload "app/views/#{template.virtual_path}"
43
53
  end
44
54
 
45
55
  super
46
56
  end
47
-
48
- def build_rendered_template(content, template)
49
- path = Rails.root.join('app', 'views', template.virtual_path)
50
- cssm = Proscenium::CssModule::Resolver.new(path)
51
- super cssm.compile_class_names(content), template
52
- end
53
57
  end
54
58
  end
55
59
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity