proscenium 0.18.0-arm64-darwin → 0.19.0-arm64-darwin

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -174
  3. data/lib/proscenium/builder.rb +36 -100
  4. data/lib/proscenium/bundled_gems.rb +37 -0
  5. data/lib/proscenium/css_module/path.rb +2 -1
  6. data/lib/proscenium/css_module/transformer.rb +1 -1
  7. data/lib/proscenium/css_module.rb +16 -9
  8. data/lib/proscenium/ensure_loaded.rb +14 -10
  9. data/lib/proscenium/ext/proscenium +0 -0
  10. data/lib/proscenium/ext/proscenium.h +9 -36
  11. data/lib/proscenium/helper.rb +4 -22
  12. data/lib/proscenium/importer.rb +39 -21
  13. data/lib/proscenium/log_subscriber.rb +11 -10
  14. data/lib/proscenium/middleware/base.rb +11 -6
  15. data/lib/proscenium/middleware/esbuild.rb +8 -9
  16. data/lib/proscenium/middleware/ruby_gems.rb +23 -0
  17. data/lib/proscenium/middleware.rb +26 -24
  18. data/lib/proscenium/monkey.rb +5 -14
  19. data/lib/proscenium/railtie.rb +11 -53
  20. data/lib/proscenium/{libs/react-manager → react-manager}/index.jsx +3 -22
  21. data/lib/proscenium/react_componentable.rb +2 -3
  22. data/lib/proscenium/resolver.rb +14 -23
  23. data/lib/proscenium/side_load.rb +41 -74
  24. data/lib/proscenium/utils.rb +33 -0
  25. data/lib/proscenium/version.rb +1 -1
  26. data/lib/proscenium.rb +2 -12
  27. metadata +11 -99
  28. data/lib/proscenium/core_ext/object/css_module_ivars.rb +0 -19
  29. data/lib/proscenium/css_module/rewriter.rb +0 -44
  30. data/lib/proscenium/libs/custom_element.js +0 -54
  31. data/lib/proscenium/libs/stimulus-loading.js +0 -65
  32. data/lib/proscenium/libs/test.js +0 -1
  33. data/lib/proscenium/libs/ujs/class.js +0 -15
  34. data/lib/proscenium/libs/ujs/data_confirm.js +0 -23
  35. data/lib/proscenium/libs/ujs/data_disable_with.js +0 -68
  36. data/lib/proscenium/libs/ujs/index.js +0 -9
  37. data/lib/proscenium/middleware/engines.rb +0 -45
  38. data/lib/proscenium/middleware/runtime.rb +0 -18
  39. data/lib/proscenium/phlex/asset_inclusions.rb +0 -17
  40. data/lib/proscenium/phlex/css_modules.rb +0 -79
  41. data/lib/proscenium/phlex/react_component.rb +0 -32
  42. data/lib/proscenium/phlex.rb +0 -42
  43. data/lib/proscenium/ui/breadcrumbs/component.module.css +0 -14
  44. data/lib/proscenium/ui/breadcrumbs/component.rb +0 -73
  45. data/lib/proscenium/ui/breadcrumbs/computed_element.rb +0 -69
  46. data/lib/proscenium/ui/breadcrumbs/control.rb +0 -95
  47. data/lib/proscenium/ui/breadcrumbs/mixins.css +0 -83
  48. data/lib/proscenium/ui/breadcrumbs.rb +0 -72
  49. data/lib/proscenium/ui/component.rb +0 -7
  50. data/lib/proscenium/ui/test.js +0 -1
  51. data/lib/proscenium/ui.rb +0 -8
  52. data/lib/proscenium/view_component/css_modules.rb +0 -11
  53. data/lib/proscenium/view_component/react_component.rb +0 -22
  54. data/lib/proscenium/view_component/sideload.rb +0 -4
  55. data/lib/proscenium/view_component.rb +0 -38
  56. /data/lib/proscenium/{libs/react-manager → react-manager}/react.js +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97b6762190186f202a4c47c31df4b917b1ac8aba94617a556bab8a3b405f10cb
4
- data.tar.gz: 1aafadc1a8b26192d92982399e00552e3e2e21c2fe2cabb1699e2ce5bc19a371
3
+ metadata.gz: e499453d502c9d28561f82b1e150fbfc6a3f2156f0ef75f41bddc7a1a1d9f693
4
+ data.tar.gz: 5be3e2606e7198d94e74286f5ed3f64df99e39b01d9f56fc8d05fac77fbc0c5c
5
5
  SHA512:
6
- metadata.gz: 955b20a69c4dab9a8ec2fc17892a819dbda39ddfb440e9a0a7b184f3f124f40a82dcb4b31c46c13b91d231b66811399fb465e493ce6399499583c27a15309bce
7
- data.tar.gz: e10d3aec815547b202fffa97242f40afd76f16e8adf01405192135f26dc267cb271fa0e54560931775cba61b24d88a9ac3f0bccf9ba594fa2cd02ee8e9f9d9c3
6
+ metadata.gz: 9bcfa44958a053cdf4c0574856db0e520e2cd450b01c692cf9e4cd3737c46e56fbadbd405639c0aac98a45e693731f3b3ec71211384f8f3f91a9196359824264
7
+ data.tar.gz: 6ba4f3dc8c3b8df5217b2e8edb8e781f8cd870399ceaadb293a104f564f25e54fd6742b7d4dc01793e2b5c602673b030975450b012347b511fdc3cb5b49b7579
data/README.md CHANGED
@@ -6,17 +6,17 @@
6
6
  >
7
7
  > - _the part of a theatre stage in front of the curtain._
8
8
 
9
- **_Proscenium_** treats your frontend and client-side code as first class citizens of your Rails app, and assumes a "fast by default" internet. It bundles and minifies JavaScript (+ JSX), TypeScript (+TSX) and CSS in real time, on demand, and with zero configuration.
9
+ **_Proscenium_** treats your frontend and client-side code as first class citizens of your Rails app, and assumes a "fast by default" internet. It bundles and minifies JavaScript (+JSX), TypeScript (+TSX) and CSS in real time, on demand, and with zero configuration.
10
10
 
11
11
  **The highlights:**
12
12
 
13
13
  - Fast, real-time bundling, tree-shaking, code-splitting and minification of Javascript (.js,.jsx), Typescript (.ts,.tsx) and CSS (.css).
14
14
  - NO JavaScript runtime needed (eg. Node) - just the browser!
15
15
  - NO build step or pre-compilation.
16
- - NO additional process or server - Just run `rails s`!
16
+ - NO additional process or server - Just run `rails server`!
17
17
  - Transforms newer JavaScript and CSS syntax to older syntax for older browsers.
18
18
  - Deep integration with Rails.
19
- - Automatically side-load your layouts, views, and partials.
19
+ - Automatically side-load JS and CSS for your layouts, views, and partials.
20
20
  - Import from NPM, URL's, and locally.
21
21
  - Server-side import map support.
22
22
  - CSS Modules & mixins.
@@ -48,12 +48,9 @@
48
48
  - [Typescript Caveats](#typescript-caveats)
49
49
  - [JSX](#jsx)
50
50
  - [JSON](#json)
51
- - [Phlex Support](#phlex-support)
52
- - [ViewComponent Support](#viewcomponent-support)
53
51
  - [Cache Busting](#cache-busting)
54
52
  - [rjs is back!](#rjs-is-back)
55
53
  - [Resolution](#resolution)
56
- - [Assets from Rails Engines](#assets-from-rails-engines)
57
54
  - [Thanks](#thanks)
58
55
  - [Development](#development)
59
56
 
@@ -78,15 +75,15 @@ gem 'proscenium'
78
75
 
79
76
  Please note that Proscenium is designed solely for use with Rails.
80
77
 
81
- Now if you start your Rails app, you can open any front end code (JS, CSS, etc.). For example, a file at `app/assets/stylesheets/application.css` can be accessed at `https://localhost:3000/app/assets/stylesheets/application.css`, which will be bundled, transformed, and minified [in production] in real time.
78
+ Now if you start your Rails app, you can open any front end code (JS, CSS, etc.). For example, a file at `app/assets/stylesheets/application.css` can be accessed at `https://localhost:3000/app/assets/stylesheets/application.css`, which will be transformed, bundled, and minified [in production] in real time.
82
79
 
83
80
  ## Client-Side Code Anywhere
84
81
 
85
- Proscenium believes that your frontend code is just as important as your backend code, and is not an afterthought - they should be first class citizens of your Rails app. So instead of having to throw all your JS and CSS into a "app/assets" directory, and then requiring a separate process to compile or bundle, just put them wherever you want within your app, and just run Rails!
82
+ Proscenium believes that your frontend code is just as important as your backend code, and is not an afterthought - they should be first class citizens of your Rails app. So instead of having to throw all your JS and CSS into a "app/assets" directory, and then requiring a separate process to compile or bundle, you can simply put them wherever you want within your app, and just run Rails!
86
83
 
87
84
  For example, if you have some JS that is required by your `app/views/users/index.html.erb` view, just create a JS file alongside it at `app/views/users/index.js`. Or if you have some CSS that is used by your entire application, put it in `app/views/layouts/application.css` and load it alongside your layout. Maybe you have a few JS utility functions, so put them in `lib/utils.js`.
88
85
 
89
- Simply put your JS(X) and CSS anywhere you want, and they will be served by your Rails app from the location where you placed them.
86
+ Simply put your JS(X) and CSS anywhere you want, and they will be served by your Rails app from the same location where you placed them.
90
87
 
91
88
  Using the examples above...
92
89
 
@@ -98,15 +95,15 @@ Using the examples above...
98
95
 
99
96
  ## Side Loading
100
97
 
101
- Proscenium is best experienced when your assets are automtically side loaded.
98
+ Proscenium is best experienced when your assets are automatically side loaded.
102
99
 
103
100
  ### The Problem
104
101
 
105
- With Rails you would typically declaratively load your JavaScript and CSS assets using the `javascript_include_tag` and `stylesheet_link_tag` helpers.
102
+ With Rails you would typically load your JavaScript and CSS assets declaratively using the `javascript_include_tag` and `stylesheet_link_tag` helpers.
106
103
 
107
- For example, you may have top-level "application" CSS located in a file at `/app/assets/stylesheets/application.css`. Likewise, you may have some global JavaScript located in a file at `/app/javascript/application.js`.
104
+ For example, you may have top-level "application" styles located in a file at `/app/assets/stylesheets/application.css`. Likewise, you may have some global JavaScript located in a file at `/app/javascript/application.js`.
108
105
 
109
- You would manually and declaratively include those two files in your application layout, something like this:
106
+ You would manually and declaratively include those two files in each of your layouts, something like this:
110
107
 
111
108
  ```erb
112
109
  <%# /app/views/layouts/application.html.erb %>
@@ -144,7 +141,9 @@ The main problem is that you have to keep track of all these assets, and make su
144
141
 
145
142
  When side loading your JavaScript, Typescript and CSS with Proscenium, they are automatically included alongside your views, partials, layouts, and components, and only when needed.
146
143
 
147
- Side loading works by looking for a JS/TS/CSS file with the same name as your view, partial, layout or component. For example, if you have a view at `app/views/users/index.html.erb`, then Proscenium will look for a JS/TS/CSS file at `app/views/users/index.js`, `app/views/users/index.ts` or `app/views/users/index.css`. If it finds one, it will include it in the HTML for that view.
144
+ Side loading works by looking for a JS/TS/CSS file with the same name as your view, partial, layout or component. For example, if you have a view at `app/views/users/index.html.erb`, then Proscenium will look for a JS and CSS file at `app/views/users/index.js` (or TypeScript with a .ts extension) and `app/views/users/index.css`. If it finds one, it will automatically include it in the HTML for that view. And only for that view.
145
+
146
+ This allows you to keep your assets organized alongside the views, partials, and components that use them, without having to manually track and include them. It also means only the assets that are needed are included.
148
147
 
149
148
  JSX is also supported for JavaScript and Typescript. Simply use the `.jsx` or `.tsx` extension instead of `.js` or `.ts`.
150
149
 
@@ -253,15 +252,13 @@ import Header from "/app/components/header";
253
252
 
254
253
  ### Unbundling
255
254
 
256
- Sometimes you don't want to bundle an import. For example, you want to ensure that only one instance of React is loaded. In this cases, you can use the `unbundle` prefix
255
+ Sometimes you don't want to bundle an import. For example, you want to ensure that only one instance of React is loaded. In these cases, you can use the `unbundle` import attribute:
257
256
 
258
257
  ```js
259
- import React from "unbundle:react";
258
+ import React from "react" with { unbundle: 'true' };
260
259
  ```
261
260
 
262
- This only works any bare and local imports.
263
-
264
- You can also use the `unbundle` prefix in your [import map](#import-maps), which ensures that all imports of a particular path is always unbundled:
261
+ You can also unbundle entries in your [import map](#import-maps) using an `unbundle:` prefix, which ensures that all imports of a particular path are always unbundled:
265
262
 
266
263
  ```json
267
264
  {
@@ -277,6 +274,14 @@ Then just import as normal:
277
274
  import React from "react";
278
275
  ```
279
276
 
277
+ Or if you don't want any bundling at all, simply turn it off application-wide:
278
+
279
+ ```ruby
280
+ config.proscenium.bundle = false
281
+ ```
282
+
283
+ This will mean every asset and import will be loaded independently.
284
+
280
285
  ## Import Maps
281
286
 
282
287
  > **[WIP]**
@@ -413,7 +418,7 @@ if (typeof proscenium.env?.UNKNOWN !== "undefined") {
413
418
  Basic support is provided for importing your Rails locale files from `config/locales/*.yml`, exporting them as JSON.
414
419
 
415
420
  ```js
416
- import translations from "@proscenium/i18n";
421
+ import translations from "proscenium/i18n";
417
422
  // translations.en.*
418
423
  ```
419
424
 
@@ -446,8 +451,6 @@ one();
446
451
 
447
452
  ### Code Splitting
448
453
 
449
- > Available in `>=0.10.0`.
450
-
451
454
  [Side loaded](#side-loading) assets are automatically code split. This means that if you have a file that is imported and used imported several times, and by different files, it will be split off into a separate file.
452
455
 
453
456
  As an example:
@@ -685,140 +688,8 @@ import { version } from "./package.json";
685
688
  console.log(version);
686
689
  ```
687
690
 
688
- ## Phlex Support
689
-
690
- [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`.
691
-
692
- ```ruby
693
- class MyView < Proscenium::Phlex
694
- def view_template
695
- h1 { 'Hello World' }
696
- end
697
- end
698
- ```
699
-
700
- In your layouts, include `Proscenium::Phlex::AssetInclusions`, and call the `include_assets` helper.
701
-
702
- ```ruby
703
- class ApplicationLayout < Proscenium::Phlex
704
- include Proscenium::Phlex::AssetInclusions # <--
705
-
706
- def view_template(&)
707
- doctype
708
- html do
709
- head do
710
- title { 'My Awesome App' }
711
- include_assets # <--
712
- end
713
- body(&)
714
- end
715
- end
716
- end
717
- ```
718
-
719
- 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.
720
-
721
- ### Side-loading
722
-
723
- Any Phlex class that inherits `Proscenium::Phlex` will automatically be [side-loaded](#side-loading).
724
-
725
- ### CSS Modules
726
-
727
- [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.
728
-
729
- Within your Phlex classes, any class names that begin with `@` will be treated as a CSS module class.
730
-
731
- ```ruby
732
- # /app/views/users/show_view.rb
733
- class Users::ShowView < Proscenium::Phlex
734
- def view_template
735
- h1 class: :@user_name do
736
- @user.name
737
- end
738
- end
739
- end
740
- ```
741
-
742
- ```css
743
- /* /app/views/users/show_view.module.css */
744
- .userName {
745
- color: red;
746
- font-size: 50px;
747
- }
748
- ```
749
-
750
- 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.
751
-
752
- The view above will be rendered something like this:
753
-
754
- ```html
755
- <h1 class="user_name-ABCD1234"></h1>
756
- ```
757
-
758
- 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.
759
-
760
- ```ruby
761
- # /app/views/users/show_view.rb
762
- class Users::ShowView < Proscenium::Phlex
763
- def view_template
764
- h1 class: :[@user_name, :title] do
765
- @user.name
766
- end
767
- end
768
- end
769
- ```
770
-
771
- ```html
772
- <h1 class="user_name-ABCD1234 title">Joel Moss</h1>
773
- ```
774
-
775
- ## ViewComponent Support
776
-
777
- [ViewComponent](https://viewcomponent.org/) iA framework for creating reusable, testable & encapsulated view components, built to integrate seamlessly with Ruby on Rails. Proscenium works perfectly with ViewComponent, with support for side-loading, CSS modules, and more. Simply write your ViewComponent classes and inherit from `Proscenium::ViewComponent`.
778
-
779
- ```ruby
780
- class MyView < Proscenium::ViewComponent
781
- def call
782
- tag.h1 'Hello World'
783
- end
784
- end
785
- ```
786
-
787
- ### Side-loading
788
-
789
- Any ViewComponent class that inherits `Proscenium::ViewComponent` will automatically be [side-loaded](#side-loading).
790
-
791
- ### CSS Modules
792
-
793
- [CSS Modules](#css-modules) are fully supported in ViewComponent classes, with access to the [`css_module` helper](#in-your-views) if you need it.
794
-
795
- ```ruby
796
- # /app/components/user_component.rb
797
- class UserComponent < Proscenium::ViewComponent
798
- def view_template
799
- div.h1 @user.name, class: css_module(:user_name)
800
- end
801
- end
802
- ```
803
-
804
- ```css
805
- /* # /app/components/user_component.module.css */
806
- .userName {
807
- color: red;
808
- font-size: 50px;
809
- }
810
- ```
811
-
812
- The view above will be rendered something like this:
813
-
814
- ```html
815
- <h1 class="user_name-ABCD1234">Joel Moss</h1>
816
- ```
817
-
818
691
  ## Cache Busting
819
692
 
820
- > _COMING SOON_
821
-
822
693
  By default, all assets are not cached by the browser. But if in production, you populate the `REVISION` env variable, all CSS and JS URL's will be appended with its value as a query string, and the `Cache-Control` response header will be set to `public` and a max-age of 30 days.
823
694
 
824
695
  For example, if you set `REVISION=v1`, URL's will be appended with `?v1`: `/my/imported/file.js?v1`.
@@ -851,26 +722,6 @@ You can continue to access any file in the `/public` directory as you normally w
851
722
 
852
723
  If requesting a file that exists in a root directory and the public directory, the file in the public directory will be served. For example, if you have a file at `/lib/foo.js` and `/public/lib/foo.js`, and you request `/lib/foo.js`, the file in the public directory (`/public/lib/foo.js`) will be served.
853
724
 
854
- ### Assets from Rails Engines
855
-
856
- Proscenium can serve assets from Rails Engines that are installed in your Rails app.
857
-
858
- An engine that wants to expose its assets via Proscenium to the application must add Proscenium as a dependency, and add itself to the list of engines in the Proscenium config options `Proscenium.config.engines`.
859
-
860
- For example, we have a gem called `gem1` that has Proscenium as a dependency, and exposes a Rails engine. It has some assets that it wants to expose to the application. To do this, it adds itself to the list of engines in the Proscenium config `engines` option:
861
-
862
- ```ruby
863
- class Gem1::Engine < ::Rails::Engine
864
- config.proscenium.engines << self
865
- end
866
- ```
867
-
868
- When this gem is installed in any Rails application, its assets will be available at the URL `/gem1/...`. For example, if the gem has a file `lib/styles.css`, it can be requested at `/gem1/lib/styles.css`.
869
-
870
- The same directories and file extensions are supported as for the application itself.
871
-
872
- It is important to note that the application takes precedence over the gem. So if the application has a file at `/public/gem1/lib/styles.css`, and the gem also has a file at `/lib/styles.css`, then the file in the application will be served. This is because both files would be accessible at the same URL: `/gem1/lib/styles.css`.
873
-
874
725
  ## Thanks
875
726
 
876
727
  HUGE thanks 🙏 go to [Evan Wallace](https://github.com/evanw) and his amazing [esbuild](https://esbuild.github.io/) project. Proscenium would not be possible without it, and it is esbuild that makes this so fast and efficient.
@@ -1,72 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'ffi'
4
- require 'oj'
5
4
 
6
5
  module Proscenium
7
6
  class Builder
8
7
  class CompileError < StandardError; end
9
8
 
9
+ ENVIRONMENTS = { development: 1, test: 2, production: 3 }.freeze
10
+
10
11
  class Result < FFI::Struct
11
12
  layout :success, :bool,
12
- :response, :string
13
+ :response, :string,
14
+ :content_hash, :string
13
15
  end
14
16
 
15
17
  module Request
16
18
  extend FFI::Library
19
+
17
20
  ffi_lib Pathname.new(__dir__).join('ext/proscenium').to_s
18
21
 
19
22
  enum :environment, [:development, 1, :test, :production]
20
23
 
21
24
  attach_function :build_to_string, [
22
- :string, # Path or entry point.
23
- :string, # Base URL of the Rails app. eg. https://example.com
24
- :string, # Path to import map, relative to root
25
- :string, # ENV variables as a JSON string
26
-
27
- # Config
28
- :string, # Rails application root
29
- :string, # Proscenium gem root
30
- :environment, # Rails environment as a Symbol
31
- :bool, # Code splitting enabled?
32
- :string, # Engine names and paths as a JSON string
33
- :bool # Debugging enabled?
34
- ], Result.by_value
35
-
36
- attach_function :build_to_path, [
37
- :string, # Path or entry point. Multiple can be given by separating with a semi-colon
38
- :string, # Base URL of the Rails app. eg. https://example.com
39
- :string, # Path to import map, relative to root
40
- :string, # ENV variables as a JSON string
41
-
42
- # Config
43
- :string, # Rails application root
44
- :string, # Proscenium gem root
45
- :environment, # Rails environment as a Symbol
46
- :bool, # Code splitting enabled?
47
- :string, # Engine names and paths as a JSON string
48
- :bool # Debugging enabled?
25
+ :string, # Path or entry point.
26
+ :pointer # Config as JSON.
49
27
  ], Result.by_value
50
28
 
51
29
  attach_function :resolve, [
52
- :string, # path or entry point
53
- :string, # path to import map, relative to root
54
-
55
- # Config
56
- :string, # Rails application root
57
- :string, # Proscenium gem root
58
- :environment, # Rails environment as a Symbol
59
- :bool # debugging enabled?
30
+ :string, # path or entry point
31
+ :pointer # Config as JSON.
60
32
  ], Result.by_value
33
+
34
+ attach_function :reset_config, [], :void
61
35
  end
62
36
 
63
37
  class BuildError < StandardError
64
38
  attr_reader :error
65
39
 
66
40
  def initialize(error)
67
- @error = Oj.load(error, mode: :strict).deep_transform_keys(&:underscore)
41
+ @error = JSON.parse(error, strict: true).deep_transform_keys(&:underscore)
68
42
 
69
43
  msg = @error['text']
44
+ msg << ' - ' << @error['detail'] if @error['detail'].is_a?(String)
70
45
  if (location = @error['location'])
71
46
  msg << " at #{location['file']}:#{location['line']}:#{location['column']}"
72
47
  end
@@ -83,65 +58,47 @@ module Proscenium
83
58
  end
84
59
  end
85
60
 
86
- def self.build_to_path(path, root: nil, base_url: nil)
87
- new(root:, base_url:).build_to_path(path)
88
- end
89
-
90
- def self.build_to_string(path, root: nil, base_url: nil)
91
- new(root:, base_url:).build_to_string(path)
61
+ def self.build_to_string(path, root: nil)
62
+ new(root:).build_to_string(path)
92
63
  end
93
64
 
94
65
  def self.resolve(path, root: nil)
95
66
  new(root:).resolve(path)
96
67
  end
97
68
 
98
- def initialize(root: nil, base_url: nil)
99
- @root = root || Rails.root
100
- @base_url = base_url
69
+ # Intended for tests only.
70
+ def self.reset_config!
71
+ Request.reset_config
101
72
  end
102
73
 
103
- def build_to_path(path)
104
- ActiveSupport::Notifications.instrument('build_to_path.proscenium',
105
- identifier: path,
106
- cached: Proscenium.cache.exist?(path)) do
107
- Proscenium.cache.fetch path do
108
- result = Request.build_to_path(path, @base_url, import_map, env_vars.to_json,
109
- @root.to_s,
110
- gem_root,
111
- Rails.env.to_sym,
112
- Proscenium.config.code_splitting,
113
- engines.to_json,
114
- Proscenium.config.debug)
115
-
116
- raise BuildError, result[:response] unless result[:success]
117
-
118
- result[:response]
119
- end
120
- end
74
+ def initialize(root: nil)
75
+ @request_config = FFI::MemoryPointer.from_string({
76
+ RootPath: (root || Rails.root).to_s,
77
+ GemPath: gem_root,
78
+ Environment: ENVIRONMENTS.fetch(Rails.env.to_sym, 2),
79
+ EnvVars: env_vars,
80
+ CodeSplitting: Proscenium.config.code_splitting,
81
+ RubyGems: Proscenium::BundledGems.paths,
82
+ Bundle: Proscenium.config.bundle,
83
+ QueryString: cache_query_string,
84
+ Debug: Proscenium.config.debug
85
+ }.to_json)
121
86
  end
122
87
 
123
88
  def build_to_string(path)
124
- ActiveSupport::Notifications.instrument('build_to_string.proscenium', identifier: path) do
125
- result = Request.build_to_string(path, @base_url, import_map, env_vars.to_json,
126
- @root.to_s,
127
- gem_root,
128
- Rails.env.to_sym,
129
- Proscenium.config.code_splitting,
130
- engines.to_json,
131
- Proscenium.config.debug)
89
+ ActiveSupport::Notifications.instrument('build.proscenium', identifier: path) do
90
+ result = Request.build_to_string(path, @request_config)
132
91
 
133
92
  raise BuildError, result[:response] unless result[:success]
134
93
 
135
- result[:response]
94
+ result
136
95
  end
137
96
  end
138
97
 
139
98
  def resolve(path)
140
99
  ActiveSupport::Notifications.instrument('resolve.proscenium', identifier: path) do
141
- result = Request.resolve(path, import_map, @root.to_s,
142
- gem_root,
143
- Rails.env.to_sym,
144
- Proscenium.config.debug)
100
+ result = Request.resolve(path, @request_config)
101
+
145
102
  raise ResolveError.new(path, result[:response]) unless result[:success]
146
103
 
147
104
  result[:response]
@@ -158,28 +115,7 @@ module Proscenium
158
115
  end
159
116
 
160
117
  def cache_query_string
161
- q = Proscenium.config.cache_query_string
162
- q ? "--cache-query-string #{q}" : nil
163
- end
164
-
165
- def engines
166
- Proscenium.config.engines.to_h { |e| [e.engine_name, e.root.to_s] }.tap do |x|
167
- x['proscenium/ui'] = Proscenium.ui_path.to_s
168
- end
169
- end
170
-
171
- def import_map
172
- return unless (path = Rails.root&.join('config'))
173
-
174
- if (json = path.join('import_map.json')).exist?
175
- return json.relative_path_from(@root).to_s
176
- end
177
-
178
- if (js = path.join('import_map.js')).exist?
179
- return js.relative_path_from(@root).to_s
180
- end
181
-
182
- nil
118
+ Proscenium.config.cache_query_string.presence || ''
183
119
  end
184
120
 
185
121
  def gem_root
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Proscenium
4
+ module BundledGems
5
+ module_function
6
+
7
+ def paths
8
+ @paths ||= begin
9
+ specs = Bundler.load.specs.reject { |s| s.name == 'bundler' }.sort_by(&:name)
10
+
11
+ raise 'No gems in your Gemfile' if specs.empty?
12
+
13
+ bundle = {}
14
+ specs.each do |s|
15
+ bundle[s.name] = if s.name == 'proscenium'
16
+ Pathname(s.full_gem_path).join('lib/proscenium').to_s
17
+ else
18
+ s.full_gem_path
19
+ end
20
+ end
21
+ bundle
22
+ end
23
+ end
24
+
25
+ def pathname_for(name)
26
+ (path = paths[name]) ? Pathname(path) : nil
27
+ end
28
+
29
+ def pathname_for!(name)
30
+ unless (path = pathname_for(name))
31
+ raise "Gem `#{name}` not found in your Gemfile"
32
+ end
33
+
34
+ path
35
+ end
36
+ end
37
+ end
@@ -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
@@ -70,7 +70,7 @@ module Proscenium
70
70
  digest = Importer.import(resolved_path)
71
71
 
72
72
  transformed_path = ''
73
- transformed_path = "__#{resolved_path[1..].gsub(%r{[/\.]}, '-')}" if Rails.env.development?
73
+ transformed_path = "__#{resolved_path[1..].gsub(%r{[@/.+]}, '-')}" if Rails.env.development?
74
74
  transformed_name = name.to_s
75
75
  transformed_name = if transformed_name.start_with?('_')
76
76
  "_#{transformed_name[1..]}-#{digest}#{transformed_path}"
@@ -5,6 +5,7 @@ module Proscenium::CssModule
5
5
 
6
6
  autoload :Path
7
7
  autoload :Transformer
8
+ autoload :Rewriter
8
9
 
9
10
  class TransformError < StandardError
10
11
  def initialize(name, additional_msg = nil)
@@ -15,21 +16,27 @@ module Proscenium::CssModule
15
16
  end
16
17
  end
17
18
 
18
- class Name
19
- def initialize(name, transform)
20
- @name = name
21
- @transform = transform
22
- end
19
+ module ClassMethods
20
+ def css_module(*names, path: nil)
21
+ path ||= respond_to?(:css_module_path) ? css_module_path : path
23
22
 
24
- def to_s
25
- @transform
23
+ cssm = Transformer.new(path)
24
+ cssm.class_names(*names, require_prefix: false).map { |name, _| name }.join(' ')
26
25
  end
27
26
 
28
- def to_sym
29
- @name
27
+ def class_names(*names, path: nil)
28
+ path ||= respond_to?(:css_module_path) ? css_module_path : path
29
+ names = names.flatten.compact
30
+
31
+ cssm = Transformer.new(path)
32
+ cssm.class_names(*names).map { |name, _| name }.join(' ') unless names.empty?
30
33
  end
31
34
  end
32
35
 
36
+ def self.included(base)
37
+ base.extend ClassMethods
38
+ end
39
+
33
40
  # Accepts one or more CSS class names, and transforms them into CSS module names.
34
41
  #
35
42
  # @param name [String,Symbol,Array<String,Symbol>]
@@ -7,17 +7,21 @@ module Proscenium
7
7
  def self.included(child)
8
8
  child.class_eval do
9
9
  append_after_action do
10
- if request.format.html? && Importer.imported?
11
- if Importer.js_imported?
12
- raise NotIncludedError, 'There are side loaded javascripts to be included, but ' \
13
- 'they have not been included in the page. Did you forget ' \
14
- 'to add the `#include_assets` helper in your views?'
15
- end
10
+ if request.format.html? && !response.redirect? && Importer.imported?
11
+ msg = <<-TEXT.squish
12
+ There are side loaded and imported assets to be included, but they have not been
13
+ included in the page. Did you forget to add the `#include_assets` helper in your
14
+ views? These assets were imported but not included:
15
+ #{Importer.imported.keys.to_sentence}
16
+ TEXT
16
17
 
17
- if Importer.css_imported?
18
- raise NotIncludedError, 'There are side loaded stylesheets to be included, but ' \
19
- 'they have not been included in the page. Did you forget ' \
20
- 'to add the `#include_assets` helper in your views?'
18
+ if Proscenium.config.ensure_loaded == :log
19
+ Rails.logger.warn do
20
+ "#{ActiveSupport::LogSubscriber.new.send(:color, ' [Proscenium]', nil,
21
+ bold: true)} #{msg}"
22
+ end
23
+ elsif Proscenium.config.ensure_loaded == :raise
24
+ raise NotIncludedError, msg
21
25
  end
22
26
  end
23
27
  end
Binary file