proscenium 0.19.0.beta16 → 0.19.0.beta20

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f9099b0a36f4297deb23000fa59be1f7b42821d0922ead517e0fa743b078079
4
- data.tar.gz: eb916375082bb5a3c849eb8374d218866fd05f8b5b57d2d43df607eff6213c1f
3
+ metadata.gz: '080d5f311b0065c945326e31473f04cf50562a193210f7cc737b8efe0decf517'
4
+ data.tar.gz: ce1f8e3c8165b153ccc409c2a2ff9126282ac376d2607472e1d7bb120b0bf368
5
5
  SHA512:
6
- metadata.gz: d24803aca9f34fd5e68a9d0e077e2ec72b9f34e94ae3dcc2bda39a2fa65449d00e9c9f4d7e1c3266af1b92c8b8958bbb302741e2ce094d2526f78c36829ed5b1
7
- data.tar.gz: 4c1a2d1dff84baea2578ca25aa58adc18c2c7929d95e975d0c6965749048ea7d9ebfc63c5c44a823f88de600cdc3eddde9a2f975aa779e47646bcda73c1063ae
6
+ metadata.gz: 5548d17d416cf00d14685eb54b7e23e6865fc52e0ec40715339ba3490e8f547b87b1ca33f436905cdbf89284b508692886329c2df1f9d513bab18cfa422a5b91
7
+ data.tar.gz: 6a9c0844565ea5f0acdd93a4e2d2723dd039e6076bafbac2f1b4e255332c49cd7bcdb206a7986e89e5b49a9947cde6da9e7932960fd5f8632ad7a6f09f75c411
data/README.md CHANGED
@@ -48,7 +48,6 @@
48
48
  - [Typescript Caveats](#typescript-caveats)
49
49
  - [JSX](#jsx)
50
50
  - [JSON](#json)
51
- - [Phlex Support](#phlex-support)
52
51
  - [Cache Busting](#cache-busting)
53
52
  - [rjs is back!](#rjs-is-back)
54
53
  - [Resolution](#resolution)
@@ -681,93 +680,6 @@ import { version } from "./package.json";
681
680
  console.log(version);
682
681
  ```
683
682
 
684
- ## Phlex Support
685
-
686
- [Phlex](https://www.phlex.fun/) is a framework for building fast, reusable, testable views in pure Ruby. Proscenium works perfectly with Phlex, with support for side-loading, CSS modules, and more. Simply write your Phlex classes and inherit from `Proscenium::Phlex`.
687
-
688
- ```ruby
689
- class MyView < Proscenium::Phlex
690
- def view_template
691
- h1 { 'Hello World' }
692
- end
693
- end
694
- ```
695
-
696
- In your layouts, include `Proscenium::Phlex::AssetInclusions`, and call the `include_assets` helper.
697
-
698
- ```ruby
699
- class ApplicationLayout < Proscenium::Phlex
700
- include Proscenium::Phlex::AssetInclusions # <--
701
-
702
- def view_template(&)
703
- doctype
704
- html do
705
- head do
706
- title { 'My Awesome App' }
707
- include_assets # <--
708
- end
709
- body(&)
710
- end
711
- end
712
- end
713
- ```
714
-
715
- You can specifically include CCS and JS assets using the `include_stylesheets` and `include_javascripts` helpers, allowing you to control where they are included in the HTML.
716
-
717
- ### Side-loading
718
-
719
- Any Phlex class that inherits `Proscenium::Phlex` will automatically be [side-loaded](#side-loading).
720
-
721
- ### CSS Modules
722
-
723
- [CSS Modules](#css-modules) are fully supported in Phlex classes, with access to the [`css_module` helper](#in-your-views) if you need it. However, there is a better and more seemless way to reference CSS module classes in your Phlex classes.
724
-
725
- Within your Phlex classes, any class names that begin with `@` will be treated as a CSS module class.
726
-
727
- ```ruby
728
- # /app/views/users/show_view.rb
729
- class Users::ShowView < Proscenium::Phlex
730
- def view_template
731
- h1 class: :@user_name do
732
- @user.name
733
- end
734
- end
735
- end
736
- ```
737
-
738
- ```css
739
- /* /app/views/users/show_view.module.css */
740
- .userName {
741
- color: red;
742
- font-size: 50px;
743
- }
744
- ```
745
-
746
- In the above `Users::ShowView` Phlex class, the `@user_name` class will be resolved to the `userName` class in the `users/show_view.module.css` file.
747
-
748
- The view above will be rendered something like this:
749
-
750
- ```html
751
- <h1 class="user_name-ABCD1234"></h1>
752
- ```
753
-
754
- You can of course continue to reference regular class names in your view, and they will be passed through as is. This will allow you to mix and match CSS modules and regular CSS classes in your views.
755
-
756
- ```ruby
757
- # /app/views/users/show_view.rb
758
- class Users::ShowView < Proscenium::Phlex
759
- def view_template
760
- h1 class: :[@user_name, :title] do
761
- @user.name
762
- end
763
- end
764
- end
765
- ```
766
-
767
- ```html
768
- <h1 class="user_name-ABCD1234 title">Joel Moss</h1>
769
- ```
770
-
771
683
  ## Cache Busting
772
684
 
773
685
  > _COMING SOON_
@@ -16,7 +16,7 @@ module Proscenium
16
16
 
17
17
  module Request
18
18
  extend FFI::Library
19
- ffi_lib ENV.fetch('PROSCENIUM_BIN', Pathname.new(__dir__).join('ext/proscenium').to_s)
19
+ ffi_lib Pathname.new(__dir__).join('ext/proscenium').to_s
20
20
 
21
21
  enum :environment, [:development, 1, :test, :production]
22
22
 
@@ -18,7 +18,8 @@ module Proscenium
18
18
  unless @css_module_path
19
19
  klass = superclass
20
20
 
21
- while klass.respond_to?(:css_module_path) && !klass.abstract_class
21
+ while klass.respond_to?(:css_module_path) &&
22
+ (klass.respond_to?(:abstract_class) ? !klass.abstract_class : true)
22
23
  break if (@css_module_path = klass.css_module_path)
23
24
 
24
25
  klass = klass.superclass
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Proscenium::CssModule
4
+ extend ActiveSupport::Autoload
5
+
6
+ autoload :Path
7
+ autoload :Transformer
8
+ autoload :Rewriter
9
+
4
10
  class TransformError < StandardError
5
11
  def initialize(name, additional_msg = nil)
6
12
  msg = "Failed to transform CSS module `#{name}`"
@@ -10,24 +16,27 @@ module Proscenium::CssModule
10
16
  end
11
17
  end
12
18
 
13
- class Name
14
- attr_reader :path
19
+ module ClassMethods
20
+ def css_module(*names, path: nil)
21
+ path ||= respond_to?(:css_module_path) ? css_module_path : path
15
22
 
16
- def initialize(name, transform, path = nil)
17
- @name = name
18
- @transform = transform
19
- @path = path
23
+ cssm = Transformer.new(path)
24
+ cssm.class_names(*names, require_prefix: false).map { |name, _| name }.join(' ')
20
25
  end
21
26
 
22
- def to_s
23
- @transform
24
- end
27
+ def class_names(*names, path: nil)
28
+ path ||= respond_to?(:css_module_path) ? css_module_path : path
29
+ names = names.flatten.compact
25
30
 
26
- def to_sym
27
- @name
31
+ cssm = Transformer.new(path)
32
+ cssm.class_names(*names).map { |name, _| name }.join(' ') unless names.empty?
28
33
  end
29
34
  end
30
35
 
36
+ def self.included(base)
37
+ base.extend ClassMethods
38
+ end
39
+
31
40
  # Accepts one or more CSS class names, and transforms them into CSS module names.
32
41
  #
33
42
  # @param name [String,Symbol,Array<String,Symbol>]
Binary file
@@ -36,5 +36,3 @@ module Proscenium
36
36
  end
37
37
  end
38
38
  end
39
-
40
- Proscenium::LogSubscriber.attach_to :proscenium
@@ -2,9 +2,15 @@
2
2
 
3
3
  module Proscenium
4
4
  class Middleware
5
+ extend ActiveSupport::Autoload
6
+
5
7
  # Error when the build command fails.
6
8
  class BuildError < StandardError; end
7
9
 
10
+ autoload :Base
11
+ autoload :Esbuild
12
+ autoload :RubyGems
13
+
8
14
  def initialize(app)
9
15
  @app = app
10
16
 
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rails'
4
- require 'proscenium/log_subscriber'
5
4
 
6
5
  ENV['RAILS_ENV'] = Rails.env
7
6
 
@@ -11,6 +10,7 @@ module Proscenium
11
10
 
12
11
  config.proscenium = ActiveSupport::OrderedOptions.new
13
12
  config.proscenium.debug = false
13
+ config.proscenium.logging = true
14
14
  config.proscenium.bundle = true
15
15
  config.proscenium.side_load = true
16
16
  config.proscenium.code_splitting = true
@@ -28,6 +28,11 @@ module Proscenium
28
28
  }
29
29
 
30
30
  config.after_initialize do |_app|
31
+ if config.proscenium.logging
32
+ require 'proscenium/log_subscriber'
33
+ Proscenium::LogSubscriber.attach_to :proscenium
34
+ end
35
+
31
36
  ActiveSupport.on_load(:action_view) do
32
37
  include Proscenium::Helper
33
38
  end
@@ -11,7 +11,7 @@ module Proscenium
11
11
  # The HTML tag to use as the wrapping element for the component. You can reassign this in your
12
12
  # component class to use a different tag:
13
13
  #
14
- # class MyComponent < Proscenium::Phlex::ReactComponent
14
+ # class MyComponent < Proscenium::ReactComponent
15
15
  # self.root_tag = :span
16
16
  # end
17
17
  #
@@ -116,7 +116,8 @@ module Proscenium
116
116
  css_imports = []
117
117
 
118
118
  klass = obj.class
119
- while klass.respond_to?(:source_path) && klass.source_path && !klass.abstract_class
119
+ while klass.respond_to?(:source_path) && klass.source_path &&
120
+ (klass.respond_to?(:abstract_class) ? !klass.abstract_class : true)
120
121
  if options[:css] == false
121
122
  Importer.sideload klass.source_path, **options
122
123
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Proscenium
4
- VERSION = '0.19.0.beta16'
4
+ VERSION = '0.19.0.beta20'
5
5
  end
data/lib/proscenium.rb CHANGED
@@ -1,13 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'zeitwerk'
4
- require 'proscenium/railtie'
5
-
6
- loader = Zeitwerk::Loader.for_gem
7
- loader.ignore "#{__dir__}/proscenium/core_ext/object/css_module_ivars.rb"
8
- loader.setup
3
+ require 'active_support'
9
4
 
10
5
  module Proscenium
6
+ extend ActiveSupport::Autoload
7
+
11
8
  FILE_EXTENSIONS = ['js', 'mjs', 'ts', 'jsx', 'tsx', 'css', 'js.map', 'mjs.map', 'jsx.map',
12
9
  'ts.map', 'tsx.map', 'css.map'].freeze
13
10
 
@@ -23,6 +20,20 @@ module Proscenium
23
20
  # Environment variables that should always be passed to the builder.
24
21
  DEFAULT_ENV_VARS = Set['RAILS_ENV', 'NODE_ENV'].freeze
25
22
 
23
+ autoload :SourcePath
24
+ autoload :Utils
25
+ autoload :Monkey
26
+ autoload :Middleware
27
+ autoload :EnsureLoaded
28
+ autoload :SideLoad
29
+ autoload :CssModule
30
+ autoload :ReactComponentable
31
+ autoload :Helper
32
+ autoload :Builder
33
+ autoload :Importer
34
+ autoload :Resolver
35
+ autoload :BundledGems
36
+
26
37
  class Deprecator
27
38
  def deprecation_warning(name, message, _caller_backtrace = nil)
28
39
  msg = "`#{name}` is deprecated and will be removed in a near future release of Proscenium"
@@ -52,3 +63,5 @@ module Proscenium
52
63
  end
53
64
  end
54
65
  end
66
+
67
+ require 'proscenium/railtie'
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.19.0.beta16
4
+ version: 0.19.0.beta20
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-04-26 00:00:00.000000000 Z
11
+ date: 2025-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.17.0
27
- - !ruby/object:Gem::Dependency
28
- name: phlex-rails
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.2'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.2'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rails
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,34 +44,6 @@ dependencies:
58
44
  - - "<"
59
45
  - !ruby/object:Gem::Version
60
46
  version: '9.0'
61
- - !ruby/object:Gem::Dependency
62
- name: ruby-next
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: 1.1.1
68
- type: :runtime
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: 1.1.1
75
- - !ruby/object:Gem::Dependency
76
- name: zeitwerk
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: 2.7.2
82
- type: :runtime
83
- prerelease: false
84
- version_requirements: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - "~>"
87
- - !ruby/object:Gem::Version
88
- version: 2.7.2
89
47
  description:
90
48
  email:
91
49
  - joel@developwithstyle.com
@@ -99,10 +57,8 @@ files:
99
57
  - lib/proscenium.rb
100
58
  - lib/proscenium/builder.rb
101
59
  - lib/proscenium/bundled_gems.rb
102
- - lib/proscenium/core_ext/object/css_module_ivars.rb
103
60
  - lib/proscenium/css_module.rb
104
61
  - lib/proscenium/css_module/path.rb
105
- - lib/proscenium/css_module/rewriter.rb
106
62
  - lib/proscenium/css_module/transformer.rb
107
63
  - lib/proscenium/ensure_loaded.rb
108
64
  - lib/proscenium/ext/proscenium
@@ -115,10 +71,6 @@ files:
115
71
  - lib/proscenium/middleware/esbuild.rb
116
72
  - lib/proscenium/middleware/ruby_gems.rb
117
73
  - lib/proscenium/monkey.rb
118
- - lib/proscenium/phlex.rb
119
- - lib/proscenium/phlex/asset_inclusions.rb
120
- - lib/proscenium/phlex/css_modules.rb
121
- - lib/proscenium/phlex/react_component.rb
122
74
  - lib/proscenium/railtie.rb
123
75
  - lib/proscenium/react-manager/index.jsx
124
76
  - lib/proscenium/react-manager/react.js
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Object
4
- def instance_variable_get(name)
5
- name.is_a?(::Proscenium::CssModule::Name) ? super(name.to_sym) : super
6
- end
7
-
8
- def instance_variable_set(name, obj)
9
- name.is_a?(::Proscenium::CssModule::Name) ? super(name.to_sym, obj) : super
10
- end
11
-
12
- def instance_variable_defined?(name)
13
- name.is_a?(::Proscenium::CssModule::Name) ? super(name.to_sym) : super
14
- end
15
-
16
- def remove_instance_variable(name)
17
- name.is_a?(::Proscenium::CssModule::Name) ? super(name.to_sym) : super
18
- end
19
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ruby-next/language'
4
- require 'proscenium/core_ext/object/css_module_ivars'
5
-
6
- module Proscenium
7
- module CssModule
8
- class Rewriter < RubyNext::Language::Rewriters::Text
9
- NAME = 'proscenium-css-module'
10
-
11
- def rewrite(source)
12
- source = source.gsub(/%i\[((@[\w@ ]+)|([\w@ ]+ @[\w@ ]+))\]/) do |_|
13
- arr = ::Regexp.last_match(1).split.map do |x|
14
- x.start_with?('@') ? css_module_string(x[1..]) : ":#{x}"
15
- end
16
- "[#{arr.join(',')}]"
17
- end
18
-
19
- source.gsub(/:@([\w]+)/) do |_|
20
- context.track!(self)
21
- css_module_string(::Regexp.last_match(1))
22
- end
23
- end
24
-
25
- private
26
-
27
- def css_module_string(name)
28
- if (path = Pathname.new(context.path).sub_ext('.module.css')).exist?
29
- tname = Transformer.new(path).class_name!(name, name.dup).first
30
- "Proscenium::CssModule::Name.new(:@#{name}, '#{tname}', #{path})"
31
- else
32
- "Proscenium::CssModule::Name.new(:@#{name}, css_module(:#{name}), nil)"
33
- end
34
- end
35
- end
36
- end
37
- end
38
-
39
- RubyNext::Language.send :include_patterns=, []
40
- RubyNext::Language.include_patterns << "#{Rails.root.join('app', 'components')}/*.rb"
41
- RubyNext::Language.include_patterns << "#{Rails.root.join('app', 'views')}/*.rb"
42
- RubyNext::Language.rewriters = [Proscenium::CssModule::Rewriter]
43
-
44
- require 'ruby-next/language/runtime'
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Proscenium::Phlex::AssetInclusions
4
- def include_stylesheets
5
- comment { '[PROSCENIUM_STYLESHEETS]' }
6
- end
7
-
8
- def include_javascripts
9
- comment { '[PROSCENIUM_JAVASCRIPTS]' }
10
- end
11
-
12
- def include_assets
13
- include_stylesheets
14
- include_javascripts
15
- end
16
- end
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Proscenium
4
- module Phlex::CssModules
5
- include Proscenium::CssModule
6
-
7
- def self.included(base)
8
- base.extend CssModule::Path
9
- base.extend ClassMethods
10
- end
11
-
12
- module ClassMethods
13
- # Set of CSS module paths that have been resolved after being transformed from 'class' HTML
14
- # attributes. See #process_attributes. This is here because Phlex caches attributes. Which
15
- # means while the CSS class names will be transformed, any resolved paths will be lost in
16
- # subsequent requests.
17
- attr_accessor :resolved_css_module_paths
18
- end
19
-
20
- def before_template
21
- self.class.resolved_css_module_paths ||= Concurrent::Set.new
22
- super
23
- end
24
-
25
- def after_template
26
- self.class.resolved_css_module_paths ||= Concurrent::Set.new
27
- self.class.resolved_css_module_paths.each do |path|
28
- Proscenium::Importer.import path, sideloaded: true
29
- end
30
-
31
- super
32
- end
33
-
34
- # Resolve and side load any CSS modules in the "class" attributes, where a CSS module is a class
35
- # name beginning with a `@`. The class name is resolved to a CSS module name based on the file
36
- # system path of the Phlex class, and any CSS file is side loaded.
37
- #
38
- # For example, the following will side load the CSS module file at
39
- # app/components/user/component.module.css, and add the CSS Module name `user_name` to the
40
- # <div>.
41
- #
42
- # # app/components/user/component.rb
43
- # class User::Component < Proscenium::Phlex
44
- # def view_template
45
- # div class: :@user_name do
46
- # 'Joel Moss'
47
- # end
48
- # end
49
- # end
50
- #
51
- # Additionally, any class name containing a `/` is resolved as a CSS module path. Allowing you
52
- # to use the same syntax as a CSS module, but without the need to manually import the CSS file.
53
- #
54
- # For example, the following will side load the CSS module file at /lib/users.module.css, and
55
- # add the CSS Module name `name` to the <div>.
56
- #
57
- # class User::Component < Proscenium::Phlex
58
- # def view_template
59
- # div class: '/lib/users@name' do
60
- # 'Joel Moss'
61
- # end
62
- # end
63
- # end
64
- #
65
- # @raise [Proscenium::CssModule::Resolver::NotFound] If a CSS module file is not found for the
66
- # Phlex class file path.
67
- def process_attributes(**attributes)
68
- if attributes.key?(:class) && (attributes[:class] = tokens(attributes[:class])).include?('@')
69
- names = attributes[:class].is_a?(Array) ? attributes[:class] : attributes[:class].split
70
-
71
- self.class.resolved_css_module_paths ||= Concurrent::Set.new
72
-
73
- attributes[:class] = cssm.class_names(*names).map do |name, path|
74
- self.class.resolved_css_module_paths << path if path
75
- name
76
- end
77
- end
78
-
79
- attributes
80
- end
81
- end
82
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Proscenium
4
- # Renders a <div> for use with React components, with data attributes specifying the component
5
- # path and props.
6
- #
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.
11
- #
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 view_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 view_template(**attributes, &)
29
- send(root_tag, **{ data: data_attributes }.deep_merge(attributes), &)
30
- end
31
- end
32
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'phlex-rails'
4
-
5
- module Proscenium
6
- class Phlex < ::Phlex::HTML
7
- include Proscenium::SourcePath
8
- include CssModules
9
- include AssetInclusions
10
-
11
- module Sideload
12
- def before_template
13
- Proscenium::SideLoad.sideload_inheritance_chain self,
14
- helpers.controller.sideload_assets_options
15
-
16
- super
17
- end
18
- end
19
-
20
- class_attribute :sideload_assets_options
21
-
22
- class << self
23
- attr_accessor :abstract_class
24
-
25
- def inherited(child)
26
- child.prepend Sideload
27
-
28
- super
29
- end
30
-
31
- def sideload_assets(value)
32
- self.sideload_assets_options = value
33
- end
34
- end
35
- end
36
- end