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.
- checksums.yaml +4 -4
- data/README.md +25 -174
- data/lib/proscenium/builder.rb +36 -100
- data/lib/proscenium/bundled_gems.rb +37 -0
- data/lib/proscenium/css_module/path.rb +2 -1
- data/lib/proscenium/css_module/transformer.rb +1 -1
- data/lib/proscenium/css_module.rb +16 -9
- data/lib/proscenium/ensure_loaded.rb +14 -10
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/ext/proscenium.h +9 -36
- data/lib/proscenium/helper.rb +4 -22
- data/lib/proscenium/importer.rb +39 -21
- data/lib/proscenium/log_subscriber.rb +11 -10
- data/lib/proscenium/middleware/base.rb +11 -6
- data/lib/proscenium/middleware/esbuild.rb +8 -9
- data/lib/proscenium/middleware/ruby_gems.rb +23 -0
- data/lib/proscenium/middleware.rb +26 -24
- data/lib/proscenium/monkey.rb +5 -14
- data/lib/proscenium/railtie.rb +11 -53
- data/lib/proscenium/{libs/react-manager → react-manager}/index.jsx +3 -22
- data/lib/proscenium/react_componentable.rb +2 -3
- data/lib/proscenium/resolver.rb +14 -23
- data/lib/proscenium/side_load.rb +41 -74
- data/lib/proscenium/utils.rb +33 -0
- data/lib/proscenium/version.rb +1 -1
- data/lib/proscenium.rb +2 -12
- metadata +11 -99
- data/lib/proscenium/core_ext/object/css_module_ivars.rb +0 -19
- data/lib/proscenium/css_module/rewriter.rb +0 -44
- data/lib/proscenium/libs/custom_element.js +0 -54
- data/lib/proscenium/libs/stimulus-loading.js +0 -65
- data/lib/proscenium/libs/test.js +0 -1
- data/lib/proscenium/libs/ujs/class.js +0 -15
- data/lib/proscenium/libs/ujs/data_confirm.js +0 -23
- data/lib/proscenium/libs/ujs/data_disable_with.js +0 -68
- data/lib/proscenium/libs/ujs/index.js +0 -9
- data/lib/proscenium/middleware/engines.rb +0 -45
- data/lib/proscenium/middleware/runtime.rb +0 -18
- data/lib/proscenium/phlex/asset_inclusions.rb +0 -17
- data/lib/proscenium/phlex/css_modules.rb +0 -79
- data/lib/proscenium/phlex/react_component.rb +0 -32
- data/lib/proscenium/phlex.rb +0 -42
- data/lib/proscenium/ui/breadcrumbs/component.module.css +0 -14
- data/lib/proscenium/ui/breadcrumbs/component.rb +0 -73
- data/lib/proscenium/ui/breadcrumbs/computed_element.rb +0 -69
- data/lib/proscenium/ui/breadcrumbs/control.rb +0 -95
- data/lib/proscenium/ui/breadcrumbs/mixins.css +0 -83
- data/lib/proscenium/ui/breadcrumbs.rb +0 -72
- data/lib/proscenium/ui/component.rb +0 -7
- data/lib/proscenium/ui/test.js +0 -1
- data/lib/proscenium/ui.rb +0 -8
- data/lib/proscenium/view_component/css_modules.rb +0 -11
- data/lib/proscenium/view_component/react_component.rb +0 -22
- data/lib/proscenium/view_component/sideload.rb +0 -4
- data/lib/proscenium/view_component.rb +0 -38
- /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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e499453d502c9d28561f82b1e150fbfc6a3f2156f0ef75f41bddc7a1a1d9f693
|
4
|
+
data.tar.gz: 5be3e2606e7198d94e74286f5ed3f64df99e39b01d9f56fc8d05fac77fbc0c5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 (+
|
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
|
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
|
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,
|
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
|
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
|
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"
|
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
|
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
|
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
|
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:
|
258
|
+
import React from "react" with { unbundle: 'true' };
|
260
259
|
```
|
261
260
|
|
262
|
-
|
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 "
|
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.
|
data/lib/proscenium/builder.rb
CHANGED
@@ -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,
|
23
|
-
:
|
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,
|
53
|
-
:
|
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 =
|
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.
|
87
|
-
new(root
|
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
|
-
|
99
|
-
|
100
|
-
|
69
|
+
# Intended for tests only.
|
70
|
+
def self.reset_config!
|
71
|
+
Request.reset_config
|
101
72
|
end
|
102
73
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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('
|
125
|
-
result = Request.build_to_string(path, @
|
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
|
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,
|
142
|
-
|
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
|
-
|
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) &&
|
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{[
|
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
|
-
|
19
|
-
def
|
20
|
-
|
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
|
-
|
25
|
-
|
23
|
+
cssm = Transformer.new(path)
|
24
|
+
cssm.class_names(*names, require_prefix: false).map { |name, _| name }.join(' ')
|
26
25
|
end
|
27
26
|
|
28
|
-
def
|
29
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|