proscenium 0.6.0-x86_64-linux → 0.8.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 +126 -109
- data/lib/proscenium/css_module/class_names_resolver.rb +66 -0
- data/lib/proscenium/css_module/resolver.rb +76 -0
- data/lib/proscenium/css_module.rb +18 -39
- data/lib/proscenium/esbuild/golib.rb +97 -0
- data/lib/proscenium/esbuild.rb +32 -0
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/ext/proscenium.h +108 -0
- data/lib/proscenium/helper.rb +0 -23
- data/lib/proscenium/log_subscriber.rb +26 -0
- data/lib/proscenium/middleware/base.rb +28 -36
- data/lib/proscenium/middleware/esbuild.rb +18 -44
- data/lib/proscenium/middleware/url.rb +1 -6
- data/lib/proscenium/middleware.rb +12 -16
- data/lib/proscenium/phlex/component_concerns.rb +27 -0
- data/lib/proscenium/phlex/page.rb +62 -0
- data/lib/proscenium/phlex/react_component.rb +52 -8
- data/lib/proscenium/phlex/resolve_css_modules.rb +67 -0
- data/lib/proscenium/phlex.rb +34 -33
- data/lib/proscenium/railtie.rb +41 -67
- data/lib/proscenium/side_load/ensure_loaded.rb +25 -0
- data/lib/proscenium/side_load/helper.rb +25 -0
- data/lib/proscenium/side_load/monkey.rb +48 -0
- data/lib/proscenium/side_load.rb +58 -52
- data/lib/proscenium/version.rb +1 -1
- data/lib/proscenium/view_component/react_component.rb +14 -0
- data/lib/proscenium/view_component.rb +28 -18
- data/lib/proscenium.rb +79 -2
- metadata +35 -77
- data/app/channels/proscenium/connection.rb +0 -13
- data/app/channels/proscenium/reload_channel.rb +0 -9
- data/bin/esbuild +0 -0
- data/bin/lightningcss +0 -0
- data/config/routes.rb +0 -7
- data/lib/proscenium/compiler.js +0 -84
- data/lib/proscenium/compilers/esbuild/argument_error.js +0 -24
- data/lib/proscenium/compilers/esbuild/compile_error.js +0 -148
- data/lib/proscenium/compilers/esbuild/css/postcss.js +0 -67
- data/lib/proscenium/compilers/esbuild/css_plugin.js +0 -172
- data/lib/proscenium/compilers/esbuild/env_plugin.js +0 -46
- data/lib/proscenium/compilers/esbuild/http_bundle_plugin.js +0 -53
- data/lib/proscenium/compilers/esbuild/import_map/parser.js +0 -178
- data/lib/proscenium/compilers/esbuild/import_map/read.js +0 -64
- data/lib/proscenium/compilers/esbuild/import_map/resolver.js +0 -95
- data/lib/proscenium/compilers/esbuild/import_map/utils.js +0 -25
- data/lib/proscenium/compilers/esbuild/resolve_plugin.js +0 -207
- data/lib/proscenium/compilers/esbuild/setup_plugin.js +0 -45
- data/lib/proscenium/compilers/esbuild/solidjs_plugin.js +0 -24
- data/lib/proscenium/compilers/esbuild.bench.js +0 -14
- data/lib/proscenium/compilers/esbuild.js +0 -179
- data/lib/proscenium/link_to_helper.rb +0 -40
- data/lib/proscenium/middleware/lightningcss.rb +0 -64
- data/lib/proscenium/middleware/outside_root.rb +0 -26
- data/lib/proscenium/middleware/runtime.rb +0 -22
- data/lib/proscenium/middleware/static.rb +0 -14
- data/lib/proscenium/phlex/component.rb +0 -9
- data/lib/proscenium/precompile.rb +0 -31
- data/lib/proscenium/runtime/auto_reload.js +0 -40
- data/lib/proscenium/runtime/react_shim/index.js +0 -1
- data/lib/proscenium/runtime/react_shim/package.json +0 -5
- data/lib/proscenium/utils.js +0 -12
- data/lib/tasks/assets.rake +0 -19
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ffi'
|
4
|
+
require 'oj'
|
5
|
+
|
6
|
+
module Proscenium
|
7
|
+
class Esbuild::Golib
|
8
|
+
class Result < FFI::Struct
|
9
|
+
layout :success, :bool,
|
10
|
+
:response, :string
|
11
|
+
end
|
12
|
+
|
13
|
+
module Request
|
14
|
+
extend FFI::Library
|
15
|
+
ffi_lib Pathname.new(__dir__).join('../ext/proscenium').to_s
|
16
|
+
|
17
|
+
enum :environment, [:development, 1, :test, :production]
|
18
|
+
|
19
|
+
attach_function :build, [
|
20
|
+
:string, # path or entry point
|
21
|
+
:string, # root
|
22
|
+
:string, # base URL of the Rails app. eg. https://example.com
|
23
|
+
:environment, # Rails environment as a Symbol
|
24
|
+
:string, # path to import map, relative to root
|
25
|
+
:bool # debugging enabled?
|
26
|
+
], Result.by_value
|
27
|
+
|
28
|
+
attach_function :resolve, [
|
29
|
+
:string, # path or entry point
|
30
|
+
:string, # root
|
31
|
+
:environment, # Rails environment as a Symbol
|
32
|
+
:string # path to import map, relative to root
|
33
|
+
], Result.by_value
|
34
|
+
end
|
35
|
+
|
36
|
+
class BuildError < StandardError
|
37
|
+
attr_reader :error, :path
|
38
|
+
|
39
|
+
def initialize(path, error)
|
40
|
+
error = Oj.load(error, mode: :strict).deep_transform_keys(&:underscore)
|
41
|
+
|
42
|
+
super "Failed to build '#{path}' -- #{error['text']}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ResolveError < StandardError
|
47
|
+
attr_reader :error_msg, :path
|
48
|
+
|
49
|
+
def initialize(path, error_msg)
|
50
|
+
super "Failed to resolve '#{path}' -- #{error_msg}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(root: nil, base_url: nil)
|
55
|
+
@root = root || Rails.root
|
56
|
+
@base_url = base_url
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.resolve(path)
|
60
|
+
new.resolve(path)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.build(path)
|
64
|
+
new.build(path)
|
65
|
+
end
|
66
|
+
|
67
|
+
def build(path)
|
68
|
+
result = Request.build(path, @root.to_s, @base_url, Rails.env.to_sym, import_map,
|
69
|
+
Rails.env.development?)
|
70
|
+
raise BuildError.new(path, result[:response]) unless result[:success]
|
71
|
+
|
72
|
+
result[:response]
|
73
|
+
end
|
74
|
+
|
75
|
+
def resolve(path)
|
76
|
+
result = Request.resolve(path, @root.to_s, Rails.env.to_sym, import_map)
|
77
|
+
raise ResolveError.new(path, result[:response]) unless result[:success]
|
78
|
+
|
79
|
+
result[:response]
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def import_map
|
85
|
+
return unless (path = Rails.root&.join('config'))
|
86
|
+
|
87
|
+
if (json = path.join('import_map.json')).exist?
|
88
|
+
return json.relative_path_from(@root).to_s
|
89
|
+
end
|
90
|
+
if (js = path.join('import_map.js')).exist?
|
91
|
+
return js.relative_path_from(@root).to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Proscenium
|
4
|
+
class Esbuild
|
5
|
+
class CompileError < StandardError; end
|
6
|
+
|
7
|
+
extend ActiveSupport::Autoload
|
8
|
+
|
9
|
+
autoload :Golib
|
10
|
+
|
11
|
+
def self.build(...)
|
12
|
+
new(...).build
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(path, root:, base_url:)
|
16
|
+
@path = path
|
17
|
+
@root = root
|
18
|
+
@base_url = base_url
|
19
|
+
end
|
20
|
+
|
21
|
+
def build
|
22
|
+
Proscenium::Esbuild::Golib.new(root: @root, base_url: @base_url).build(@path)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def cache_query_string
|
28
|
+
q = Proscenium.config.cache_query_string
|
29
|
+
q ? "--cache-query-string #{q}" : nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
Binary file
|
@@ -0,0 +1,108 @@
|
|
1
|
+
/* Code generated by cmd/cgo; DO NOT EDIT. */
|
2
|
+
|
3
|
+
/* package joelmoss/proscenium */
|
4
|
+
|
5
|
+
|
6
|
+
#line 1 "cgo-builtin-export-prolog"
|
7
|
+
|
8
|
+
#include <stddef.h>
|
9
|
+
|
10
|
+
#ifndef GO_CGO_EXPORT_PROLOGUE_H
|
11
|
+
#define GO_CGO_EXPORT_PROLOGUE_H
|
12
|
+
|
13
|
+
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
14
|
+
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#endif
|
18
|
+
|
19
|
+
/* Start of preamble from import "C" comments. */
|
20
|
+
|
21
|
+
|
22
|
+
#line 3 "main.go"
|
23
|
+
|
24
|
+
struct Result {
|
25
|
+
int success;
|
26
|
+
char* response;
|
27
|
+
};
|
28
|
+
|
29
|
+
#line 1 "cgo-generated-wrapper"
|
30
|
+
|
31
|
+
|
32
|
+
/* End of preamble from import "C" comments. */
|
33
|
+
|
34
|
+
|
35
|
+
/* Start of boilerplate cgo prologue. */
|
36
|
+
#line 1 "cgo-gcc-export-header-prolog"
|
37
|
+
|
38
|
+
#ifndef GO_CGO_PROLOGUE_H
|
39
|
+
#define GO_CGO_PROLOGUE_H
|
40
|
+
|
41
|
+
typedef signed char GoInt8;
|
42
|
+
typedef unsigned char GoUint8;
|
43
|
+
typedef short GoInt16;
|
44
|
+
typedef unsigned short GoUint16;
|
45
|
+
typedef int GoInt32;
|
46
|
+
typedef unsigned int GoUint32;
|
47
|
+
typedef long long GoInt64;
|
48
|
+
typedef unsigned long long GoUint64;
|
49
|
+
typedef GoInt64 GoInt;
|
50
|
+
typedef GoUint64 GoUint;
|
51
|
+
typedef size_t GoUintptr;
|
52
|
+
typedef float GoFloat32;
|
53
|
+
typedef double GoFloat64;
|
54
|
+
#ifdef _MSC_VER
|
55
|
+
#include <complex.h>
|
56
|
+
typedef _Fcomplex GoComplex64;
|
57
|
+
typedef _Dcomplex GoComplex128;
|
58
|
+
#else
|
59
|
+
typedef float _Complex GoComplex64;
|
60
|
+
typedef double _Complex GoComplex128;
|
61
|
+
#endif
|
62
|
+
|
63
|
+
/*
|
64
|
+
static assertion to make sure the file is being used on architecture
|
65
|
+
at least with matching size of GoInt.
|
66
|
+
*/
|
67
|
+
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
|
68
|
+
|
69
|
+
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
70
|
+
typedef _GoString_ GoString;
|
71
|
+
#endif
|
72
|
+
typedef void *GoMap;
|
73
|
+
typedef void *GoChan;
|
74
|
+
typedef struct { void *t; void *v; } GoInterface;
|
75
|
+
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
|
76
|
+
|
77
|
+
#endif
|
78
|
+
|
79
|
+
/* End of boilerplate cgo prologue. */
|
80
|
+
|
81
|
+
#ifdef __cplusplus
|
82
|
+
extern "C" {
|
83
|
+
#endif
|
84
|
+
|
85
|
+
|
86
|
+
// Build the given `path` in the `root`.
|
87
|
+
//
|
88
|
+
// - path - The path to build relative to `root`.
|
89
|
+
// - root - The working directory.
|
90
|
+
// - baseUrl - base URL of the Rails app. eg. https://example.com
|
91
|
+
// - env - The environment (1 = development, 2 = test, 3 = production)
|
92
|
+
// - importMap - Path to the import map relative to `root`.
|
93
|
+
// - debug
|
94
|
+
//
|
95
|
+
extern struct Result build(char* filepath, char* root, char* baseUrl, unsigned int env, char* importMap, GoUint8 debug);
|
96
|
+
|
97
|
+
// Resolve the given `path` relative to the `root`.
|
98
|
+
//
|
99
|
+
// - path - The path to build relative to `root`.
|
100
|
+
// - root - The working directory.
|
101
|
+
// - env - The environment (1 = development, 2 = test, 3 = production)
|
102
|
+
// - importMap - Path to the import map relative to `root`.
|
103
|
+
//
|
104
|
+
extern struct Result resolve(char* path, char* root, unsigned int env, char* importMap);
|
105
|
+
|
106
|
+
#ifdef __cplusplus
|
107
|
+
}
|
108
|
+
#endif
|
data/lib/proscenium/helper.rb
CHANGED
@@ -15,28 +15,5 @@ module Proscenium
|
|
15
15
|
|
16
16
|
super
|
17
17
|
end
|
18
|
-
|
19
|
-
def side_load_stylesheets
|
20
|
-
return unless Proscenium::Current.loaded
|
21
|
-
|
22
|
-
Proscenium::Current.loaded[:css].map do |sheet|
|
23
|
-
stylesheet_link_tag(sheet, id: "_#{Digest::SHA1.hexdigest("/#{sheet}")[..7]}")
|
24
|
-
end.join("\n").html_safe
|
25
|
-
end
|
26
|
-
|
27
|
-
def side_load_javascripts(**options)
|
28
|
-
return unless Proscenium::Current.loaded
|
29
|
-
|
30
|
-
javascript_include_tag(*Proscenium::Current.loaded[:js], options)
|
31
|
-
end
|
32
|
-
|
33
|
-
def proscenium_dev
|
34
|
-
return unless Proscenium.config.auto_reload
|
35
|
-
|
36
|
-
javascript_tag %(
|
37
|
-
import autoReload from '/proscenium-runtime/auto_reload.js';
|
38
|
-
autoReload('#{Proscenium::Railtie.websocket_mount_path}');
|
39
|
-
), type: 'module', defer: true
|
40
|
-
end
|
41
18
|
end
|
42
19
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/log_subscriber'
|
4
|
+
|
5
|
+
module Proscenium
|
6
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
7
|
+
def sideload(event)
|
8
|
+
info do
|
9
|
+
" [Proscenium] Side loaded #{event.payload[:identifier]}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def build(event)
|
14
|
+
path = event.payload[:identifier]
|
15
|
+
path = path.start_with?(/https?%3A%2F%2F/) ? CGI.unescape(path) : path
|
16
|
+
|
17
|
+
info do
|
18
|
+
message = +"[Proscenium] Building #{path}"
|
19
|
+
message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
|
20
|
+
message << "\n" if defined?(Rails.env) && Rails.env.development?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Proscenium::LogSubscriber.attach_to :proscenium
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'open3'
|
4
|
+
require 'oj'
|
4
5
|
|
5
6
|
module Proscenium
|
6
7
|
class Middleware
|
@@ -9,7 +10,15 @@ module Proscenium
|
|
9
10
|
|
10
11
|
# Error when the result of the build returns an error. For example, when esbuild returns
|
11
12
|
# errors.
|
12
|
-
class CompileError < StandardError
|
13
|
+
class CompileError < StandardError
|
14
|
+
attr_reader :detail, :file
|
15
|
+
|
16
|
+
def initialize(args)
|
17
|
+
@detail = args[:detail]
|
18
|
+
@file = args[:file]
|
19
|
+
super "Failed to build '#{args[:file]}' -- #{detail}"
|
20
|
+
end
|
21
|
+
end
|
13
22
|
|
14
23
|
def self.attempt(request)
|
15
24
|
new(request).renderable!&.attempt
|
@@ -25,12 +34,25 @@ module Proscenium
|
|
25
34
|
|
26
35
|
private
|
27
36
|
|
37
|
+
def real_path
|
38
|
+
@request.path
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String] the path to the file without the leading slash which will be built.
|
42
|
+
def path_to_build
|
43
|
+
@request.path[1..]
|
44
|
+
end
|
45
|
+
|
46
|
+
def sourcemap?
|
47
|
+
@request.path.ends_with?('.map')
|
48
|
+
end
|
49
|
+
|
28
50
|
def renderable?
|
29
51
|
file_readable?
|
30
52
|
end
|
31
53
|
|
32
|
-
def file_readable?
|
33
|
-
return unless (path = clean_path(
|
54
|
+
def file_readable?
|
55
|
+
return unless (path = clean_path(sourcemap? ? real_path[0...-4] : real_path))
|
34
56
|
|
35
57
|
file_stat = File.stat(Pathname(root).join(path.delete_prefix('/').b).to_s)
|
36
58
|
rescue SystemCallError
|
@@ -50,7 +72,7 @@ module Proscenium
|
|
50
72
|
|
51
73
|
def content_type
|
52
74
|
@content_type ||
|
53
|
-
::Rack::Mime.mime_type(::File.extname(
|
75
|
+
::Rack::Mime.mime_type(::File.extname(path_to_build), nil) ||
|
54
76
|
'application/javascript'
|
55
77
|
end
|
56
78
|
|
@@ -59,9 +81,10 @@ module Proscenium
|
|
59
81
|
response.write content
|
60
82
|
response.content_type = content_type
|
61
83
|
response['X-Proscenium-Middleware'] = name
|
84
|
+
response.set_header 'SourceMap', "#{@request.path_info}.map"
|
62
85
|
|
63
86
|
if Proscenium.config.cache_query_string && Proscenium.config.cache_max_age
|
64
|
-
response
|
87
|
+
response.cache! Proscenium.config.cache_max_age
|
65
88
|
end
|
66
89
|
|
67
90
|
yield response if block_given?
|
@@ -69,37 +92,6 @@ module Proscenium
|
|
69
92
|
response.finish
|
70
93
|
end
|
71
94
|
|
72
|
-
def build(cmd)
|
73
|
-
stdout, stderr, status = Open3.capture3(cmd)
|
74
|
-
|
75
|
-
unless status.success?
|
76
|
-
raise self.class::CompileError, stderr if status.exitstatus == 2
|
77
|
-
|
78
|
-
raise BuildError, stderr
|
79
|
-
end
|
80
|
-
|
81
|
-
unless stderr.empty?
|
82
|
-
raise BuildError, "Proscenium build of #{name}:'#{@request.fullpath}' failed -- #{stderr}"
|
83
|
-
end
|
84
|
-
|
85
|
-
stdout
|
86
|
-
end
|
87
|
-
|
88
|
-
def benchmark(type)
|
89
|
-
super logging_message(type)
|
90
|
-
end
|
91
|
-
|
92
|
-
# rubocop:disable Style/FormatStringToken
|
93
|
-
def logging_message(type)
|
94
|
-
format '[Proscenium] Request (%s) %s for %s at %s',
|
95
|
-
type, @request.fullpath, @request.ip, Time.now.to_default_s
|
96
|
-
end
|
97
|
-
# rubocop:enable Style/FormatStringToken
|
98
|
-
|
99
|
-
def logger
|
100
|
-
Rails.logger
|
101
|
-
end
|
102
|
-
|
103
95
|
def name
|
104
96
|
@name ||= self.class.name.split('::').last.downcase
|
105
97
|
end
|
@@ -3,55 +3,29 @@
|
|
3
3
|
module Proscenium
|
4
4
|
class Middleware
|
5
5
|
class Esbuild < Base
|
6
|
-
class CompileError <
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
class CompileError < Base::CompileError
|
7
|
+
def initialize(args)
|
8
|
+
detail = args[:detail]
|
9
|
+
detail = ActiveSupport::HashWithIndifferentAccess.new(Oj.load(detail, mode: :strict))
|
10
|
+
|
11
|
+
args[:detail] = if detail[:location]
|
12
|
+
"#{detail[:text]} in #{detail[:location][:file]}:" +
|
13
|
+
detail[:location][:line].to_s
|
14
|
+
else
|
15
|
+
detail[:text]
|
16
|
+
end
|
17
|
+
|
18
|
+
super args
|
13
19
|
end
|
14
20
|
end
|
15
21
|
|
16
22
|
def attempt
|
17
|
-
|
18
|
-
render_response build(
|
19
|
-
|
20
|
-
cache_query_string,
|
21
|
-
"--lightningcss-bin #{lightningcss_cli} #{path}"
|
22
|
-
].compact.join(' '))
|
23
|
-
end
|
24
|
-
rescue CompileError => e
|
25
|
-
render_response "export default #{e.detail.to_json}" do |response|
|
26
|
-
response['X-Proscenium-Middleware'] = 'Esbuild::CompileError'
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def path
|
33
|
-
@request.path[1..]
|
34
|
-
end
|
35
|
-
|
36
|
-
def cli
|
37
|
-
if ENV['PROSCENIUM_TEST']
|
38
|
-
'deno run -q --import-map import_map.json -A lib/proscenium/compilers/esbuild.js'
|
39
|
-
else
|
40
|
-
Gem.bin_path 'proscenium', 'esbuild'
|
23
|
+
ActiveSupport::Notifications.instrument('build.proscenium', identifier: path_to_build) do
|
24
|
+
render_response Proscenium::Esbuild.build(path_to_build, root: root,
|
25
|
+
base_url: @request.base_url)
|
41
26
|
end
|
42
|
-
|
43
|
-
|
44
|
-
def lightningcss_cli
|
45
|
-
if ENV['PROSCENIUM_TEST']
|
46
|
-
'bin/lightningcss'
|
47
|
-
else
|
48
|
-
Gem.bin_path 'proscenium', 'lightningcss'
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def cache_query_string
|
53
|
-
q = Proscenium.config.cache_query_string
|
54
|
-
q ? "--cache-query-string #{q}" : nil
|
27
|
+
rescue Proscenium::Esbuild::CompileError => e
|
28
|
+
raise self.class::CompileError, { file: @request.fullpath, detail: e.message }, caller
|
55
29
|
end
|
56
30
|
end
|
57
31
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Proscenium
|
4
4
|
class Middleware
|
5
|
-
# Handles requests
|
5
|
+
# Handles requests for URL encoded URL's.
|
6
6
|
class Url < Esbuild
|
7
7
|
private
|
8
8
|
|
@@ -11,11 +11,6 @@ module Proscenium
|
|
11
11
|
def renderable?
|
12
12
|
true
|
13
13
|
end
|
14
|
-
|
15
|
-
# @override [Esbuild]
|
16
|
-
def path
|
17
|
-
CGI.unescape(@request.path)[1..]
|
18
|
-
end
|
19
14
|
end
|
20
15
|
end
|
21
16
|
end
|
@@ -9,9 +9,7 @@ module Proscenium
|
|
9
9
|
|
10
10
|
autoload :Base
|
11
11
|
autoload :Esbuild
|
12
|
-
autoload :Runtime
|
13
12
|
autoload :Url
|
14
|
-
autoload :OutsideRoot
|
15
13
|
|
16
14
|
def initialize(app)
|
17
15
|
@app = app
|
@@ -27,37 +25,35 @@ module Proscenium
|
|
27
25
|
|
28
26
|
private
|
29
27
|
|
30
|
-
# Look for the precompiled file in public/assets first, then fallback to the Proscenium
|
31
|
-
# middleware that matches the type of file requested, ie: .js => esbuild.
|
32
|
-
# See Rails.application.config.proscenium.glob_types.
|
33
28
|
def attempt(request)
|
34
29
|
return unless (type = find_type(request))
|
35
30
|
|
36
|
-
file_handler.attempt(request.env) || type.attempt(request)
|
31
|
+
# file_handler.attempt(request.env) || type.attempt(request)
|
32
|
+
|
33
|
+
type.attempt(request)
|
37
34
|
end
|
38
35
|
|
39
|
-
# Returns the type of file being requested using
|
36
|
+
# Returns the type of file being requested using Proscenium::MIDDLEWARE_GLOB_TYPES.
|
40
37
|
def find_type(request)
|
41
38
|
path = Pathname.new(request.path)
|
42
39
|
|
43
|
-
# Non-production only!
|
44
|
-
if request.query_string == 'outsideRoot'
|
45
|
-
return if Rails.env.production?
|
46
|
-
return OutsideRoot if path.fnmatch?(glob_types[:outsideRoot], File::FNM_EXTGLOB)
|
47
|
-
end
|
48
|
-
|
49
40
|
return Url if request.path.match?(glob_types[:url])
|
50
|
-
return
|
51
|
-
return Esbuild if path.fnmatch?(glob_types[:esbuild], File::FNM_EXTGLOB)
|
41
|
+
return Esbuild if path.fnmatch?(application_glob_type, File::FNM_EXTGLOB)
|
52
42
|
end
|
53
43
|
|
44
|
+
# TODO: handle precompiled assets
|
54
45
|
def file_handler
|
55
46
|
::ActionDispatch::FileHandler.new Rails.public_path.join('assets').to_s,
|
56
47
|
headers: { 'X-Proscenium-Middleware' => 'precompiled' }
|
57
48
|
end
|
58
49
|
|
59
50
|
def glob_types
|
60
|
-
|
51
|
+
@glob_types ||= Proscenium::MIDDLEWARE_GLOB_TYPES
|
52
|
+
end
|
53
|
+
|
54
|
+
def application_glob_type
|
55
|
+
paths = Rails.application.config.proscenium.include_paths.join(',')
|
56
|
+
"/{#{paths}}#{glob_types[:application]}"
|
61
57
|
end
|
62
58
|
end
|
63
59
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Proscenium::Phlex::ComponentConcerns
|
4
|
+
module CssModules
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
include Proscenium::CssModule
|
7
|
+
include Proscenium::Phlex::ResolveCssModules
|
8
|
+
|
9
|
+
# class_methods do
|
10
|
+
# # FIXME: Still needed?
|
11
|
+
# def path
|
12
|
+
# pp name, super
|
13
|
+
# pp Module.const_source_location(name).first
|
14
|
+
|
15
|
+
# name && Pathname.new(Module.const_source_location(name).first)
|
16
|
+
# rescue NameError
|
17
|
+
# nil
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def path
|
24
|
+
self.class.path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'phlex/rails'
|
4
|
+
|
5
|
+
# Include this in your view for additional logic for rendering a full HTML page, usually from a
|
6
|
+
# controller.
|
7
|
+
module Proscenium::Phlex::Page
|
8
|
+
include Phlex::Rails::Helpers::CSPMetaTag
|
9
|
+
include Phlex::Rails::Helpers::CSRFMetaTags
|
10
|
+
include Phlex::Rails::Helpers::FaviconLinkTag
|
11
|
+
include Phlex::Rails::Helpers::PreloadLinkTag
|
12
|
+
include Phlex::Rails::Helpers::StyleSheetLinkTag
|
13
|
+
include Phlex::Rails::Helpers::ActionCableMetaTag
|
14
|
+
include Phlex::Rails::Helpers::AutoDiscoveryLinkTag
|
15
|
+
include Phlex::Rails::Helpers::JavaScriptIncludeTag
|
16
|
+
include Phlex::Rails::Helpers::JavaScriptImportMapTags
|
17
|
+
include Phlex::Rails::Helpers::JavaScriptImportModuleTag
|
18
|
+
|
19
|
+
def self.included(klass)
|
20
|
+
klass.extend(Phlex::Rails::Layout::Interface)
|
21
|
+
end
|
22
|
+
|
23
|
+
def template(&block)
|
24
|
+
doctype
|
25
|
+
html do
|
26
|
+
head
|
27
|
+
body(&block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def after_template
|
34
|
+
super
|
35
|
+
@_buffer.gsub!('<!-- [SIDE_LOAD_STYLESHEETS] -->', capture { side_load_stylesheets })
|
36
|
+
end
|
37
|
+
|
38
|
+
def page_title
|
39
|
+
Rails.application.class.name.deconstantize
|
40
|
+
end
|
41
|
+
|
42
|
+
def head
|
43
|
+
super do
|
44
|
+
title { page_title }
|
45
|
+
|
46
|
+
yield if block_given?
|
47
|
+
|
48
|
+
csp_meta_tag
|
49
|
+
csrf_meta_tags
|
50
|
+
|
51
|
+
comment { '[SIDE_LOAD_STYLESHEETS]' }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def body
|
56
|
+
super do
|
57
|
+
yield if block_given?
|
58
|
+
|
59
|
+
side_load_javascripts defer: true, type: :module
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|