proscenium 0.21.6 → 0.22.0.beta1
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/lib/proscenium/builder.rb +36 -16
- data/lib/proscenium/css_module.rb +1 -1
- data/lib/proscenium/ensure_loaded.rb +1 -1
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/ext/proscenium.h +11 -0
- data/lib/proscenium/helper.rb +1 -10
- data/lib/proscenium/manifest.rb +40 -0
- data/lib/proscenium/middleware/base.rb +0 -12
- data/lib/proscenium/middleware/esbuild.rb +0 -18
- data/lib/proscenium/middleware.rb +2 -2
- data/lib/proscenium/railtie.rb +13 -2
- data/lib/proscenium/railties/assets.rake +18 -0
- data/lib/proscenium/side_load.rb +2 -2
- data/lib/proscenium/version.rb +1 -1
- data/lib/proscenium.rb +15 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 25c8afc9ba8ceb38580394723a1a348ad223c6cd4d2746a2491581e73bfbc801
|
|
4
|
+
data.tar.gz: abfa8c374b6633064079f24c68f3ed94fe6e8a7364bb871a4f5bd3942e3b0a56
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9fdde9277820a78e9fab18b4c8dd5fe78be9fca04ff2b866523ed3f2a9d42474fe194f733a69172452bfb5f02c44eb390fa157298594688beb390ed16cbf0fad
|
|
7
|
+
data.tar.gz: 7f7440d3caca1d84ffead3c5cafecc114e0a5f4e5aa5ae39052d0599b1946527bc2302c0042337fc6260f74c9212a5124141823ed33caa8adac2675c8862ae07
|
data/lib/proscenium/builder.rb
CHANGED
|
@@ -4,8 +4,6 @@ require 'ffi'
|
|
|
4
4
|
|
|
5
5
|
module Proscenium
|
|
6
6
|
class Builder
|
|
7
|
-
class CompileError < StandardError; end
|
|
8
|
-
|
|
9
7
|
ENVIRONMENTS = { development: 1, test: 2, production: 3 }.freeze
|
|
10
8
|
|
|
11
9
|
class Result < FFI::Struct
|
|
@@ -14,6 +12,11 @@ module Proscenium
|
|
|
14
12
|
:content_hash, :string
|
|
15
13
|
end
|
|
16
14
|
|
|
15
|
+
class CompileResult < FFI::Struct
|
|
16
|
+
layout :success, :bool,
|
|
17
|
+
:messages, :string
|
|
18
|
+
end
|
|
19
|
+
|
|
17
20
|
module Request
|
|
18
21
|
extend FFI::Library
|
|
19
22
|
|
|
@@ -32,30 +35,36 @@ module Proscenium
|
|
|
32
35
|
:pointer # Config as JSON.
|
|
33
36
|
], Result.by_value
|
|
34
37
|
|
|
38
|
+
attach_function :compile, [
|
|
39
|
+
:pointer # Config as JSON.
|
|
40
|
+
], CompileResult.by_value
|
|
41
|
+
|
|
35
42
|
attach_function :reset_config, [], :void
|
|
36
43
|
end
|
|
37
44
|
|
|
38
|
-
class BuildError <
|
|
39
|
-
attr_reader :error
|
|
45
|
+
class BuildError < Error
|
|
46
|
+
attr_reader :error, :path
|
|
40
47
|
|
|
41
|
-
def initialize(error)
|
|
42
|
-
@
|
|
48
|
+
def initialize(path, error)
|
|
49
|
+
@path = path
|
|
50
|
+
@error = JSON.parse(error, strict: true)
|
|
43
51
|
|
|
44
|
-
msg = @error['
|
|
45
|
-
msg << ' - ' << @error['
|
|
46
|
-
if (location = @error['
|
|
47
|
-
msg << " at #{location['
|
|
52
|
+
msg = @error['Text']
|
|
53
|
+
msg << ' - ' << @error['Detail'] if @error['Detail'].is_a?(String)
|
|
54
|
+
if (location = @error['Location'])
|
|
55
|
+
msg << " at #{location['File']}:#{location['Line']}:#{location['Column']}"
|
|
48
56
|
end
|
|
49
57
|
|
|
50
|
-
super(msg)
|
|
58
|
+
super("Failed to build #{path} - #{msg}")
|
|
51
59
|
end
|
|
52
60
|
end
|
|
53
61
|
|
|
54
|
-
class ResolveError <
|
|
55
|
-
attr_reader :
|
|
62
|
+
class ResolveError < Error
|
|
63
|
+
attr_reader :path
|
|
56
64
|
|
|
57
|
-
def initialize(path,
|
|
58
|
-
|
|
65
|
+
def initialize(path, msg)
|
|
66
|
+
@path = path
|
|
67
|
+
super("Failed to resolve #{path} - #{msg}")
|
|
59
68
|
end
|
|
60
69
|
end
|
|
61
70
|
|
|
@@ -67,6 +76,10 @@ module Proscenium
|
|
|
67
76
|
new(root:).resolve(path)
|
|
68
77
|
end
|
|
69
78
|
|
|
79
|
+
def self.compile(root: nil)
|
|
80
|
+
new(root:).compile
|
|
81
|
+
end
|
|
82
|
+
|
|
70
83
|
# Intended for tests only.
|
|
71
84
|
def self.reset_config!
|
|
72
85
|
Request.reset_config
|
|
@@ -75,6 +88,7 @@ module Proscenium
|
|
|
75
88
|
def initialize(root: nil)
|
|
76
89
|
@request_config = FFI::MemoryPointer.from_string({
|
|
77
90
|
RootPath: (root || Rails.root).to_s,
|
|
91
|
+
OutputDir: "public#{Proscenium.config.output_dir}",
|
|
78
92
|
GemPath: gem_root,
|
|
79
93
|
Environment: ENVIRONMENTS.fetch(Rails.env.to_sym, 2),
|
|
80
94
|
EnvVars: env_vars,
|
|
@@ -82,6 +96,7 @@ module Proscenium
|
|
|
82
96
|
RubyGems: Proscenium::BundledGems.paths,
|
|
83
97
|
Bundle: Proscenium.config.bundle,
|
|
84
98
|
Aliases: Proscenium.config.aliases,
|
|
99
|
+
Precompile: Proscenium.config.precompile,
|
|
85
100
|
QueryString: Proscenium.config.cache_query_string.presence || '',
|
|
86
101
|
Debug: Proscenium.config.debug
|
|
87
102
|
}.to_json)
|
|
@@ -91,7 +106,7 @@ module Proscenium
|
|
|
91
106
|
ActiveSupport::Notifications.instrument('build.proscenium', identifier: path) do
|
|
92
107
|
result = Request.build_to_string(path, cache_query_string, @request_config)
|
|
93
108
|
|
|
94
|
-
raise BuildError, result[:response] unless result[:success]
|
|
109
|
+
raise BuildError.new(path, result[:response]) unless result[:success]
|
|
95
110
|
|
|
96
111
|
result
|
|
97
112
|
end
|
|
@@ -107,6 +122,11 @@ module Proscenium
|
|
|
107
122
|
end
|
|
108
123
|
end
|
|
109
124
|
|
|
125
|
+
def compile
|
|
126
|
+
result = Request.compile(@request_config)
|
|
127
|
+
result[:success]
|
|
128
|
+
end
|
|
129
|
+
|
|
110
130
|
private
|
|
111
131
|
|
|
112
132
|
# Build the ENV variables as determined by `Proscenium.config.env_vars` and
|
|
@@ -7,7 +7,7 @@ module Proscenium::CssModule
|
|
|
7
7
|
autoload :Transformer
|
|
8
8
|
autoload :Rewriter
|
|
9
9
|
|
|
10
|
-
class TransformError <
|
|
10
|
+
class TransformError < Proscenium::Error
|
|
11
11
|
def initialize(name, additional_msg = nil)
|
|
12
12
|
msg = "Failed to transform CSS module `#{name}`"
|
|
13
13
|
msg << ' - ' << additional_msg if additional_msg
|
|
Binary file
|
|
@@ -25,6 +25,10 @@ struct Result {
|
|
|
25
25
|
int success;
|
|
26
26
|
char* response;
|
|
27
27
|
char* contentHash;
|
|
28
|
+
};
|
|
29
|
+
struct CompileResult {
|
|
30
|
+
int success;
|
|
31
|
+
char* messages;
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
#line 1 "cgo-generated-wrapper"
|
|
@@ -88,6 +92,7 @@ extern void reset_config();
|
|
|
88
92
|
// Build the given `path` using the `config`.
|
|
89
93
|
//
|
|
90
94
|
// - path - The path to build relative to `root`.
|
|
95
|
+
// - cache_query_string - The current query string used for cache busting, taken from the URL.
|
|
91
96
|
// - config
|
|
92
97
|
//
|
|
93
98
|
extern struct Result build_to_string(char* filePath, char* cacheQueryString, char* configJson);
|
|
@@ -99,6 +104,12 @@ extern struct Result build_to_string(char* filePath, char* cacheQueryString, cha
|
|
|
99
104
|
//
|
|
100
105
|
extern struct Result resolve(char* filePath, char* configJson);
|
|
101
106
|
|
|
107
|
+
// Compile assets using the given `config`.
|
|
108
|
+
//
|
|
109
|
+
// - config
|
|
110
|
+
//
|
|
111
|
+
extern struct CompileResult compile(char* configJson);
|
|
112
|
+
|
|
102
113
|
#ifdef __cplusplus
|
|
103
114
|
}
|
|
104
115
|
#endif
|
data/lib/proscenium/helper.rb
CHANGED
|
@@ -11,18 +11,9 @@ module Proscenium
|
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
# Overriden to allow regular use of javascript_include_tag and stylesheet_link_tag, while still
|
|
15
|
-
# building with Proscenium. It's important to note that `include_assets` will not call this, as
|
|
16
|
-
# those asset paths all begin with a slash, which the Rails asset helpers do not pass through to
|
|
17
|
-
# here.
|
|
18
|
-
#
|
|
19
|
-
# If the given `path` is a bare path (does not start with `./` or `../`), then we use
|
|
20
|
-
# Rails default conventions, and serve CSS from /app/assets/stylesheets and JS from
|
|
21
|
-
# /app/javascript.
|
|
22
14
|
def compute_asset_path(path, options = {})
|
|
23
15
|
if %i[javascript stylesheet].include?(options[:type])
|
|
24
|
-
|
|
25
|
-
return path
|
|
16
|
+
return Proscenium::Manifest[path] || "/#{path}"
|
|
26
17
|
end
|
|
27
18
|
|
|
28
19
|
super
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Proscenium
|
|
4
|
+
module Manifest
|
|
5
|
+
mattr_accessor :manifest, default: {}
|
|
6
|
+
mattr_accessor :loaded, default: false
|
|
7
|
+
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def loaded?
|
|
11
|
+
loaded
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def load!
|
|
15
|
+
self.manifest = {}
|
|
16
|
+
self.loaded = false
|
|
17
|
+
|
|
18
|
+
if Proscenium.config.manifest_path.exist?
|
|
19
|
+
self.loaded = true
|
|
20
|
+
|
|
21
|
+
JSON.parse(Proscenium.config.manifest_path.read)['outputs'].each do |output_path, details|
|
|
22
|
+
next if !details.key?('entryPoint')
|
|
23
|
+
|
|
24
|
+
manifest[details['entryPoint']] = "/#{output_path.delete_prefix('public/')}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
manifest
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def reset!
|
|
32
|
+
self.manifest = {}
|
|
33
|
+
self.loaded = false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def [](key)
|
|
37
|
+
loaded? ? manifest[key] : "/#{key}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -5,18 +5,6 @@ module Proscenium
|
|
|
5
5
|
class Base
|
|
6
6
|
include ActiveSupport::Benchmarkable
|
|
7
7
|
|
|
8
|
-
# Error when the result of the build returns an error. For example, when esbuild returns
|
|
9
|
-
# errors.
|
|
10
|
-
class CompileError < StandardError
|
|
11
|
-
attr_reader :detail, :file
|
|
12
|
-
|
|
13
|
-
def initialize(args)
|
|
14
|
-
@detail = args[:detail]
|
|
15
|
-
@file = args[:file]
|
|
16
|
-
super("Failed to build '#{args[:file]}' -- #{detail}")
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
8
|
def self.attempt(request)
|
|
21
9
|
new(request).renderable!&.attempt
|
|
22
10
|
end
|
|
@@ -3,26 +3,8 @@
|
|
|
3
3
|
module Proscenium
|
|
4
4
|
class Middleware
|
|
5
5
|
class Esbuild < Base
|
|
6
|
-
class CompileError < Base::CompileError
|
|
7
|
-
def initialize(args)
|
|
8
|
-
detail = args[:detail]
|
|
9
|
-
detail = JSON.parse(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
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
6
|
def attempt
|
|
23
7
|
render_response Builder.build_to_string(path_to_build, cache_query_string:)
|
|
24
|
-
rescue Builder::CompileError => e
|
|
25
|
-
raise self.class::CompileError, { file: @request.fullpath, detail: e.message }, caller
|
|
26
8
|
end
|
|
27
9
|
end
|
|
28
10
|
end
|
|
@@ -4,7 +4,7 @@ module Proscenium
|
|
|
4
4
|
class Middleware
|
|
5
5
|
extend ActiveSupport::Autoload
|
|
6
6
|
|
|
7
|
-
class BuildError <
|
|
7
|
+
class BuildError < Error; end
|
|
8
8
|
|
|
9
9
|
autoload :Base
|
|
10
10
|
autoload :Esbuild
|
|
@@ -24,7 +24,7 @@ module Proscenium
|
|
|
24
24
|
# cache lifetime, since these are content-hashed and will never change.
|
|
25
25
|
if request.path.match?(CHUNKS_PATH)
|
|
26
26
|
::ActionDispatch::FileHandler.new(
|
|
27
|
-
|
|
27
|
+
Proscenium.config.output_path.to_s,
|
|
28
28
|
headers: {
|
|
29
29
|
'Cache-Control' => "public, max-age=#{100.years}, immutable",
|
|
30
30
|
'etag' => request.path.match(/-\$([a-z0-9]+)\$/i)[1]
|
data/lib/proscenium/railtie.rb
CHANGED
|
@@ -17,8 +17,9 @@ module Proscenium
|
|
|
17
17
|
config.proscenium.ensure_loaded = :raise
|
|
18
18
|
config.proscenium.cache_query_string = Rails.env.production? && ENV.fetch('REVISION', nil)
|
|
19
19
|
config.proscenium.cache_max_age = 2_592_000 # 30 days
|
|
20
|
-
|
|
21
20
|
config.proscenium.aliases = {}
|
|
21
|
+
config.proscenium.precompile = Set.new
|
|
22
|
+
config.proscenium.output_dir = '/assets'
|
|
22
23
|
|
|
23
24
|
# List of environment variable names that should be passed to the builder, which will then be
|
|
24
25
|
# passed to esbuild's `Define` option. Being explicit about which environment variables are
|
|
@@ -29,7 +30,13 @@ module Proscenium
|
|
|
29
30
|
'Proscenium::Builder::BuildError' => 'build_error'
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
config.after_initialize do |
|
|
33
|
+
config.after_initialize do |app|
|
|
34
|
+
config.proscenium.output_path ||=
|
|
35
|
+
Pathname.new(File.join(app.config.paths['public'].first, app.config.proscenium.output_dir))
|
|
36
|
+
config.proscenium.manifest_path = config.proscenium.output_path.join('.manifest.json')
|
|
37
|
+
|
|
38
|
+
Proscenium::Manifest.load!
|
|
39
|
+
|
|
33
40
|
if config.proscenium.logging
|
|
34
41
|
require 'proscenium/log_subscriber'
|
|
35
42
|
Proscenium::LogSubscriber.attach_to :proscenium
|
|
@@ -65,5 +72,9 @@ module Proscenium
|
|
|
65
72
|
ActionView::PartialRenderer.prepend Monkey::PartialRenderer
|
|
66
73
|
end
|
|
67
74
|
end
|
|
75
|
+
|
|
76
|
+
rake_tasks do
|
|
77
|
+
load 'proscenium/railties/assets.rake'
|
|
78
|
+
end
|
|
68
79
|
end
|
|
69
80
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :assets do
|
|
4
|
+
desc 'Compile Proscenium assets'
|
|
5
|
+
task precompile: :environment do
|
|
6
|
+
puts "\nPre-compiling assets..."
|
|
7
|
+
|
|
8
|
+
raise 'Assets pre-compilation failed!' unless Proscenium::Builder.compile
|
|
9
|
+
|
|
10
|
+
puts "\nAssets pre-compiled successfully."
|
|
11
|
+
|
|
12
|
+
if Rails.env.development?
|
|
13
|
+
puts "\nWarning: You are precompiling assets in development. Rails will not " \
|
|
14
|
+
'serve any changed assets until you delete ' \
|
|
15
|
+
"public#{Rails.application.config.proscenium.output_dir}/.manifest.json"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/proscenium/side_load.rb
CHANGED
|
@@ -43,7 +43,7 @@ module Proscenium
|
|
|
43
43
|
if Proscenium.config.cache_query_string.present?
|
|
44
44
|
path += "?#{Proscenium.config.cache_query_string}"
|
|
45
45
|
end
|
|
46
|
-
out << helpers.stylesheet_link_tag(path, extname: false, **opts)
|
|
46
|
+
out << helpers.stylesheet_link_tag(path.delete_prefix('/'), extname: false, **opts)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
if fragments
|
|
@@ -74,7 +74,7 @@ module Proscenium
|
|
|
74
74
|
if Proscenium.config.cache_query_string.present?
|
|
75
75
|
path += "?#{Proscenium.config.cache_query_string}"
|
|
76
76
|
end
|
|
77
|
-
out << helpers.javascript_include_tag(path, extname: false, **opts)
|
|
77
|
+
out << helpers.javascript_include_tag(path.delete_prefix('/'), extname: false, **opts)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
if fragments
|
data/lib/proscenium/version.rb
CHANGED
data/lib/proscenium.rb
CHANGED
|
@@ -26,6 +26,7 @@ module Proscenium
|
|
|
26
26
|
autoload :Utils
|
|
27
27
|
autoload :Monkey
|
|
28
28
|
autoload :Middleware
|
|
29
|
+
autoload :Manifest
|
|
29
30
|
autoload :EnsureLoaded
|
|
30
31
|
autoload :SideLoad
|
|
31
32
|
autoload :CssModule
|
|
@@ -44,7 +45,20 @@ module Proscenium
|
|
|
44
45
|
end
|
|
45
46
|
end
|
|
46
47
|
|
|
47
|
-
class
|
|
48
|
+
class Error < StandardError; end
|
|
49
|
+
|
|
50
|
+
class MissingAssetError < Error
|
|
51
|
+
def initialize(path)
|
|
52
|
+
super
|
|
53
|
+
@path = path
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def message
|
|
57
|
+
"The asset '#{@path}' was not found."
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class PathResolutionFailed < Error
|
|
48
62
|
def initialize(path)
|
|
49
63
|
@path = path
|
|
50
64
|
super
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: proscenium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.22.0.beta1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joel Moss
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-10-
|
|
11
|
+
date: 2025-10-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|
|
@@ -66,6 +66,7 @@ files:
|
|
|
66
66
|
- lib/proscenium/helper.rb
|
|
67
67
|
- lib/proscenium/importer.rb
|
|
68
68
|
- lib/proscenium/log_subscriber.rb
|
|
69
|
+
- lib/proscenium/manifest.rb
|
|
69
70
|
- lib/proscenium/middleware.rb
|
|
70
71
|
- lib/proscenium/middleware/base.rb
|
|
71
72
|
- lib/proscenium/middleware/esbuild.rb
|
|
@@ -73,6 +74,7 @@ files:
|
|
|
73
74
|
- lib/proscenium/middleware/silence_request.rb
|
|
74
75
|
- lib/proscenium/monkey.rb
|
|
75
76
|
- lib/proscenium/railtie.rb
|
|
77
|
+
- lib/proscenium/railties/assets.rake
|
|
76
78
|
- lib/proscenium/react-manager/index.jsx
|
|
77
79
|
- lib/proscenium/react-manager/react.js
|
|
78
80
|
- lib/proscenium/react_componentable.rb
|