proscenium 0.10.0-aarch64-linux → 0.11.0-aarch64-linux
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +207 -45
- data/lib/proscenium/builder.rb +41 -19
- data/lib/proscenium/css_module/path.rb +31 -0
- data/lib/proscenium/css_module/transformer.rb +82 -0
- data/lib/proscenium/css_module.rb +12 -25
- data/lib/proscenium/ensure_loaded.rb +27 -0
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/ext/proscenium.h +3 -2
- data/lib/proscenium/helper.rb +85 -0
- data/lib/proscenium/importer.rb +110 -0
- data/lib/proscenium/libs/react-manager/index.jsx +101 -0
- data/lib/proscenium/libs/react-manager/react.js +2 -0
- data/lib/proscenium/libs/test.js +1 -0
- data/lib/proscenium/middleware/base.rb +7 -7
- data/lib/proscenium/middleware/engines.rb +37 -0
- data/lib/proscenium/middleware/esbuild.rb +3 -5
- data/lib/proscenium/middleware/runtime.rb +18 -0
- data/lib/proscenium/middleware.rb +14 -4
- data/lib/proscenium/{side_load/monkey.rb → monkey.rb} +19 -15
- data/lib/proscenium/phlex/{resolve_css_modules.rb → css_modules.rb} +28 -16
- data/lib/proscenium/phlex/react_component.rb +26 -27
- data/lib/proscenium/phlex.rb +11 -30
- data/lib/proscenium/railtie.rb +44 -46
- data/lib/proscenium/react_componentable.rb +95 -0
- data/lib/proscenium/resolver.rb +37 -0
- data/lib/proscenium/side_load.rb +13 -73
- data/lib/proscenium/source_path.rb +15 -0
- data/lib/proscenium/templates/rescues/build_error.html.erb +30 -0
- data/lib/proscenium/utils.rb +13 -0
- data/lib/proscenium/version.rb +1 -1
- data/lib/proscenium/view_component/css_modules.rb +11 -0
- data/lib/proscenium/view_component/react_component.rb +15 -15
- data/lib/proscenium/view_component/sideload.rb +4 -0
- data/lib/proscenium/view_component.rb +8 -38
- data/lib/proscenium.rb +22 -68
- metadata +23 -30
- data/lib/proscenium/componentable.rb +0 -63
- data/lib/proscenium/css_module/class_names_resolver.rb +0 -66
- data/lib/proscenium/css_module/resolver.rb +0 -76
- data/lib/proscenium/current.rb +0 -9
- data/lib/proscenium/phlex/component_concerns.rb +0 -9
- data/lib/proscenium/phlex/page.rb +0 -62
- data/lib/proscenium/side_load/ensure_loaded.rb +0 -25
- data/lib/proscenium/side_load/helper.rb +0 -41
- data/lib/proscenium/view_component/tag_builder.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c9e2910c66b7815caac52459933e495e418d806dcc59ee468a1503516f3412b
|
4
|
+
data.tar.gz: 3362ffddc7b059ac0a9ed0d13ad072bd6e4bb5058e979cfb7bedb376a2db805d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60d02529097f5f539d0403b42f8f95d1f7349490a73cfc0b7c52792f05993dad85eea679ea40fb064946b2b803c9c1fc6b7a02893b7f01bb73ddebc2c40f3121
|
7
|
+
data.tar.gz: 16bcd2a02ab09654207ddb58d02728e08492a3e2973e1bdd5cb26a071639b128ecf07990bd50dfede00e1f56bfa3df22ea796ee5d717baeb45bb2b4f83184160
|
data/README.md
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
# Proscenium - Modern client-side development for Rails
|
2
2
|
|
3
|
-
Proscenium treats your client-side code as first class citizens of your Rails app, and assumes a
|
4
|
-
"fast by default" internet. It bundles your JS, JSX and CSS in real time, on demand, and with zero
|
5
|
-
configuration.
|
3
|
+
Proscenium treats your client-side code as first class citizens of your Rails app, and assumes a "fast by default" internet. It bundles your JavaScript and CSS in real time, on demand, and with zero configuration.
|
6
4
|
|
7
|
-
|
5
|
+
**The highlights:**
|
6
|
+
|
7
|
+
- Fast real-time bundling, tree-shaking, code-splitting and minification of Javascript (.js,.jsx), Typescript (.ts,.tsx) and CSS (.css).
|
8
8
|
- NO JavaScript runtime needed - just the browser!
|
9
9
|
- NO build step or pre-compilation.
|
10
10
|
- NO additional process or server - Just run Rails!
|
11
11
|
- Deep integration with Rails.
|
12
|
-
-
|
13
|
-
-
|
14
|
-
- Automatically side load JS/TS/CSS for your layouts and views.
|
15
|
-
- ESM importing from NPM, URLs, and locally.
|
12
|
+
- Automatically side-load your layouts, views, and partials.
|
13
|
+
- Import from NPM, URL's, and locally.
|
16
14
|
- Server-side import map support.
|
17
15
|
- CSS Modules & mixins.
|
18
16
|
- Source maps.
|
@@ -54,7 +52,7 @@ configuration.
|
|
54
52
|
|
55
53
|
## Getting Started
|
56
54
|
|
57
|
-
Getting started obviously depends on whether you are adding Proscenium to an existing Rails app, or creating a new
|
55
|
+
Getting started obviously depends on whether you are adding Proscenium to an existing Rails app, or creating a new one. So choose the appropriate guide below:
|
58
56
|
|
59
57
|
- [Getting Started with a new Rails app](https://github.com/joelmoss/proscenium/blob/master/docs/guides/new_rails_app.md)
|
60
58
|
- Getting Started with an existing Rails app
|
@@ -91,7 +89,7 @@ Using the examples above...
|
|
91
89
|
|
92
90
|
## Side Loading
|
93
91
|
|
94
|
-
> Prior to **0.10.0**, only assets with the extension `.js`, `.ts` and `.css` were side loaded. From 0.10.0, all assets are side loaded, including `.jsx`, and `.
|
92
|
+
> Prior to **0.10.0**, only assets with the extension `.js`, `.ts` and `.css` were side loaded. From 0.10.0, all assets are side loaded, including `.jsx`, `.tsx`, and `.module.css`. Also partials were not side loaded prior to 0.10.0.
|
95
93
|
|
96
94
|
Proscenium is best experienced when you side load your assets.
|
97
95
|
|
@@ -101,7 +99,7 @@ With Rails you would typically declaratively load your JavaScript and CSS assets
|
|
101
99
|
|
102
100
|
For example, you may have top-level "application" CSS located in a file at `/app/assets/application.css`. Likewise, you may have some global JavaScript located in a file at `/app/assets/application.js`.
|
103
101
|
|
104
|
-
You would include those two files in your application layout, something like this:
|
102
|
+
You would manually and declaratively include those two files in your application layout, something like this:
|
105
103
|
|
106
104
|
```erb
|
107
105
|
<%# /app/views/layouts/application.html.erb %>
|
@@ -119,7 +117,7 @@ You would include those two files in your application layout, something like thi
|
|
119
117
|
</html>
|
120
118
|
```
|
121
119
|
|
122
|
-
Now, you may have some CSS and JavaScript that is only required by a specific view and partial, so you would load that in your view, something like this:
|
120
|
+
Now, you may have some CSS and JavaScript that is only required by a specific view and partial, so you would load that in your view (or layout), something like this:
|
123
121
|
|
124
122
|
```erb
|
125
123
|
<%# /app/views/users/index.html.erb %>
|
@@ -163,25 +161,25 @@ Your application layout is at `/app/views/layouts/application.hml.erb`, and the
|
|
163
161
|
- `/app/views/users/index.js`
|
164
162
|
- `/app/views/users/_user.js` (partial)
|
165
163
|
|
166
|
-
Now, in your layout and view, replace the `javascript_include_tag` and `stylesheet_link_tag` helpers with the `
|
164
|
+
Now, in your layout and view, replace the `javascript_include_tag` and `stylesheet_link_tag` helpers with the `include_stylesheets` and `include_javascripts` helpers from Proscenium. Something like this:
|
167
165
|
|
168
166
|
```erb
|
169
167
|
<!DOCTYPE html>
|
170
168
|
<html>
|
171
169
|
<head>
|
172
170
|
<title>Hello World</title>
|
173
|
-
<%=
|
171
|
+
<%= include_stylesheets %>
|
174
172
|
</head>
|
175
173
|
<body>
|
176
174
|
<%= yield %>
|
177
|
-
<%=
|
175
|
+
<%= include_javascripts type: 'module', defer: true %>
|
178
176
|
</body>
|
179
177
|
</html>
|
180
178
|
```
|
181
179
|
|
182
180
|
> NOTE that Proscenium is desiged to work with modern JavaAscript, and assumes [ESModules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) are used everywhere. This is why the `type` attribute is set to `module` in the example above. If you are not using ESModules, then you can omit the `type` attribute.
|
183
181
|
|
184
|
-
On each page request, Proscenium will check if your views, layouts and partials have a JS/TS/CSS file of the same name, and then include them wherever your placed the `
|
182
|
+
On each page request, Proscenium will check if your views, layouts and partials have a JS/TS/CSS file of the same name, and then include them wherever your placed the `include_stylesheets` and `include_javascripts` helpers.
|
185
183
|
|
186
184
|
Now you never have to remember to include your assets again. Just create them alongside your views, partials and layouts, and Proscenium will take care of the rest.
|
187
185
|
|
@@ -229,6 +227,16 @@ import utils from '/lib/utils'
|
|
229
227
|
import constants from './constants'
|
230
228
|
```
|
231
229
|
|
230
|
+
```css /app/views/layouts/application.css
|
231
|
+
@import '/lib/reset';
|
232
|
+
```
|
233
|
+
|
234
|
+
```css /lib/reset.css
|
235
|
+
body {
|
236
|
+
/* some styles... */
|
237
|
+
}
|
238
|
+
```
|
239
|
+
|
232
240
|
## Import Maps
|
233
241
|
|
234
242
|
> **[WIP]**
|
@@ -397,14 +405,6 @@ one();
|
|
397
405
|
|
398
406
|
> Available in `>=0.10.0`.
|
399
407
|
|
400
|
-
> #### *Experimental!* 🧪
|
401
|
-
>
|
402
|
-
> Code splitting is currently experimentally and limited to side loaded code. It is disabled by default. You can enable code splitting by setting the `code_splitting` configuration option to `true` in your application's `/config/application.rb`:
|
403
|
-
>
|
404
|
-
> ```ruby
|
405
|
-
> config.proscenium.code_splitting = true
|
406
|
-
> ```
|
407
|
-
|
408
408
|
[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.
|
409
409
|
|
410
410
|
As an example:
|
@@ -438,6 +438,11 @@ If these files are side loaded, then `father.js` will be split off into a separa
|
|
438
438
|
|
439
439
|
- Without code splitting, an import() expression becomes `Promise.resolve().then(() => require())` instead. This still preserves the asynchronous semantics of the expression but it means the imported code is included in the same bundle instead of being split off into a separate file.
|
440
440
|
|
441
|
+
Code splitting is enabled by default. You can disable it by setting the `code_splitting` configuration option to `false` in your application's `/config/application.rb`:
|
442
|
+
```ruby
|
443
|
+
config.proscenium.code_splitting = false
|
444
|
+
```
|
445
|
+
|
441
446
|
### JavaScript Caveats
|
442
447
|
|
443
448
|
There are a few important caveats as far as JavaScript is concerned. These are [detailed on the esbuild site](https://esbuild.github.io/content-types/#javascript-caveats).
|
@@ -464,34 +469,74 @@ export let Button = ({ text }) => {
|
|
464
469
|
|
465
470
|
### CSS Modules
|
466
471
|
|
467
|
-
Proscenium implements a subset of [CSS Modules](https://github.com/css-modules/css-modules). It supports the `:local` and `:global` keywords, but not the `composes` property.
|
472
|
+
Proscenium implements a subset of [CSS Modules](https://github.com/css-modules/css-modules). It supports the `:local` and `:global` keywords, but not the `composes` property. (it is recommended that you use mixins instead of `composes`, as they will work everywhere, even in plain CSS files.)
|
468
473
|
|
469
|
-
Give any CSS file a `.module.css` extension, and Proscenium will
|
474
|
+
Give any CSS file a `.module.css` extension, and Proscenium will treat it as a CSS Module, transforming all class names with a suffix unique to the file.
|
470
475
|
|
471
476
|
```css
|
472
|
-
.
|
473
|
-
|
477
|
+
.title {
|
478
|
+
font-size: 20em;
|
474
479
|
}
|
475
480
|
```
|
476
481
|
|
477
482
|
The above input produces:
|
478
483
|
|
479
484
|
```css
|
480
|
-
.
|
481
|
-
|
485
|
+
.title-5564cdbb {
|
486
|
+
font-size: 20em;
|
482
487
|
}
|
483
488
|
```
|
484
489
|
|
485
|
-
|
490
|
+
You now have a unique class name that you can use pretty much anywhere.
|
491
|
+
|
492
|
+
#### In your Views
|
493
|
+
|
494
|
+
You can reference CSS modules from your Rails views, partials, and layouts using the `css_module` helper, which accepts one or more class names, and will return the equivilent CSS module names - the class name with the unique suffix appended.
|
495
|
+
|
496
|
+
With [side-loading](#side-loading) setup, you can use the `css_module` helper as follows.
|
497
|
+
|
498
|
+
```erb
|
499
|
+
<div>
|
500
|
+
<h1 class="<%= css_module :hello_title %>">Hello World</h1>
|
501
|
+
<p class="<%= css_module :body, paragraph: %>">
|
502
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
503
|
+
</p>
|
504
|
+
</div>
|
505
|
+
```
|
506
|
+
|
507
|
+
`css_module` accepts multiple class names, and will return a space-separated string of transformed CSS module names.
|
508
|
+
|
509
|
+
```ruby
|
510
|
+
css_module :my_module_name
|
511
|
+
# => "my_module_name-ABCD1234"
|
512
|
+
```
|
513
|
+
|
514
|
+
You can even reference a class from any CSS file by passing the URL path to the file, as a prefix to the class name. Doing so will automatically [side load](#side-loading) the stylesheet.
|
515
|
+
|
516
|
+
```ruby
|
517
|
+
css_module '/app/components/button.css@big_button'
|
518
|
+
# => "big_button"
|
519
|
+
```
|
520
|
+
|
521
|
+
It also supports NPM packages (already installed in /node_modules):
|
522
|
+
|
523
|
+
```ruby
|
524
|
+
css_module 'mypackage/button@big_button'
|
525
|
+
# => "big_button"
|
526
|
+
```
|
527
|
+
|
528
|
+
#### In your JavaScript
|
529
|
+
|
530
|
+
Importing a CSS module from JS will automatically append the stylesheet to the document's head. And the result of the import will be an object of CSS class to module names.
|
486
531
|
|
487
532
|
```js
|
488
533
|
import styles from './styles.module.css'
|
489
|
-
// styles == { header: '
|
534
|
+
// styles == { header: 'header-5564cdbb' }
|
490
535
|
```
|
491
536
|
|
492
|
-
It is important to note that the exported object of CSS module names is actually a Proxy object. So destructuring the object will not work. Instead, you must access the properties directly.
|
537
|
+
It is important to note that the exported object of CSS module names is actually a JavaScript [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) object. So destructuring the object will not work. Instead, you must access the properties directly.
|
493
538
|
|
494
|
-
Also, importing a CSS module
|
539
|
+
Also, importing a CSS module into another CSS module will result in the same digest string for all classes.
|
495
540
|
|
496
541
|
### CSS Mixins
|
497
542
|
|
@@ -589,11 +634,112 @@ console.log(version)
|
|
589
634
|
|
590
635
|
## Phlex Support
|
591
636
|
|
592
|
-
|
637
|
+
[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`.
|
638
|
+
|
639
|
+
```ruby
|
640
|
+
class MyView < Proscenium::Phlex
|
641
|
+
def template
|
642
|
+
h1 { 'Hello World' }
|
643
|
+
end
|
644
|
+
end
|
645
|
+
```
|
646
|
+
|
647
|
+
### Side-loading
|
648
|
+
|
649
|
+
Any Phlex class that inherits `Proscenium::Phlex` will automatically be [side-loaded](#side-loading).
|
650
|
+
|
651
|
+
### CSS Modules
|
652
|
+
|
653
|
+
[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.
|
654
|
+
|
655
|
+
Within your Phlex classes, any class names that begin with `@` will be treated as a CSS module class.
|
656
|
+
|
657
|
+
```ruby
|
658
|
+
# /app/views/users/show_view.rb
|
659
|
+
class Users::ShowView < Proscenium::Phlex
|
660
|
+
def template
|
661
|
+
h1 class: :@user_name do
|
662
|
+
@user.name
|
663
|
+
end
|
664
|
+
end
|
665
|
+
end
|
666
|
+
```
|
667
|
+
|
668
|
+
```css
|
669
|
+
/* /app/views/users/show_view.module.css */
|
670
|
+
.userName {
|
671
|
+
color: red;
|
672
|
+
font-size: 50px;
|
673
|
+
}
|
674
|
+
```
|
675
|
+
|
676
|
+
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.
|
677
|
+
|
678
|
+
The view above will be rendered something like this:
|
679
|
+
|
680
|
+
```html
|
681
|
+
<h1 class="user_name-ABCD1234"></h1>
|
682
|
+
```
|
683
|
+
|
684
|
+
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.
|
685
|
+
|
686
|
+
```ruby
|
687
|
+
# /app/views/users/show_view.rb
|
688
|
+
class Users::ShowView < Proscenium::Phlex
|
689
|
+
def template
|
690
|
+
h1 class: :[@user_name, :title] do
|
691
|
+
@user.name
|
692
|
+
end
|
693
|
+
end
|
694
|
+
end
|
695
|
+
```
|
696
|
+
|
697
|
+
```html
|
698
|
+
<h1 class="user_name-ABCD1234 title">Joel Moss</h1>
|
699
|
+
```
|
593
700
|
|
594
701
|
## ViewComponent Support
|
595
702
|
|
596
|
-
|
703
|
+
[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`.
|
704
|
+
|
705
|
+
```ruby
|
706
|
+
class MyView < Proscenium::ViewComponent
|
707
|
+
def call
|
708
|
+
tag.h1 'Hello World'
|
709
|
+
end
|
710
|
+
end
|
711
|
+
```
|
712
|
+
|
713
|
+
### Side-loading
|
714
|
+
|
715
|
+
Any ViewComponent class that inherits `Proscenium::ViewComponent` will automatically be [side-loaded](#side-loading).
|
716
|
+
|
717
|
+
### CSS Modules
|
718
|
+
|
719
|
+
[CSS Modules](#css-modules) are fully supported in ViewComponent classes, with access to the [`css_module` helper](#in-your-views) if you need it.
|
720
|
+
|
721
|
+
```ruby
|
722
|
+
# /app/components/user_component.rb
|
723
|
+
class UserComponent < Proscenium::ViewComponent
|
724
|
+
def template
|
725
|
+
div.h1 @user.name, class: css_module(:user_name)
|
726
|
+
end
|
727
|
+
end
|
728
|
+
```
|
729
|
+
|
730
|
+
```css
|
731
|
+
/* # /app/components/user_component.module.css */
|
732
|
+
.userName {
|
733
|
+
color: red;
|
734
|
+
font-size: 50px;
|
735
|
+
}
|
736
|
+
```
|
737
|
+
|
738
|
+
The view above will be rendered something like this:
|
739
|
+
|
740
|
+
```html
|
741
|
+
<h1 class="user_name-ABCD1234">Joel Moss</h1>
|
742
|
+
```
|
597
743
|
|
598
744
|
## Cache Busting
|
599
745
|
|
@@ -617,24 +763,40 @@ The cache is set with a `max-age` of 30 days. You can customise this with the `c
|
|
617
763
|
Rails.application.config.proscenium.cache_max_age = 12.months.to_i
|
618
764
|
```
|
619
765
|
|
620
|
-
## rjs is back
|
766
|
+
## rjs is back
|
621
767
|
|
622
768
|
Proscenium brings back RJS! Any path ending in .rjs will be served from your Rails app. This allows you to import server rendered javascript.
|
623
769
|
|
624
|
-
##
|
770
|
+
## Resolution
|
771
|
+
|
772
|
+
Proscenium will serve files ending with any of these extension: `js,mjs,ts,css,jsx,tsx` from the following directories, and their sub-directories of your Rails application's root: `/app`, `/lib`, `/config`, `/node_modules`, `/vendor`.
|
773
|
+
|
774
|
+
So a file at `/app/views/users/index.js` will be served from `https://yourapp.com/app/views/users/index.js`.
|
625
775
|
|
626
|
-
|
776
|
+
You can continue to access any file in the `/public` directory as you normally would. Proscenium will not process files in the `/public` directory.
|
627
777
|
|
628
|
-
|
778
|
+
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.
|
629
779
|
|
630
|
-
|
780
|
+
### Assets from Rails Engines
|
631
781
|
|
632
|
-
|
782
|
+
Proscenium can serve assets from Rails Engines that are installed in your Rails app.
|
783
|
+
|
784
|
+
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`.
|
785
|
+
|
786
|
+
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:
|
633
787
|
|
634
788
|
```ruby
|
635
|
-
|
789
|
+
class Gem1::Engine < ::Rails::Engine
|
790
|
+
config.proscenium.engines << self
|
791
|
+
end
|
636
792
|
```
|
637
793
|
|
794
|
+
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`.
|
795
|
+
|
796
|
+
The same directories and file extensions are supported as for the application itself.
|
797
|
+
|
798
|
+
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`.
|
799
|
+
|
638
800
|
## Thanks
|
639
801
|
|
640
802
|
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.
|
@@ -654,7 +816,7 @@ bundle exec rake compile:local
|
|
654
816
|
We have tests for both Ruby and Go. To run the Ruby tests:
|
655
817
|
|
656
818
|
```bash
|
657
|
-
bundle exec
|
819
|
+
bundle exec sus
|
658
820
|
```
|
659
821
|
|
660
822
|
To run the Go tests:
|
@@ -671,7 +833,7 @@ go test ./internal/builder -bench=. -run="^$" -count=10 -benchmem
|
|
671
833
|
|
672
834
|
## Contributing
|
673
835
|
|
674
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/joelmoss/proscenium
|
836
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/joelmoss/proscenium>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/joelmoss/proscenium/blob/master/CODE_OF_CONDUCT.md).
|
675
837
|
|
676
838
|
## License
|
677
839
|
|
data/lib/proscenium/builder.rb
CHANGED
@@ -25,9 +25,11 @@ module Proscenium
|
|
25
25
|
:string, # ENV variables as a JSON string
|
26
26
|
|
27
27
|
# Config
|
28
|
-
:string, # root
|
28
|
+
:string, # Rails application root
|
29
|
+
:string, # Proscenium gem root
|
29
30
|
:environment, # Rails environment as a Symbol
|
30
31
|
:bool, # code splitting enabled?
|
32
|
+
:string, # engine names and paths as a JSON string
|
31
33
|
:bool # debugging enabled?
|
32
34
|
], Result.by_value
|
33
35
|
|
@@ -36,18 +38,25 @@ module Proscenium
|
|
36
38
|
:string, # path to import map, relative to root
|
37
39
|
|
38
40
|
# Config
|
39
|
-
:string, # root
|
40
|
-
:
|
41
|
+
:string, # Rails application root
|
42
|
+
:string, # Proscenium gem root
|
43
|
+
:environment, # Rails environment as a Symbol
|
44
|
+
:bool # debugging enabled?
|
41
45
|
], Result.by_value
|
42
46
|
end
|
43
47
|
|
44
48
|
class BuildError < StandardError
|
45
|
-
attr_reader :error
|
49
|
+
attr_reader :error
|
46
50
|
|
47
|
-
def initialize(
|
48
|
-
error = Oj.load(error, mode: :strict).deep_transform_keys(&:underscore)
|
51
|
+
def initialize(error)
|
52
|
+
@error = Oj.load(error, mode: :strict).deep_transform_keys(&:underscore)
|
49
53
|
|
50
|
-
|
54
|
+
msg = @error['text']
|
55
|
+
if (location = @error['location'])
|
56
|
+
msg << " at #{location['file']}:#{location['line']}:#{location['column']}"
|
57
|
+
end
|
58
|
+
|
59
|
+
super msg
|
51
60
|
end
|
52
61
|
end
|
53
62
|
|
@@ -72,23 +81,32 @@ module Proscenium
|
|
72
81
|
@base_url = base_url
|
73
82
|
end
|
74
83
|
|
75
|
-
def build(path)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
84
|
+
def build(path) # rubocop:disable Metrics/AbcSize
|
85
|
+
ActiveSupport::Notifications.instrument('build.proscenium', identifier: path) do
|
86
|
+
result = Request.build(path, @base_url, import_map, env_vars.to_json,
|
87
|
+
@root.to_s,
|
88
|
+
Pathname.new(__dir__).join('..', '..').to_s,
|
89
|
+
Rails.env.to_sym,
|
90
|
+
Proscenium.config.code_splitting,
|
91
|
+
engines.to_json,
|
92
|
+
Proscenium.config.debug)
|
81
93
|
|
82
|
-
|
94
|
+
raise BuildError, result[:response] unless result[:success]
|
83
95
|
|
84
|
-
|
96
|
+
result[:response]
|
97
|
+
end
|
85
98
|
end
|
86
99
|
|
87
100
|
def resolve(path)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
101
|
+
ActiveSupport::Notifications.instrument('resolve.proscenium', identifier: path) do
|
102
|
+
result = Request.resolve(path, import_map, @root.to_s,
|
103
|
+
Pathname.new(__dir__).join('..', '..').to_s,
|
104
|
+
Rails.env.to_sym,
|
105
|
+
Proscenium.config.debug)
|
106
|
+
raise ResolveError.new(path, result[:response]) unless result[:success]
|
107
|
+
|
108
|
+
result[:response]
|
109
|
+
end
|
92
110
|
end
|
93
111
|
|
94
112
|
private
|
@@ -105,6 +123,10 @@ module Proscenium
|
|
105
123
|
q ? "--cache-query-string #{q}" : nil
|
106
124
|
end
|
107
125
|
|
126
|
+
def engines
|
127
|
+
Proscenium.config.engines.to_h { |e| [e.engine_name, e.root.to_s] }
|
128
|
+
end
|
129
|
+
|
108
130
|
def import_map
|
109
131
|
return unless (path = Rails.root&.join('config'))
|
110
132
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Proscenium
|
4
|
+
module CssModule::Path
|
5
|
+
# Returns the path to the CSS module file for this class, where the file is located alongside
|
6
|
+
# the class file, and has the same name as the class file, but with a `.module.css` extension.
|
7
|
+
#
|
8
|
+
# If the CSS module file does not exist, it's ancestry is checked, returning the first that
|
9
|
+
# exists. Then finally `nil` is returned if never found.
|
10
|
+
#
|
11
|
+
# @return [Pathname]
|
12
|
+
def css_module_path
|
13
|
+
return @css_module_path if instance_variable_defined?(:@css_module_path)
|
14
|
+
|
15
|
+
path = source_path.sub_ext('.module.css')
|
16
|
+
@css_module_path = path.exist? ? path : nil
|
17
|
+
|
18
|
+
unless @css_module_path
|
19
|
+
klass = superclass
|
20
|
+
|
21
|
+
while klass.respond_to?(:css_module_path) && !klass.abstract_class
|
22
|
+
break if (@css_module_path = klass.css_module_path)
|
23
|
+
|
24
|
+
klass = klass.superclass
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@css_module_path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Proscenium
|
4
|
+
class CssModule::Transformer
|
5
|
+
FILE_EXT = '.module.css'
|
6
|
+
|
7
|
+
def self.class_names(path, *names)
|
8
|
+
new(path).class_names(*names)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(source_path)
|
12
|
+
return unless (@source_path = source_path)
|
13
|
+
|
14
|
+
@source_path = Pathname.new(@source_path) unless @source_path.is_a?(Pathname)
|
15
|
+
@source_path = @source_path.sub_ext(FILE_EXT) unless @source_path.to_s.end_with?(FILE_EXT)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Transform each of the given class `names` to their respective CSS module name, which consist
|
19
|
+
# of the name, and suffixed with the digest of the resolved source path.
|
20
|
+
#
|
21
|
+
# Any name beginning with '@' will be transformed to a CSS module name. If `require_prefix` is
|
22
|
+
# false, then all names will be transformed to a CSS module name regardless of whether or not
|
23
|
+
# they begin with '@'.
|
24
|
+
#
|
25
|
+
# class_names :@my_module_name, :my_class_name
|
26
|
+
#
|
27
|
+
# Note that the generated digest is based on the resolved (URL) path, not the original path.
|
28
|
+
#
|
29
|
+
# You can also provide a path specifier and class name. The path will be the URL path to a
|
30
|
+
# stylesheet. The class name will be the name of the class to transform.
|
31
|
+
#
|
32
|
+
# class_names "/lib/button@default"
|
33
|
+
# class_names "mypackage/button@large"
|
34
|
+
# class_names "@scoped/package/button@small"
|
35
|
+
#
|
36
|
+
# @param names [String,Symbol,Array<String,Symbol>]
|
37
|
+
# @param require_prefix: [Boolean] whether or not to require the `@` prefix.
|
38
|
+
# @return [Array<String>] the transformed CSS module names.
|
39
|
+
def class_names(*names, require_prefix: true)
|
40
|
+
names.map do |name|
|
41
|
+
original_name = name.dup
|
42
|
+
name = name.to_s if name.is_a?(Symbol)
|
43
|
+
|
44
|
+
if name.include?('/')
|
45
|
+
if name.start_with?('@')
|
46
|
+
# Scoped bare specifier (eg. "@scoped/package/lib/button@default").
|
47
|
+
_, path, name = name.split('@')
|
48
|
+
path = "@#{path}"
|
49
|
+
else
|
50
|
+
# Local path (eg. /some/path/to/button@default") or bare specifier (eg.
|
51
|
+
# "mypackage/lib/button@default").
|
52
|
+
path, name = name.split('@')
|
53
|
+
end
|
54
|
+
|
55
|
+
class_name! name, original_name, path: "#{path}#{FILE_EXT}"
|
56
|
+
elsif name.start_with?('@')
|
57
|
+
class_name! name[1..], original_name
|
58
|
+
else
|
59
|
+
require_prefix ? name : class_name!(name, original_name)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def class_name!(name, original_name, path: @source_path)
|
65
|
+
unless path
|
66
|
+
raise Proscenium::CssModule::TransformError.new(original_name, 'CSS module path not given')
|
67
|
+
end
|
68
|
+
|
69
|
+
resolved_path = Resolver.resolve(path.to_s)
|
70
|
+
digest = Importer.import(resolved_path)
|
71
|
+
|
72
|
+
transformed_name = name.to_s
|
73
|
+
transformed_name = if transformed_name.start_with?('_')
|
74
|
+
"_#{transformed_name[1..]}-#{digest}"
|
75
|
+
else
|
76
|
+
"#{transformed_name}-#{digest}"
|
77
|
+
end
|
78
|
+
|
79
|
+
[transformed_name, resolved_path]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|