proscenium 0.10.0-x86_64-linux → 0.11.0.pre.2-x86_64-linux
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.
- checksums.yaml +4 -4
- data/README.md +175 -39
- data/lib/proscenium/builder.rb +17 -11
- data/lib/proscenium/css_module/path.rb +31 -0
- data/lib/proscenium/css_module/transformer.rb +76 -0
- data/lib/proscenium/css_module.rb +6 -28
- data/lib/proscenium/ensure_loaded.rb +27 -0
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/ext/proscenium.h +2 -1
- data/lib/proscenium/helper.rb +62 -0
- data/lib/proscenium/importer.rb +110 -0
- data/lib/proscenium/libs/react-manager/index.jsx +88 -0
- data/lib/proscenium/libs/react-manager/react.js +2 -0
- data/lib/proscenium/libs/test.js +1 -0
- data/lib/proscenium/middleware/base.rb +2 -2
- data/lib/proscenium/middleware/esbuild.rb +2 -4
- data/lib/proscenium/middleware/runtime.rb +18 -0
- data/lib/proscenium/middleware.rb +4 -1
- data/lib/proscenium/{side_load/monkey.rb → monkey.rb} +11 -15
- data/lib/proscenium/phlex/{resolve_css_modules.rb → css_modules.rb} +6 -20
- data/lib/proscenium/phlex/page.rb +2 -2
- data/lib/proscenium/phlex/react_component.rb +26 -27
- data/lib/proscenium/phlex.rb +10 -29
- data/lib/proscenium/railtie.rb +14 -26
- data/lib/proscenium/react_componentable.rb +94 -0
- data/lib/proscenium/resolver.rb +41 -0
- data/lib/proscenium/side_load.rb +13 -73
- data/lib/proscenium/source_path.rb +15 -0
- data/lib/proscenium/utils.rb +13 -0
- data/lib/proscenium/version.rb +1 -1
- data/lib/proscenium/view_component/css_modules.rb +11 -0
- data/lib/proscenium/view_component/react_component.rb +15 -15
- data/lib/proscenium/view_component/sideload.rb +4 -0
- data/lib/proscenium/view_component.rb +8 -38
- data/lib/proscenium.rb +23 -68
- metadata +21 -29
- data/lib/proscenium/componentable.rb +0 -63
- data/lib/proscenium/css_module/class_names_resolver.rb +0 -66
- data/lib/proscenium/css_module/resolver.rb +0 -76
- data/lib/proscenium/current.rb +0 -9
- data/lib/proscenium/phlex/component_concerns.rb +0 -9
- data/lib/proscenium/side_load/ensure_loaded.rb +0 -25
- data/lib/proscenium/side_load/helper.rb +0 -41
- data/lib/proscenium/view_component/tag_builder.rb +0 -23
@@ -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 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,88 @@
|
|
1
|
+
const elements = document.querySelectorAll("[data-proscenium-component-path]");
|
2
|
+
|
3
|
+
// Initialize only if there are components.
|
4
|
+
elements.length > 0 && init();
|
5
|
+
|
6
|
+
function init() {
|
7
|
+
/**
|
8
|
+
* Mounts component located at `path`, into the DOM `element`.
|
9
|
+
*
|
10
|
+
* The element at which the component is mounted must have the following data attributes:
|
11
|
+
*
|
12
|
+
* - `data-proscenium-component-path`: The URL path to the component's source file.
|
13
|
+
* - `data-proscenium-component-props`: JSON object of props to pass to the component.
|
14
|
+
* - `data-proscenium-component-lazy`: If present, will lazily load the component when in view
|
15
|
+
* using IntersectionObserver.
|
16
|
+
* - `data-proscenium-component-forward-children`: If the element should forward its `innerHTML`
|
17
|
+
* as the component's children prop.
|
18
|
+
*/
|
19
|
+
function mount(element, path, { children, ...props }) {
|
20
|
+
// For testing and simulation of slow connections.
|
21
|
+
// const sim = new Promise((resolve) => setTimeout(resolve, 5000));
|
22
|
+
|
23
|
+
if (!(path in window.prosceniumLazyScripts)) {
|
24
|
+
throw `[proscenium/react/manager] Cannot load component ${path} (not found in prosceniumLazyScripts)`;
|
25
|
+
}
|
26
|
+
|
27
|
+
const react = import("@proscenium/react-manager/react");
|
28
|
+
const Component = import(window.prosceniumLazyScripts[path].outpath);
|
29
|
+
|
30
|
+
const forwardChildren =
|
31
|
+
"prosceniumComponentForwardChildren" in element.dataset &&
|
32
|
+
element.innerHTML !== "";
|
33
|
+
|
34
|
+
Promise.all([react, Component]).then(([r, c]) => {
|
35
|
+
if (proscenium.env.RAILS_ENV === "development") {
|
36
|
+
console.groupCollapsed(
|
37
|
+
`[proscenium/react/manager] 🔥 %o mounted!`,
|
38
|
+
path
|
39
|
+
);
|
40
|
+
console.log("props: %o", props);
|
41
|
+
console.groupEnd();
|
42
|
+
}
|
43
|
+
|
44
|
+
let component;
|
45
|
+
if (forwardChildren) {
|
46
|
+
component = r.createElement(c.default, props, element.innerHTML);
|
47
|
+
} else if (children) {
|
48
|
+
component = r.createElement(c.default, props, children);
|
49
|
+
} else {
|
50
|
+
component = r.createElement(c.default, props);
|
51
|
+
}
|
52
|
+
|
53
|
+
r.createRoot(element).render(component);
|
54
|
+
});
|
55
|
+
}
|
56
|
+
|
57
|
+
Array.from(elements, (element) => {
|
58
|
+
const path = element.dataset.prosceniumComponentPath;
|
59
|
+
const isLazy = "prosceniumComponentLazy" in element.dataset;
|
60
|
+
const props = JSON.parse(element.dataset.prosceniumComponentProps);
|
61
|
+
|
62
|
+
if (proscenium.env.RAILS_ENV === "development") {
|
63
|
+
console.groupCollapsed(
|
64
|
+
`[proscenium/react/manager] ${isLazy ? "💤" : "⚡️"} %o`,
|
65
|
+
path
|
66
|
+
);
|
67
|
+
console.log("element: %o", element);
|
68
|
+
console.log("props: %o", props);
|
69
|
+
console.groupEnd();
|
70
|
+
}
|
71
|
+
|
72
|
+
if (isLazy) {
|
73
|
+
const observer = new IntersectionObserver((entries) => {
|
74
|
+
entries.forEach((entry) => {
|
75
|
+
if (entry.isIntersecting) {
|
76
|
+
observer.unobserve(element);
|
77
|
+
|
78
|
+
mount(element, path, props);
|
79
|
+
}
|
80
|
+
});
|
81
|
+
});
|
82
|
+
|
83
|
+
observer.observe(element);
|
84
|
+
} else {
|
85
|
+
mount(element, path, props);
|
86
|
+
}
|
87
|
+
});
|
88
|
+
}
|
@@ -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?
|
@@ -20,10 +20,8 @@ module Proscenium
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def attempt
|
23
|
-
|
24
|
-
|
25
|
-
base_url: @request.base_url)
|
26
|
-
end
|
23
|
+
render_response Proscenium::Builder.build(path_to_build, root: root,
|
24
|
+
base_url: @request.base_url)
|
27
25
|
rescue Proscenium::Builder::CompileError => e
|
28
26
|
raise self.class::CompileError, { file: @request.fullpath, detail: e.message }, caller
|
29
27
|
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
|
14
|
+
@root ||= Proscenium::Railtie.root.to_s
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -9,6 +9,7 @@ module Proscenium
|
|
9
9
|
|
10
10
|
autoload :Base
|
11
11
|
autoload :Esbuild
|
12
|
+
autoload :Runtime
|
12
13
|
autoload :Url
|
13
14
|
|
14
15
|
def initialize(app)
|
@@ -40,7 +41,9 @@ module Proscenium
|
|
40
41
|
|
41
42
|
def find_type(request)
|
42
43
|
return Url if request.path.match?(%r{^/https?%3A%2F%2F})
|
43
|
-
return
|
44
|
+
return Runtime if request.path.match?(%r{^/@proscenium/})
|
45
|
+
|
46
|
+
Esbuild if Pathname.new(request.path).fnmatch?(path_glob, File::FNM_EXTGLOB)
|
44
47
|
end
|
45
48
|
|
46
49
|
def path_glob
|
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
module Proscenium
|
4
4
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
5
5
|
module Monkey
|
6
6
|
module TemplateRenderer
|
7
7
|
private
|
8
8
|
|
9
9
|
def render_template(view, template, layout_name, locals)
|
10
|
+
return super unless Proscenium.config.side_load
|
11
|
+
|
10
12
|
layout = find_layout(layout_name, locals.keys, [formats.first])
|
11
13
|
renderable = template.instance_variable_get(:@renderable)
|
12
14
|
|
@@ -14,18 +16,18 @@ class Proscenium::SideLoad
|
|
14
16
|
template.is_a?(ActionView::Template::Renderable) &&
|
15
17
|
renderable.class < ::ViewComponent::Base && renderable.class.format == :html
|
16
18
|
# Side load controller rendered ViewComponent
|
17
|
-
|
18
|
-
|
19
|
+
Importer.sideload "app/views/#{layout.virtual_path}" if layout
|
20
|
+
Importer.sideload "app/views/#{renderable.virtual_path}"
|
19
21
|
elsif template.respond_to?(:virtual_path) &&
|
20
22
|
template.respond_to?(:type) && template.type == :html
|
21
|
-
|
23
|
+
Importer.sideload "app/views/#{layout.virtual_path}" if layout
|
22
24
|
|
23
25
|
# Try side loading the variant template
|
24
26
|
if template.respond_to?(:variant) && template.variant
|
25
|
-
|
27
|
+
Importer.sideload "app/views/#{template.virtual_path}+#{template.variant}"
|
26
28
|
end
|
27
29
|
|
28
|
-
|
30
|
+
Importer.sideload "app/views/#{template.virtual_path}"
|
29
31
|
end
|
30
32
|
|
31
33
|
super
|
@@ -36,20 +38,14 @@ class Proscenium::SideLoad
|
|
36
38
|
private
|
37
39
|
|
38
40
|
def render_partial_template(view, locals, template, layout, block)
|
39
|
-
if template.respond_to?(:virtual_path) &&
|
41
|
+
if Proscenium.config.side_load && template.respond_to?(:virtual_path) &&
|
40
42
|
template.respond_to?(:type) && template.type == :html
|
41
|
-
|
42
|
-
|
43
|
+
Importer.sideload "app/views/#{layout.virtual_path}" if layout
|
44
|
+
Importer.sideload "app/views/#{template.virtual_path}"
|
43
45
|
end
|
44
46
|
|
45
47
|
super
|
46
48
|
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
49
|
end
|
54
50
|
end
|
55
51
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
@@ -1,16 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Proscenium
|
4
|
-
module Phlex::
|
5
|
-
|
4
|
+
module Phlex::CssModules
|
5
|
+
include Proscenium::CssModule
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
def before_template
|
12
|
-
self.class.side_load_cache ||= Set.new
|
13
|
-
super
|
7
|
+
def self.included(base)
|
8
|
+
base.extend CssModule::Path
|
14
9
|
end
|
15
10
|
|
16
11
|
# Resolve and side load any CSS modules in the "class" attributes, where a CSS module is a class
|
@@ -44,24 +39,15 @@ module Proscenium
|
|
44
39
|
# end
|
45
40
|
# end
|
46
41
|
#
|
47
|
-
# The given class name should be underscored, and the resulting CSS module name will be
|
48
|
-
# `camelCased` with a lower case first character.
|
49
|
-
#
|
50
42
|
# @raise [Proscenium::CssModule::Resolver::NotFound] If a CSS module file is not found for the
|
51
43
|
# Phlex class file path.
|
52
44
|
def process_attributes(**attributes)
|
53
45
|
if attributes.key?(:class) && (attributes[:class] = tokens(attributes[:class])).include?('@')
|
54
|
-
|
55
|
-
|
56
|
-
attributes[:class] = resolver.class_names
|
46
|
+
names = attributes[:class].is_a?(Array) ? attributes[:class] : attributes[:class].split
|
47
|
+
attributes[:class] = cssm.class_names(*names)
|
57
48
|
end
|
58
49
|
|
59
50
|
attributes
|
60
51
|
end
|
61
|
-
|
62
|
-
def after_template
|
63
|
-
super
|
64
|
-
self.class.side_load_cache&.each { |path| SideLoad.append! path, :css }
|
65
|
-
end
|
66
52
|
end
|
67
53
|
end
|
@@ -32,7 +32,7 @@ module Proscenium::Phlex::Page
|
|
32
32
|
|
33
33
|
def after_template
|
34
34
|
super
|
35
|
-
@_buffer.gsub!('<!-- [SIDE_LOAD_STYLESHEETS] -->', capture {
|
35
|
+
@_buffer.gsub!('<!-- [SIDE_LOAD_STYLESHEETS] -->', capture { include_stylesheets })
|
36
36
|
end
|
37
37
|
|
38
38
|
def page_title
|
@@ -56,7 +56,7 @@ module Proscenium::Phlex::Page
|
|
56
56
|
super do
|
57
57
|
yield if block_given?
|
58
58
|
|
59
|
-
|
59
|
+
include_javascripts type: :module, defer: true
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -1,33 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
# Renders a <div> for use with React components, with data attributes specifying the component
|
5
|
-
# and props.
|
6
|
-
#
|
7
|
-
# If a block is given, it will be yielded within the div, allowing for a custom "loading" UI. If no
|
8
|
-
# block is given, then a "loading..." text will be rendered. It is intended that the component is
|
9
|
-
# mounted to this div, and the loading UI will then be replaced with the component's rendered
|
10
|
-
# output.
|
11
|
-
#
|
12
|
-
# You can pass props to the component in the `:props` keyword argument.
|
13
|
-
#
|
14
|
-
class Proscenium::Phlex::ReactComponent < Proscenium::Phlex
|
15
|
-
self.abstract_class = true
|
16
|
-
|
17
|
-
include Proscenium::Componentable
|
18
|
-
include Proscenium::Phlex::ComponentConcerns::CssModules
|
19
|
-
|
20
|
-
# Override this to provide your own loading UI.
|
3
|
+
module Proscenium
|
4
|
+
# Renders a <div> for use with React components, with data attributes specifying the component
|
5
|
+
# path and props.
|
21
6
|
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# end
|
27
|
-
# end
|
7
|
+
# If a block is given, it will be yielded within the div, allowing for a custom "loading" UI. If
|
8
|
+
# no block is given, then a "loading..." text will be rendered. It is intended that the component
|
9
|
+
# is mounted to this div, and the loading UI will then be replaced with the component's rendered
|
10
|
+
# output.
|
28
11
|
#
|
29
|
-
#
|
30
|
-
|
31
|
-
|
12
|
+
# You can pass props to the component in the `:props` keyword argument.
|
13
|
+
class Phlex::ReactComponent < Phlex
|
14
|
+
self.abstract_class = true
|
15
|
+
|
16
|
+
include ReactComponentable
|
17
|
+
|
18
|
+
# Override this to provide your own loading UI.
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# def template(**attributes, &block)
|
22
|
+
# super do
|
23
|
+
# 'Look at me! I am loading now...'
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @yield the given block to a `div` within the top level component div.
|
28
|
+
def template(**attributes, &block)
|
29
|
+
send root_tag, **{ data: data_attributes }.deep_merge(attributes), &block
|
30
|
+
end
|
32
31
|
end
|
33
32
|
end
|
data/lib/proscenium/phlex.rb
CHANGED
@@ -5,54 +5,35 @@ require 'phlex-rails'
|
|
5
5
|
module Proscenium
|
6
6
|
class Phlex < ::Phlex::HTML
|
7
7
|
extend ActiveSupport::Autoload
|
8
|
-
include Proscenium::CssModule
|
9
8
|
|
10
9
|
autoload :Page
|
10
|
+
autoload :CssModules
|
11
11
|
autoload :ReactComponent
|
12
|
-
autoload :ResolveCssModules
|
13
|
-
autoload :ComponentConcerns
|
14
12
|
|
15
13
|
extend ::Phlex::Rails::HelperMacros
|
16
14
|
include ::Phlex::Rails::Helpers::JavaScriptIncludeTag
|
17
15
|
include ::Phlex::Rails::Helpers::StyleSheetLinkTag
|
16
|
+
include Proscenium::SourcePath
|
17
|
+
include CssModules
|
18
18
|
|
19
|
-
define_output_helper :side_load_stylesheets
|
20
|
-
define_output_helper :
|
19
|
+
define_output_helper :side_load_stylesheets # deprecated
|
20
|
+
define_output_helper :include_stylesheets
|
21
|
+
define_output_helper :side_load_javascripts # deprecated
|
22
|
+
define_output_helper :include_javascripts
|
21
23
|
|
22
|
-
# Side loads the class, and its super classes that respond to `.path`. Assign the
|
23
|
-
# `abstract_class` class variable to any abstract class, and it will not be side loaded.
|
24
|
-
# Additionally, if the class responds to `side_load`, then that method is called.
|
25
24
|
module Sideload
|
26
25
|
def before_template
|
27
|
-
|
28
|
-
|
29
|
-
if !klass.abstract_class && respond_to?(:side_load, true)
|
30
|
-
side_load
|
31
|
-
klass = klass.superclass
|
32
|
-
end
|
33
|
-
|
34
|
-
while !klass.abstract_class && klass.respond_to?(:path) && klass.path
|
35
|
-
Proscenium::SideLoad.append klass.path
|
36
|
-
klass = klass.superclass
|
37
|
-
end
|
26
|
+
Proscenium::SideLoad.sideload_inheritance_chain self
|
38
27
|
|
39
28
|
super
|
40
29
|
end
|
41
30
|
end
|
42
31
|
|
43
32
|
class << self
|
44
|
-
attr_accessor :
|
33
|
+
attr_accessor :abstract_class
|
45
34
|
|
46
35
|
def inherited(child)
|
47
|
-
|
48
|
-
child.path = if caller_locations(1, 1).first.label == 'inherited'
|
49
|
-
Pathname.new caller_locations(2, 1).first.path
|
50
|
-
else
|
51
|
-
Pathname.new caller_locations(1, 1).first.path
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
child.prepend Sideload if Rails.application.config.proscenium.side_load
|
36
|
+
child.prepend Sideload
|
56
37
|
|
57
38
|
super
|
58
39
|
end
|
data/lib/proscenium/railtie.rb
CHANGED
@@ -6,14 +6,6 @@ require 'proscenium/log_subscriber'
|
|
6
6
|
ENV['RAILS_ENV'] = Rails.env
|
7
7
|
|
8
8
|
module Proscenium
|
9
|
-
FILE_EXTENSIONS = ['js', 'mjs', 'ts', 'jsx', 'tsx', 'css', 'js.map', 'mjs.map', 'jsx.map',
|
10
|
-
'ts.map', 'tsx.map', 'css.map'].freeze
|
11
|
-
|
12
|
-
APPLICATION_INCLUDE_PATHS = ['config', 'app/assets', 'app/views', 'lib', 'node_modules'].freeze
|
13
|
-
|
14
|
-
# Environment variables that should always be passed to the builder.
|
15
|
-
DEFAULT_ENV_VARS = Set['RAILS_ENV', 'NODE_ENV'].freeze
|
16
|
-
|
17
9
|
class << self
|
18
10
|
def config
|
19
11
|
@config ||= Railtie.config.proscenium
|
@@ -26,10 +18,12 @@ module Proscenium
|
|
26
18
|
config.proscenium = ActiveSupport::OrderedOptions.new
|
27
19
|
config.proscenium.debug = false
|
28
20
|
config.proscenium.side_load = true
|
29
|
-
config.proscenium.code_splitting =
|
21
|
+
config.proscenium.code_splitting = true
|
22
|
+
config.proscenium.include_paths = Set.new(APPLICATION_INCLUDE_PATHS)
|
23
|
+
|
24
|
+
# TODO: implement!
|
30
25
|
config.proscenium.cache_query_string = Rails.env.production? && ENV.fetch('REVISION', nil)
|
31
26
|
config.proscenium.cache_max_age = 2_592_000 # 30 days
|
32
|
-
config.proscenium.include_paths = Set.new(APPLICATION_INCLUDE_PATHS)
|
33
27
|
|
34
28
|
# List of environment variable names that should be passed to the builder, which will then be
|
35
29
|
# passed to esbuild's `Define` option. Being explicit about which environment variables are
|
@@ -60,31 +54,25 @@ module Proscenium
|
|
60
54
|
end
|
61
55
|
|
62
56
|
initializer 'proscenium.middleware' do |app|
|
63
|
-
app.middleware.insert_after ActionDispatch::Static,
|
57
|
+
app.middleware.insert_after ActionDispatch::Static, Middleware
|
64
58
|
app.middleware.insert_after ActionDispatch::Static, Rack::ETag, 'no-cache'
|
65
59
|
app.middleware.insert_after ActionDispatch::Static, Rack::ConditionalGet
|
66
60
|
end
|
67
61
|
|
68
|
-
initializer 'proscenium.
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
ActiveSupport.on_load(:action_view) do
|
73
|
-
ActionView::Base.include Proscenium::SideLoad::Helper
|
74
|
-
|
75
|
-
ActionView::TemplateRenderer.prepend SideLoad::Monkey::TemplateRenderer
|
76
|
-
ActionView::PartialRenderer.prepend SideLoad::Monkey::PartialRenderer
|
77
|
-
end
|
78
|
-
|
79
|
-
ActiveSupport.on_load(:action_controller) do
|
80
|
-
ActionController::Base.include Proscenium::SideLoad::EnsureLoaded
|
81
|
-
end
|
62
|
+
initializer 'proscenium.monkey_views' do
|
63
|
+
ActiveSupport.on_load(:action_view) do
|
64
|
+
ActionView::TemplateRenderer.prepend Monkey::TemplateRenderer
|
65
|
+
ActionView::PartialRenderer.prepend Monkey::PartialRenderer
|
82
66
|
end
|
83
67
|
end
|
84
68
|
|
85
69
|
initializer 'proscenium.helper' do
|
86
70
|
ActiveSupport.on_load(:action_view) do
|
87
|
-
ActionView::Base.include
|
71
|
+
ActionView::Base.include Helper
|
72
|
+
end
|
73
|
+
|
74
|
+
ActiveSupport.on_load(:action_controller) do
|
75
|
+
ActionController::Base.include EnsureLoaded
|
88
76
|
end
|
89
77
|
end
|
90
78
|
end
|