proscenium 0.16.0 → 0.19.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +64 -54
- data/lib/proscenium/builder.rb +34 -71
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/ext/proscenium.h +11 -32
- data/lib/proscenium/helper.rb +9 -3
- data/lib/proscenium/log_subscriber.rb +1 -1
- data/lib/proscenium/middleware/esbuild.rb +1 -2
- data/lib/proscenium/middleware.rb +0 -2
- data/lib/proscenium/railtie.rb +1 -0
- data/lib/proscenium/resolver.rb +5 -1
- data/lib/proscenium/side_load.rb +38 -10
- data/lib/proscenium/ui/breadcrumbs/component.module.css +1 -1
- data/lib/proscenium/ui/breadcrumbs/component.rb +8 -14
- data/lib/proscenium/ui/component.rb +0 -4
- data/lib/proscenium/ui/test.js +1 -1
- data/lib/proscenium/{libs → ui}/ujs/index.js +1 -1
- data/lib/proscenium/ui.rb +0 -6
- data/lib/proscenium/version.rb +1 -1
- data/lib/proscenium.rb +7 -0
- metadata +16 -46
- data/lib/proscenium/libs/test.js +0 -1
- data/lib/proscenium/middleware/url.rb +0 -16
- /data/lib/proscenium/{libs → ui}/custom_element.js +0 -0
- /data/lib/proscenium/{libs → ui}/react-manager/index.jsx +0 -0
- /data/lib/proscenium/{libs → ui}/react-manager/react.js +0 -0
- /data/lib/proscenium/{libs → ui}/stimulus-loading.js +0 -0
- /data/lib/proscenium/{libs → ui}/ujs/class.js +0 -0
- /data/lib/proscenium/{libs → ui}/ujs/data_confirm.js +0 -0
- /data/lib/proscenium/{libs → ui}/ujs/data_disable_with.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: c0ef99a0b3eea897d899b62e5cd298770db886a8271376eb04c8686a6078fcc9
|
4
|
+
data.tar.gz: 9787122129710ba85c76f6c762804d2e50ff6b7667a7949bc016f044f10cb983
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5a4d81385d795d350681e8150bccccd84fea0aaae377cf6ae060754fd3d1fb05eae207be86fb2390d8d75bac7e5d1351e4c5cbc0f38a4320e7b2616930fbae2
|
7
|
+
data.tar.gz: 58099ab856fa75ddacaee87c185ba228fa49e681525cc0711f0dded22b34535caf49508db53bbe2726b8c147d7e941398dd55079f13a106fd8c24d69ee053e4a
|
data/README.md
CHANGED
@@ -1,13 +1,20 @@
|
|
1
|
-
# Proscenium -
|
1
|
+
# Proscenium - Integrated Frontend Development for Rails
|
2
2
|
|
3
|
-
|
3
|
+
> 🗣️ prow · see · nee · uhm
|
4
|
+
>
|
5
|
+
> _noun_: **proscenium**
|
6
|
+
>
|
7
|
+
> - _the part of a theatre stage in front of the curtain._
|
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.
|
4
10
|
|
5
11
|
**The highlights:**
|
6
12
|
|
7
|
-
- Fast real-time bundling, tree-shaking, code-splitting and minification of Javascript (.js,.jsx), Typescript (.ts,.tsx) and CSS (.css).
|
8
|
-
- NO JavaScript runtime needed - just the browser!
|
13
|
+
- Fast, real-time bundling, tree-shaking, code-splitting and minification of Javascript (.js,.jsx), Typescript (.ts,.tsx) and CSS (.css).
|
14
|
+
- NO JavaScript runtime needed (eg. Node) - just the browser!
|
9
15
|
- NO build step or pre-compilation.
|
10
|
-
- NO additional process or server - Just run
|
16
|
+
- NO additional process or server - Just run `rails s`!
|
17
|
+
- Transforms newer JavaScript and CSS syntax to older syntax for older browsers.
|
11
18
|
- Deep integration with Rails.
|
12
19
|
- Automatically side-load your layouts, views, and partials.
|
13
20
|
- Import from NPM, URL's, and locally.
|
@@ -22,7 +29,6 @@ Proscenium treats your client-side code as first class citizens of your Rails ap
|
|
22
29
|
- [Client-Side Code Anywhere](#client-side-code-anywhere)
|
23
30
|
- [Side Loading](#side-loading)
|
24
31
|
- [Importing](#importing-assets)
|
25
|
-
- [URL Imports](#url-imports)
|
26
32
|
- [Local Imports](#local-imports)
|
27
33
|
- [Import Maps](#import-maps)
|
28
34
|
- [Source Maps](#source-maps)
|
@@ -70,7 +76,9 @@ Add this line to your Rails application's Gemfile, and you're good to go:
|
|
70
76
|
gem 'proscenium'
|
71
77
|
```
|
72
78
|
|
73
|
-
Please note that Proscenium is designed solely for use with Rails
|
79
|
+
Please note that Proscenium is designed solely for use with Rails.
|
80
|
+
|
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.
|
74
82
|
|
75
83
|
## Client-Side Code Anywhere
|
76
84
|
|
@@ -82,23 +90,21 @@ Simply put your JS(X) and CSS anywhere you want, and they will be served by your
|
|
82
90
|
|
83
91
|
Using the examples above...
|
84
92
|
|
85
|
-
- `app/views/users/index.js` => `https://
|
86
|
-
- `app/views/layouts/application.css` => `https://
|
87
|
-
- `lib/utils.js` => `https://
|
88
|
-
- `app/components/menu_component.jsx` => `https://
|
89
|
-
- `config/properties.css` => `https://
|
93
|
+
- `app/views/users/index.js` => `https://localhost:3000/app/views/users/index.js`
|
94
|
+
- `app/views/layouts/application.css` => `https://localhost:3000/app/views/layouts/application.css`
|
95
|
+
- `lib/utils.js` => `https://localhost:3000/lib/utils.js`
|
96
|
+
- `app/components/menu_component.jsx` => `https://localhost:3000/app/components/menu_component.jsx`
|
97
|
+
- `config/properties.css` => `https://localhost:3000/config/properties.css`
|
90
98
|
|
91
99
|
## Side Loading
|
92
100
|
|
93
|
-
|
94
|
-
|
95
|
-
Proscenium is best experienced when you side load your assets.
|
101
|
+
Proscenium is best experienced when your assets are automtically side loaded.
|
96
102
|
|
97
103
|
### The Problem
|
98
104
|
|
99
105
|
With Rails you would typically declaratively load your JavaScript and CSS assets using the `javascript_include_tag` and `stylesheet_link_tag` helpers.
|
100
106
|
|
101
|
-
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/
|
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`.
|
102
108
|
|
103
109
|
You would manually and declaratively include those two files in your application layout, something like this:
|
104
110
|
|
@@ -177,45 +183,55 @@ Now, in your layout and view, replace the `javascript_include_tag` and `styleshe
|
|
177
183
|
</html>
|
178
184
|
```
|
179
185
|
|
180
|
-
On each page request, Proscenium will check if any of your views, layouts and partials have a
|
181
|
-
|
182
|
-
|
186
|
+
On each page request, Proscenium will check if any of your views, layouts and partials have a JS/TS/CSS file of the same name, and then include them wherever your placed the `include_assets` helper.
|
187
|
+
|
188
|
+
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.
|
189
|
+
|
190
|
+
Side loading is enabled by default, but you can disable it by setting `config.proscenium.side_load` to `false` in your `/config/application.rb`.
|
191
|
+
|
192
|
+
There are also `include_stylesheets` and `include_javascripts` helpers to allow you to control where the CSS and JS assets are included in the HTML. These helpers should be used instead of `include_assets` if you want to control exactly where the assets are included.
|
183
193
|
|
184
|
-
|
185
|
-
partials and layouts, and Proscenium will take care of the rest.
|
194
|
+
## Bundling
|
186
195
|
|
187
|
-
|
188
|
-
to `false` in your `/config/application.rb`.
|
196
|
+
To bundle a file means to inline any imported dependencies into the file itself. This process is recursive so dependencies of dependencies (and so on) will also be inlined.
|
189
197
|
|
190
|
-
|
191
|
-
the CSS and JS assets are included in the HTML. These helpers should be used instead of
|
192
|
-
`include_assets` if you want to control exactly where the assets are included.
|
198
|
+
Proscenium will bundle by default, and in real time. So there is no separate build step or pre-compilation.
|
193
199
|
|
194
|
-
|
200
|
+
Proscenium supports importing JS, JSX, TS, TSX, CSS and SVG from NPM, by URL, your local app, and even from other Ruby Gems.
|
195
201
|
|
196
|
-
|
202
|
+
Both static ([`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)) and dynamic ([`import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import)) imports are supported for JavaScript and TypeScript, and can be used to import JS, TS, JSX, TSX, JSON, CSS and SVG files.
|
197
203
|
|
198
|
-
|
204
|
+
The [`@import`](https://developer.mozilla.org/en-US/docs/Web/CSS/@import) CSS at-rule is supported for CSS.
|
199
205
|
|
200
|
-
|
206
|
+
### Non-analyzable imports
|
201
207
|
|
202
|
-
|
208
|
+
Import paths are currently only bundled if they are a string literal or a glob pattern. Other forms of import paths are not bundled, and are instead preserved verbatim in the generated output. This is because bundling is a compile-time operation and Proscenium doesn't support all forms of run-time path resolution.
|
203
209
|
|
204
|
-
|
210
|
+
Here are some examples:
|
205
211
|
|
206
212
|
```js
|
207
|
-
|
208
|
-
|
213
|
+
// Analyzable imports (will be bundled)
|
214
|
+
import "pkg";
|
215
|
+
import("pkg");
|
216
|
+
import(`./locale-${foo}.json`);
|
209
217
|
|
210
|
-
|
211
|
-
|
218
|
+
// Non-analyzable imports (will not be bundled)
|
219
|
+
import(`pkg/${foo}`);
|
212
220
|
```
|
213
221
|
|
214
|
-
|
222
|
+
The way to work around non-analyzable imports is to mark the package containing this problematic code as [unbundled](#Unbundling) so that it's not included in the bundle. You will then need to ensure that a copy of the external package is available to your bundled code at run-time.
|
215
223
|
|
216
224
|
### Import from NPM (`node_modules`)
|
217
225
|
|
218
|
-
Bare imports (imports not beginning with `./`, `/`, `https://`, `http://`) are fully supported, and will use your package manager of choice (eg, NPM, Yarn, pnpm) via the `package.json` file
|
226
|
+
Bare imports (imports not beginning with `./`, `/`, `https://`, `http://`) are fully supported, and will use your package manager of choice (eg, NPM, Yarn, pnpm) via the `package.json` file located at the root of your Rails app.
|
227
|
+
|
228
|
+
Install the package you want to import using your package manager of choice...
|
229
|
+
|
230
|
+
```
|
231
|
+
npm install react
|
232
|
+
```
|
233
|
+
|
234
|
+
...and then import it as you would any other package.
|
219
235
|
|
220
236
|
```js
|
221
237
|
import React from "react";
|
@@ -223,26 +239,18 @@ import React from "react";
|
|
223
239
|
|
224
240
|
### Local Imports
|
225
241
|
|
226
|
-
And of course you can import your own code, using relative or absolute paths (file extension is optional):
|
242
|
+
And of course you can import your own code, using relative or absolute paths (file extension is optional, and absolute paths use your Rails root as the base):
|
227
243
|
|
228
|
-
```js
|
244
|
+
```js
|
229
245
|
import utils from "/lib/utils";
|
230
|
-
```
|
231
|
-
|
232
|
-
```js /lib/utils.js
|
233
246
|
import constants from "./constants";
|
247
|
+
import Header from "/app/components/header";
|
234
248
|
```
|
235
249
|
|
236
|
-
```css
|
250
|
+
```css
|
237
251
|
@import "/lib/reset";
|
238
252
|
```
|
239
253
|
|
240
|
-
```css /lib/reset.css
|
241
|
-
body {
|
242
|
-
/* some styles... */
|
243
|
-
}
|
244
|
-
```
|
245
|
-
|
246
254
|
### Unbundling
|
247
255
|
|
248
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
|
@@ -253,7 +261,7 @@ import React from "unbundle:react";
|
|
253
261
|
|
254
262
|
This only works any bare and local imports.
|
255
263
|
|
256
|
-
You can also use the `unbundle` prefix in your import map, which ensures that all imports of a particular path is always unbundled:
|
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:
|
257
265
|
|
258
266
|
```json
|
259
267
|
{
|
@@ -411,7 +419,7 @@ import translations from "@proscenium/i18n";
|
|
411
419
|
|
412
420
|
## Javascript
|
413
421
|
|
414
|
-
By default, Proscenium's output will take advantage of all modern JS features. For example, `a !== void 0 && a !== null ? a : b` will become `a ?? b` when minifying (enabled by default in production), which makes use of syntax from the ES2020 version of JavaScript.
|
422
|
+
By default, Proscenium's output will take advantage of all modern JS features from the ES2022 spec and earlier. For example, `a !== void 0 && a !== null ? a : b` will become `a ?? b` when minifying (enabled by default in production), which makes use of syntax from the ES2020 version of JavaScript. Any syntax feature that is not supported by ES2020 will be transformed into older JavaScript syntax that is more widely supported.
|
415
423
|
|
416
424
|
### Tree Shaking
|
417
425
|
|
@@ -491,6 +499,8 @@ Note that by default, Proscenium's output will take advantage of all modern CSS
|
|
491
499
|
|
492
500
|
The new CSS nesting syntax is supported, and transformed into non-nested CSS for older browsers.
|
493
501
|
|
502
|
+
Proscenium will also automatically insert vendor prefixes so that your CSS will work in older browsers.
|
503
|
+
|
494
504
|
### Importing CSS from JavaScript
|
495
505
|
|
496
506
|
You can also import CSS from JavaScript. When you do this, Proscenium will automatically append each stylesheet to the document's head as a `<link>` element.
|
@@ -835,7 +845,7 @@ Proscenium brings back RJS! Any path ending in .rjs will be served from your Rai
|
|
835
845
|
|
836
846
|
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`.
|
837
847
|
|
838
|
-
So a file at `/app/views/users/index.js` will be served from `https://
|
848
|
+
So a file at `/app/views/users/index.js` will be served from `https://localhost:3000/app/views/users/index.js`.
|
839
849
|
|
840
850
|
You can continue to access any file in the `/public` directory as you normally would. Proscenium will not process files in the `/public` directory.
|
841
851
|
|
@@ -880,7 +890,7 @@ bundle exec rake compile:local
|
|
880
890
|
We have tests for both Ruby and Go. To run the Ruby tests:
|
881
891
|
|
882
892
|
```bash
|
883
|
-
|
893
|
+
bin/test
|
884
894
|
```
|
885
895
|
|
886
896
|
To run the Go tests:
|
data/lib/proscenium/builder.rb
CHANGED
@@ -7,6 +7,8 @@ module Proscenium
|
|
7
7
|
class Builder
|
8
8
|
class CompileError < StandardError; end
|
9
9
|
|
10
|
+
ENVIRONMENTS = { development: 1, test: 2, production: 3 }.freeze
|
11
|
+
|
10
12
|
class Result < FFI::Struct
|
11
13
|
layout :success, :bool,
|
12
14
|
:response, :string
|
@@ -19,45 +21,21 @@ module Proscenium
|
|
19
21
|
enum :environment, [:development, 1, :test, :production]
|
20
22
|
|
21
23
|
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?
|
24
|
+
:string, # Path or entry point.
|
25
|
+
:pointer # Config as JSON.
|
34
26
|
], Result.by_value
|
35
27
|
|
36
28
|
attach_function :build_to_path, [
|
37
|
-
:string,
|
38
|
-
:
|
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?
|
29
|
+
:string, # Path or entry point. Multiple can be given by separating with a semi-colon
|
30
|
+
:pointer # Config as JSON.
|
49
31
|
], Result.by_value
|
50
32
|
|
51
33
|
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?
|
34
|
+
:string, # path or entry point
|
35
|
+
:pointer # Config as JSON.
|
60
36
|
], Result.by_value
|
37
|
+
|
38
|
+
attach_function :reset_config, [], :void
|
61
39
|
end
|
62
40
|
|
63
41
|
class BuildError < StandardError
|
@@ -83,21 +61,34 @@ module Proscenium
|
|
83
61
|
end
|
84
62
|
end
|
85
63
|
|
86
|
-
def self.build_to_path(path, root: nil
|
87
|
-
new(root
|
64
|
+
def self.build_to_path(path, root: nil)
|
65
|
+
new(root:).build_to_path(path)
|
88
66
|
end
|
89
67
|
|
90
|
-
def self.build_to_string(path, root: nil
|
91
|
-
new(root
|
68
|
+
def self.build_to_string(path, root: nil)
|
69
|
+
new(root:).build_to_string(path)
|
92
70
|
end
|
93
71
|
|
94
72
|
def self.resolve(path, root: nil)
|
95
73
|
new(root:).resolve(path)
|
96
74
|
end
|
97
75
|
|
98
|
-
|
99
|
-
|
100
|
-
|
76
|
+
# Intended for tests only.
|
77
|
+
def self.reset_config!
|
78
|
+
Request.reset_config
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize(root: nil)
|
82
|
+
@request_config = FFI::MemoryPointer.from_string({
|
83
|
+
RootPath: (root || Rails.root).to_s,
|
84
|
+
GemPath: gem_root,
|
85
|
+
Environment: ENVIRONMENTS.fetch(Rails.env.to_sym, 2),
|
86
|
+
Engines: engines,
|
87
|
+
EnvVars: env_vars,
|
88
|
+
CodeSplitting: Proscenium.config.code_splitting,
|
89
|
+
Bundle: Proscenium.config.bundle,
|
90
|
+
Debug: Proscenium.config.debug
|
91
|
+
}.to_json)
|
101
92
|
end
|
102
93
|
|
103
94
|
def build_to_path(path)
|
@@ -105,13 +96,7 @@ module Proscenium
|
|
105
96
|
identifier: path,
|
106
97
|
cached: Proscenium.cache.exist?(path)) do
|
107
98
|
Proscenium.cache.fetch path do
|
108
|
-
result = Request.build_to_path(path, @
|
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)
|
99
|
+
result = Request.build_to_path(path, @request_config)
|
115
100
|
|
116
101
|
raise BuildError, result[:response] unless result[:success]
|
117
102
|
|
@@ -122,13 +107,7 @@ module Proscenium
|
|
122
107
|
|
123
108
|
def build_to_string(path)
|
124
109
|
ActiveSupport::Notifications.instrument('build_to_string.proscenium', identifier: path) do
|
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)
|
110
|
+
result = Request.build_to_string(path, @request_config)
|
132
111
|
|
133
112
|
raise BuildError, result[:response] unless result[:success]
|
134
113
|
|
@@ -138,10 +117,8 @@ module Proscenium
|
|
138
117
|
|
139
118
|
def resolve(path)
|
140
119
|
ActiveSupport::Notifications.instrument('resolve.proscenium', identifier: path) do
|
141
|
-
result = Request.resolve(path,
|
142
|
-
|
143
|
-
Rails.env.to_sym,
|
144
|
-
Proscenium.config.debug)
|
120
|
+
result = Request.resolve(path, @request_config)
|
121
|
+
|
145
122
|
raise ResolveError.new(path, result[:response]) unless result[:success]
|
146
123
|
|
147
124
|
result[:response]
|
@@ -168,20 +145,6 @@ module Proscenium
|
|
168
145
|
end
|
169
146
|
end
|
170
147
|
|
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
|
183
|
-
end
|
184
|
-
|
185
148
|
def gem_root
|
186
149
|
Pathname.new(__dir__).join('..', '..').to_s
|
187
150
|
end
|
Binary file
|
@@ -82,49 +82,28 @@ typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
|
|
82
82
|
extern "C" {
|
83
83
|
#endif
|
84
84
|
|
85
|
+
extern void reset_config();
|
85
86
|
|
86
|
-
// Build the given `path`
|
87
|
+
// Build the given `path` using the `config`.
|
87
88
|
//
|
88
|
-
//
|
89
|
-
//
|
90
|
-
// - baseUrl - base URL of the Rails app. eg. https://example.com
|
91
|
-
// - importMap - Path to the import map relative to `root`.
|
92
|
-
// - envVars - JSON string of environment variables.
|
93
|
-
// Config:
|
94
|
-
// - root - The working directory.
|
95
|
-
// - env - The environment (1 = development, 2 = test, 3 = production)
|
96
|
-
// - codeSpitting?
|
97
|
-
// - debug?
|
89
|
+
// - path - The path to build relative to `root`.
|
90
|
+
// - config
|
98
91
|
//
|
99
|
-
extern struct Result build_to_string(char*
|
92
|
+
extern struct Result build_to_string(char* filePath, char* configJson);
|
100
93
|
|
101
94
|
// Build the given `path` in the `root`.
|
102
95
|
//
|
103
|
-
//
|
104
|
-
//
|
105
|
-
// with a semi-colon.
|
106
|
-
// - baseUrl - base URL of the Rails app. eg. https://example.com
|
107
|
-
// - importMap - Path to the import map relative to `root`.
|
108
|
-
// - envVars - JSON string of environment variables.
|
109
|
-
// Config:
|
110
|
-
// - root - The working directory.
|
111
|
-
// - env - The environment (1 = development, 2 = test, 3 = production)
|
112
|
-
// - codeSpitting?
|
113
|
-
// - debug?
|
96
|
+
// - path - The path to build relative to `root`.
|
97
|
+
// - config
|
114
98
|
//
|
115
|
-
extern struct Result build_to_path(char*
|
99
|
+
extern struct Result build_to_path(char* filePath, char* configJson);
|
116
100
|
|
117
101
|
// Resolve the given `path` relative to the `root`.
|
118
102
|
//
|
119
|
-
//
|
120
|
-
//
|
121
|
-
// - importMap - Path to the import map relative to `root`.
|
122
|
-
// Config
|
123
|
-
// - root - The working directory.
|
124
|
-
// - env - The environment (1 = development, 2 = test, 3 = production)
|
125
|
-
// - debug?
|
103
|
+
// - path - The path to build relative to `root`.
|
104
|
+
// - config
|
126
105
|
//
|
127
|
-
extern struct Result resolve(char*
|
106
|
+
extern struct Result resolve(char* filePath, char* configJson);
|
128
107
|
|
129
108
|
#ifdef __cplusplus
|
130
109
|
}
|
data/lib/proscenium/helper.rb
CHANGED
@@ -15,9 +15,15 @@ module Proscenium
|
|
15
15
|
# building with Proscenium. It's important to note that `include_assets` will not call this, as
|
16
16
|
# those asset paths all begin with a slash, which the Rails asset helpers do not pass through to
|
17
17
|
# here.
|
18
|
+
#
|
19
|
+
# If the given `path` is a bare path (does not start with `./` or `../`), then we use
|
20
|
+
# Rails default conventions, and serve CSS from /app/assets/stylesheets and JS from
|
21
|
+
# /app/javascript.
|
18
22
|
def compute_asset_path(path, options = {})
|
19
23
|
if %i[javascript stylesheet].include?(options[:type])
|
20
|
-
|
24
|
+
path.prepend DEFAULT_RAILS_ASSET_PATHS[options[:type]] unless path.start_with?('./', '../')
|
25
|
+
|
26
|
+
result = Proscenium::Builder.build_to_path(path)
|
21
27
|
return result.split('::').last.delete_prefix 'public'
|
22
28
|
end
|
23
29
|
|
@@ -53,7 +59,7 @@ module Proscenium
|
|
53
59
|
end
|
54
60
|
|
55
61
|
def include_stylesheets
|
56
|
-
|
62
|
+
SideLoad::CSS_COMMENT.html_safe
|
57
63
|
end
|
58
64
|
alias side_load_stylesheets include_stylesheets
|
59
65
|
deprecate side_load_stylesheets: 'Use `include_stylesheets` instead', deprecator: Deprecator.new
|
@@ -62,7 +68,7 @@ module Proscenium
|
|
62
68
|
#
|
63
69
|
# @return [String] the HTML tags for the javascripts.
|
64
70
|
def include_javascripts
|
65
|
-
|
71
|
+
(SideLoad::LAZY_COMMENT + SideLoad::JS_COMMENT).html_safe
|
66
72
|
end
|
67
73
|
alias side_load_javascripts include_javascripts
|
68
74
|
deprecate side_load_javascripts: 'Use `include_javascripts` instead', deprecator: Deprecator.new
|
@@ -27,7 +27,7 @@ module Proscenium
|
|
27
27
|
path = CGI.unescape(path) if path.start_with?(/https?%3A%2F%2F/)
|
28
28
|
|
29
29
|
info do
|
30
|
-
message = " #{color('[Proscenium]', nil, bold: true)} Building #{path}"
|
30
|
+
message = " #{color('[Proscenium]', nil, bold: true)} Building (to string) #{path}"
|
31
31
|
message << " (Duration: #{event.duration.round(1)}ms | Allocations: #{event.allocations})"
|
32
32
|
end
|
33
33
|
end
|
@@ -20,8 +20,7 @@ module Proscenium
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def attempt
|
23
|
-
render_response Builder.build_to_string(path_to_build
|
24
|
-
base_url: @request.base_url)
|
23
|
+
render_response Builder.build_to_string(path_to_build)
|
25
24
|
rescue Builder::CompileError => e
|
26
25
|
raise self.class::CompileError, { file: @request.fullpath, detail: e.message }, caller
|
27
26
|
end
|
@@ -11,7 +11,6 @@ module Proscenium
|
|
11
11
|
autoload :Esbuild
|
12
12
|
autoload :Engines
|
13
13
|
autoload :Runtime
|
14
|
-
autoload :Url
|
15
14
|
|
16
15
|
def initialize(app)
|
17
16
|
@app = app
|
@@ -41,7 +40,6 @@ module Proscenium
|
|
41
40
|
end
|
42
41
|
|
43
42
|
def find_type(request)
|
44
|
-
return Url if request.path.match?(%r{^/https?%3A%2F%2F})
|
45
43
|
return Runtime if request.path.match?(%r{^/@proscenium/})
|
46
44
|
return Esbuild if Pathname.new(request.path).fnmatch?(app_path_glob, File::FNM_EXTGLOB)
|
47
45
|
|
data/lib/proscenium/railtie.rb
CHANGED
data/lib/proscenium/resolver.rb
CHANGED
@@ -26,7 +26,11 @@ module Proscenium
|
|
26
26
|
elsif path.start_with?(Proscenium.ui_path.to_s)
|
27
27
|
path.delete_prefix Proscenium.root.join('lib').to_s
|
28
28
|
elsif (engine = Proscenium.config.engines.find { |e| path.start_with? "#{e.root}/" })
|
29
|
-
|
29
|
+
if engine.root.to_s.start_with?("#{Rails.root}/")
|
30
|
+
path.delete_prefix Rails.root.to_s
|
31
|
+
else
|
32
|
+
path.sub(/^#{engine.root}/, "/#{engine.engine_name}")
|
33
|
+
end
|
30
34
|
elsif path.start_with?("#{Rails.root}/")
|
31
35
|
path.delete_prefix Rails.root.to_s
|
32
36
|
else
|
data/lib/proscenium/side_load.rb
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
module Proscenium
|
4
4
|
class SideLoad
|
5
|
+
JS_COMMENT = '<!-- [PROSCENIUM_JAVASCRIPTS] -->'
|
6
|
+
CSS_COMMENT = '<!-- [PROSCENIUM_STYLESHEETS] -->'
|
7
|
+
LAZY_COMMENT = '<!-- [PROSCENIUM_LAZY_SCRIPTS] -->'
|
8
|
+
|
5
9
|
module Controller
|
6
10
|
def self.included(child)
|
7
11
|
child.class_eval do
|
@@ -23,7 +27,13 @@ module Proscenium
|
|
23
27
|
def capture_and_replace_proscenium_stylesheets
|
24
28
|
return if response_body.nil?
|
25
29
|
return if response_body.first.blank? || !Proscenium::Importer.css_imported?
|
26
|
-
|
30
|
+
|
31
|
+
included_comment = response_body.first.include?(CSS_COMMENT)
|
32
|
+
fragments = if (fragment_header = request.headers['X-Fragment'])
|
33
|
+
fragment_header.split
|
34
|
+
end
|
35
|
+
|
36
|
+
return if !fragments && !included_comment
|
27
37
|
|
28
38
|
imports = Proscenium::Importer.imported.dup
|
29
39
|
paths_to_build = []
|
@@ -31,8 +41,7 @@ module Proscenium
|
|
31
41
|
paths_to_build << x.delete_prefix('/')
|
32
42
|
end
|
33
43
|
|
34
|
-
result = Proscenium::Builder.build_to_path(paths_to_build.join(';')
|
35
|
-
base_url: helpers.request.base_url)
|
44
|
+
result = Proscenium::Builder.build_to_path(paths_to_build.join(';'))
|
36
45
|
|
37
46
|
out = []
|
38
47
|
result.split(';').each do |x|
|
@@ -44,12 +53,17 @@ module Proscenium
|
|
44
53
|
|
45
54
|
import = imports[inpath]
|
46
55
|
opts = import[:css].is_a?(Hash) ? import[:css] : {}
|
56
|
+
opts[:preload_links_header] = false if fragments
|
47
57
|
opts[:data] ||= {}
|
48
58
|
opts[:data][:original_href] = inpath
|
49
59
|
out << helpers.stylesheet_link_tag(outpath, extname: false, **opts)
|
50
60
|
end
|
51
61
|
|
52
|
-
|
62
|
+
if fragments
|
63
|
+
response_body.first.prepend out.join.html_safe
|
64
|
+
elsif included_comment
|
65
|
+
response_body.first.gsub! CSS_COMMENT, out.join.html_safe
|
66
|
+
end
|
53
67
|
end
|
54
68
|
|
55
69
|
def capture_and_replace_proscenium_javascripts
|
@@ -62,10 +76,15 @@ module Proscenium
|
|
62
76
|
paths_to_build << x.delete_prefix('/')
|
63
77
|
end
|
64
78
|
|
65
|
-
result = Proscenium::Builder.build_to_path(paths_to_build.join(';')
|
66
|
-
base_url: helpers.request.base_url)
|
79
|
+
result = Proscenium::Builder.build_to_path(paths_to_build.join(';'))
|
67
80
|
|
68
|
-
|
81
|
+
included_js_comment = response_body.first.include?(JS_COMMENT)
|
82
|
+
included_lazy_comment = response_body.first.include?(LAZY_COMMENT)
|
83
|
+
fragments = if (fragment_header = request.headers['X-Fragment'])
|
84
|
+
fragment_header.split
|
85
|
+
end
|
86
|
+
|
87
|
+
if fragments || included_js_comment
|
69
88
|
out = []
|
70
89
|
scripts = {}
|
71
90
|
result.split(';').each do |x|
|
@@ -79,14 +98,19 @@ module Proscenium
|
|
79
98
|
scripts[inpath] = import.merge(outpath:)
|
80
99
|
else
|
81
100
|
opts = import[:js].is_a?(Hash) ? import[:js] : {}
|
101
|
+
opts[:preload_links_header] = false if fragments
|
82
102
|
out << helpers.javascript_include_tag(outpath, extname: false, **opts)
|
83
103
|
end
|
84
104
|
end
|
85
105
|
|
86
|
-
|
106
|
+
if fragments
|
107
|
+
response_body.first.prepend out.join.html_safe
|
108
|
+
elsif included_js_comment
|
109
|
+
response_body.first.gsub! JS_COMMENT, out.join.html_safe
|
110
|
+
end
|
87
111
|
end
|
88
112
|
|
89
|
-
return
|
113
|
+
return if !fragments && !included_lazy_comment
|
90
114
|
|
91
115
|
lazy_script = ''
|
92
116
|
if scripts.present?
|
@@ -96,7 +120,11 @@ module Proscenium
|
|
96
120
|
end
|
97
121
|
end
|
98
122
|
|
99
|
-
|
123
|
+
if fragments
|
124
|
+
response_body.first.prepend lazy_script
|
125
|
+
elsif included_lazy_comment
|
126
|
+
response_body.first.gsub! LAZY_COMMENT, lazy_script
|
127
|
+
end
|
100
128
|
end
|
101
129
|
end
|
102
130
|
|
@@ -1,28 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'literal'
|
4
|
+
|
3
5
|
module Proscenium::UI
|
4
6
|
class Breadcrumbs::Component < Component
|
7
|
+
extend Literal::Properties
|
5
8
|
include Phlex::Rails::Helpers::URLFor
|
6
9
|
|
7
10
|
# The path (route) to use as the HREF for the home segment. Defaults to `:root`.
|
8
|
-
|
11
|
+
prop :home_path, _Union(String, Symbol), default: -> { :root }
|
9
12
|
|
10
13
|
# Assign false to hide the home segment.
|
11
|
-
|
12
|
-
|
13
|
-
# One or more class name(s) for the base div element which will be appended to the default.
|
14
|
-
option :class, Types::Coercible::String | Types::Array.of(Types::Coercible::String),
|
15
|
-
as: :class_name, default: -> { [] }
|
16
|
-
|
17
|
-
# One or more class name(s) for the base div element which will replace the default. If both
|
18
|
-
# `class` and `class!` are provided, all values will be merged. Defaults to `:@base`.
|
19
|
-
option :class!, Types::Coercible::String | Types::Array.of(Types::Coercible::String),
|
20
|
-
as: :class_name_override, default: -> { :@base }
|
14
|
+
prop :with_home, _Boolean, default: -> { true }
|
21
15
|
|
22
16
|
def view_template
|
23
|
-
div class:
|
17
|
+
div class: :@base do
|
24
18
|
ol do
|
25
|
-
if with_home
|
19
|
+
if @with_home
|
26
20
|
li do
|
27
21
|
home_template
|
28
22
|
end
|
@@ -48,7 +42,7 @@ module Proscenium::UI
|
|
48
42
|
# super { 'hello' }
|
49
43
|
# end
|
50
44
|
def home_template(&block)
|
51
|
-
a(href: url_for(home_path)) do
|
45
|
+
a(href: url_for(@home_path)) do
|
52
46
|
if block
|
53
47
|
yield
|
54
48
|
else
|
data/lib/proscenium/ui/test.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
console.log("
|
1
|
+
console.log("@proscenium/ui/test.js");
|
@@ -2,7 +2,7 @@ export default async () => {
|
|
2
2
|
window.Proscenium = window.Proscenium || {};
|
3
3
|
|
4
4
|
if (!window.Proscenium.UJS) {
|
5
|
-
const classPath = "
|
5
|
+
const classPath = "/proscenium/ui/ujs/class.js";
|
6
6
|
const module = await import(classPath);
|
7
7
|
window.Proscenium.UJS = new module.default();
|
8
8
|
}
|
data/lib/proscenium/ui.rb
CHANGED
data/lib/proscenium/version.rb
CHANGED
data/lib/proscenium.rb
CHANGED
@@ -8,6 +8,13 @@ module Proscenium
|
|
8
8
|
FILE_EXTENSIONS = ['js', 'mjs', 'ts', 'jsx', 'tsx', 'css', 'js.map', 'mjs.map', 'jsx.map',
|
9
9
|
'ts.map', 'tsx.map', 'css.map'].freeze
|
10
10
|
|
11
|
+
# Default paths for Rails assets. Used by the `compute_asset_path` helper to maintain Rails
|
12
|
+
# default conventions of where JS and CSS files are located.
|
13
|
+
DEFAULT_RAILS_ASSET_PATHS = {
|
14
|
+
stylesheet: 'app/assets/stylesheets/',
|
15
|
+
javascript: 'app/javascript/'
|
16
|
+
}.freeze
|
17
|
+
|
11
18
|
ALLOWED_DIRECTORIES = 'app,lib,config,vendor,node_modules'
|
12
19
|
|
13
20
|
# Environment variables that should always be passed to the builder.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: proscenium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.19.0.beta2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Moss
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -30,34 +30,6 @@ dependencies:
|
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '8.0'
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: dry-initializer
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '3.1'
|
40
|
-
type: :runtime
|
41
|
-
prerelease: false
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '3.1'
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: dry-types
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '1.7'
|
54
|
-
type: :runtime
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - "~>"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '1.7'
|
61
33
|
- !ruby/object:Gem::Dependency
|
62
34
|
name: ffi
|
63
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,33 +45,33 @@ dependencies:
|
|
73
45
|
- !ruby/object:Gem::Version
|
74
46
|
version: 1.17.0
|
75
47
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
48
|
+
name: literal
|
77
49
|
requirement: !ruby/object:Gem::Requirement
|
78
50
|
requirements:
|
79
51
|
- - "~>"
|
80
52
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
53
|
+
version: '1.0'
|
82
54
|
type: :runtime
|
83
55
|
prerelease: false
|
84
56
|
version_requirements: !ruby/object:Gem::Requirement
|
85
57
|
requirements:
|
86
58
|
- - "~>"
|
87
59
|
- !ruby/object:Gem::Version
|
88
|
-
version: '
|
60
|
+
version: '1.0'
|
89
61
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
62
|
+
name: oj
|
91
63
|
requirement: !ruby/object:Gem::Requirement
|
92
64
|
requirements:
|
93
65
|
- - "~>"
|
94
66
|
- !ruby/object:Gem::Version
|
95
|
-
version:
|
67
|
+
version: '3.13'
|
96
68
|
type: :runtime
|
97
69
|
prerelease: false
|
98
70
|
version_requirements: !ruby/object:Gem::Requirement
|
99
71
|
requirements:
|
100
72
|
- - "~>"
|
101
73
|
- !ruby/object:Gem::Version
|
102
|
-
version:
|
74
|
+
version: '3.13'
|
103
75
|
- !ruby/object:Gem::Dependency
|
104
76
|
name: railties
|
105
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,22 +128,12 @@ files:
|
|
156
128
|
- lib/proscenium/ext/proscenium.h
|
157
129
|
- lib/proscenium/helper.rb
|
158
130
|
- lib/proscenium/importer.rb
|
159
|
-
- lib/proscenium/libs/custom_element.js
|
160
|
-
- lib/proscenium/libs/react-manager/index.jsx
|
161
|
-
- lib/proscenium/libs/react-manager/react.js
|
162
|
-
- lib/proscenium/libs/stimulus-loading.js
|
163
|
-
- lib/proscenium/libs/test.js
|
164
|
-
- lib/proscenium/libs/ujs/class.js
|
165
|
-
- lib/proscenium/libs/ujs/data_confirm.js
|
166
|
-
- lib/proscenium/libs/ujs/data_disable_with.js
|
167
|
-
- lib/proscenium/libs/ujs/index.js
|
168
131
|
- lib/proscenium/log_subscriber.rb
|
169
132
|
- lib/proscenium/middleware.rb
|
170
133
|
- lib/proscenium/middleware/base.rb
|
171
134
|
- lib/proscenium/middleware/engines.rb
|
172
135
|
- lib/proscenium/middleware/esbuild.rb
|
173
136
|
- lib/proscenium/middleware/runtime.rb
|
174
|
-
- lib/proscenium/middleware/url.rb
|
175
137
|
- lib/proscenium/monkey.rb
|
176
138
|
- lib/proscenium/phlex.rb
|
177
139
|
- lib/proscenium/phlex/asset_inclusions.rb
|
@@ -191,7 +153,15 @@ files:
|
|
191
153
|
- lib/proscenium/ui/breadcrumbs/control.rb
|
192
154
|
- lib/proscenium/ui/breadcrumbs/mixins.css
|
193
155
|
- lib/proscenium/ui/component.rb
|
156
|
+
- lib/proscenium/ui/custom_element.js
|
157
|
+
- lib/proscenium/ui/react-manager/index.jsx
|
158
|
+
- lib/proscenium/ui/react-manager/react.js
|
159
|
+
- lib/proscenium/ui/stimulus-loading.js
|
194
160
|
- lib/proscenium/ui/test.js
|
161
|
+
- lib/proscenium/ui/ujs/class.js
|
162
|
+
- lib/proscenium/ui/ujs/data_confirm.js
|
163
|
+
- lib/proscenium/ui/ujs/data_disable_with.js
|
164
|
+
- lib/proscenium/ui/ujs/index.js
|
195
165
|
- lib/proscenium/utils.rb
|
196
166
|
- lib/proscenium/version.rb
|
197
167
|
- lib/proscenium/view_component.rb
|
data/lib/proscenium/libs/test.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
console.log("/@proscenium/test.js");
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Proscenium
|
4
|
-
class Middleware
|
5
|
-
# Handles requests for URL encoded URL's.
|
6
|
-
class Url < Esbuild
|
7
|
-
private
|
8
|
-
|
9
|
-
# @override [Esbuild] It's a URL, so always assume it is renderable (we won't actually know
|
10
|
-
# until it's downloaded).
|
11
|
-
def renderable?
|
12
|
-
true
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|