proscenium 0.8.2-x86_64-darwin → 0.9.0-x86_64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +163 -44
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/middleware/base.rb +7 -4
- data/lib/proscenium/middleware.rb +11 -18
- data/lib/proscenium/railtie.rb +2 -6
- data/lib/proscenium/side_load/helper.rb +2 -2
- data/lib/proscenium/side_load.rb +9 -3
- data/lib/proscenium/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7275553369eb466cb49d27691c77ba994f2c207db06d3ea01b7462f8a2cdef42
|
4
|
+
data.tar.gz: c1c90ebc442cae8ae0f514fd3470fbe338e3527cd6049540c5b218bc3c533c6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1c1a04bb140750dffdff38a87e53f30f24ba0f94c4ca8bad97b5cd762a735f26299fdb14ceb3bf82f372747169a09196834cce786d21a7338ba24a07335063c
|
7
|
+
data.tar.gz: ca9476628bc14855c44a51eda50d04f981deb8c61578989be9a7c785380f1a652ce4bd7d607f56abe9e62279554320ea2d95ac40532b998ff4773d617fe03567
|
data/README.md
CHANGED
@@ -1,18 +1,19 @@
|
|
1
|
-
# Proscenium - Modern
|
1
|
+
# Proscenium - Modern client-side development for Rails
|
2
2
|
|
3
3
|
Proscenium treats your client-side code as first class citizens of your Rails app, and assumes a
|
4
4
|
"fast by default" internet. It bundles your JS, JSX and CSS in real time, on demand, and with zero
|
5
5
|
configuration.
|
6
6
|
|
7
|
-
- Zero configuration.
|
8
7
|
- Fast real-time bundling, tree-shaking and minification.
|
8
|
+
- Real time bundling of Javascript (.js,.jsx), Typescript (.ts,.tsx) and CSS (.css).
|
9
9
|
- NO JavaScript runtime - just the browser!
|
10
|
+
- NO build step or pre-compilation.
|
11
|
+
- NO additional process or server - Just run Rails!
|
10
12
|
- Deep integration with Rails.
|
11
|
-
-
|
13
|
+
- Zero configuration.
|
12
14
|
- Serve assets from anywhere within your Rails root (/app, /config, /lib, etc.).
|
13
|
-
- Automatically side load JS/CSS for your layouts and views.
|
14
|
-
- Import
|
15
|
-
- Support for JSX.
|
15
|
+
- Automatically side load JS/TS/CSS for your layouts and views.
|
16
|
+
- Import from NPM, URLs, and locally.
|
16
17
|
- Server-side import map support.
|
17
18
|
- CSS Modules.
|
18
19
|
- CSS mixins.
|
@@ -45,6 +46,35 @@ Using the examples above...
|
|
45
46
|
- `app/components/menu_component.jsx` => `https://yourapp.com/app/components/menu_component.jsx`
|
46
47
|
- `config/properties.css` => `https://yourapp.com/config/properties.css`
|
47
48
|
|
49
|
+
## Side Loading
|
50
|
+
|
51
|
+
Proscenium has built in support for automatically side loading JS, TS and CSS with your views and
|
52
|
+
layouts.
|
53
|
+
|
54
|
+
Just create a JS and/or CSS file with the same name as any view or layout, and make sure your
|
55
|
+
layouts include `<%= side_load_stylesheets %>` and `<%= side_load_javascripts %>`. Something like
|
56
|
+
this:
|
57
|
+
|
58
|
+
```html
|
59
|
+
<!DOCTYPE html>
|
60
|
+
<html>
|
61
|
+
<head>
|
62
|
+
<title>Hello World</title>
|
63
|
+
<%= side_load_stylesheets %>
|
64
|
+
</head>
|
65
|
+
<body>
|
66
|
+
<%= yield %>
|
67
|
+
<%= side_load_javascripts defer: true, type: 'module' %>
|
68
|
+
</body>
|
69
|
+
</html>
|
70
|
+
```
|
71
|
+
|
72
|
+
On each page request, Proscenium will check if your layout and view has a JS/TS/CSS file of the same
|
73
|
+
name, and include them into your layout HTML. Partials are not side loaded.
|
74
|
+
|
75
|
+
Side loading is enabled by default, but you can disable it by setting `config.proscenium.side_load`
|
76
|
+
to `false`.
|
77
|
+
|
48
78
|
## Importing
|
49
79
|
|
50
80
|
Proscenium supports importing JS, JSX, TS and CSS from NPM, by URL, your local app, and even from Ruby Gems.
|
@@ -129,36 +159,81 @@ env => ({
|
|
129
159
|
})
|
130
160
|
```
|
131
161
|
|
132
|
-
##
|
162
|
+
## Importing SVG from JS(X) and TS(X)
|
133
163
|
|
134
|
-
|
135
|
-
layouts.
|
164
|
+
Importing SVG from JS(X) will bundle the SVG source code. Additionally, if importing from JSX or TSX, the SVG source code will be rendered as a JSX/TSX component.
|
136
165
|
|
137
|
-
|
138
|
-
layouts include `<%= side_load_stylesheets %>` and `<%= side_load_javascripts %>`. Something like
|
139
|
-
this:
|
166
|
+
## Environment Variables
|
140
167
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
<title>Hello World</title>
|
146
|
-
<%= side_load_stylesheets %>
|
147
|
-
</head>
|
148
|
-
<body>
|
149
|
-
<%= yield %>
|
150
|
-
<%= side_load_javascripts defer: true, type: 'module' %>
|
151
|
-
</body>
|
152
|
-
</html>
|
168
|
+
Import any environment variables into your JS(X) code.
|
169
|
+
|
170
|
+
```js
|
171
|
+
import RAILS_ENV from '@proscenium/env/RAILS_ENV'
|
153
172
|
```
|
154
173
|
|
155
|
-
|
156
|
-
name, and include them into your layout HTML. Partials are not side loaded.
|
174
|
+
You can only access environment variables that are explicitly named. It will export `undefined` if the env variable does not exist.
|
157
175
|
|
158
|
-
|
159
|
-
to `false`.
|
176
|
+
## Importing i18n
|
160
177
|
|
161
|
-
|
178
|
+
Basic support is provided for importing your Rails locale files from `config/locales/*.yml`, exporting them as JSON.
|
179
|
+
|
180
|
+
```js
|
181
|
+
import translations from '@proscenium/i18n'
|
182
|
+
// translations.en.*
|
183
|
+
```
|
184
|
+
|
185
|
+
## Javascript
|
186
|
+
|
187
|
+
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.
|
188
|
+
|
189
|
+
### Tree Shaking
|
190
|
+
|
191
|
+
Tree shaking is the term the JavaScript community uses for dead code elimination, a common compiler optimization that automatically removes unreachable code. Tree shaking is enabled by default in Proascenium.
|
192
|
+
|
193
|
+
```javascript
|
194
|
+
function one() {
|
195
|
+
console.log('one')
|
196
|
+
}
|
197
|
+
function two() {
|
198
|
+
console.log('two')
|
199
|
+
}
|
200
|
+
one()
|
201
|
+
```
|
202
|
+
|
203
|
+
The above code will be transformed to the following code, discarding `two()`, as it is never called.
|
204
|
+
|
205
|
+
```javascript
|
206
|
+
function one() {
|
207
|
+
console.log("one");
|
208
|
+
}
|
209
|
+
one();
|
210
|
+
```
|
211
|
+
|
212
|
+
### JavaScript Caveats
|
213
|
+
|
214
|
+
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).
|
215
|
+
|
216
|
+
## CSS
|
217
|
+
|
218
|
+
CSS is a first-class content type in Proscenium, which means it can bundle CSS files directly without needing to import your CSS from JavaScript code. You can `@import` other CSS files and reference image and font files with `url()` and Proscenium will bundle everything together.
|
219
|
+
|
220
|
+
Note that by default, Proscenium's output will take advantage of all modern CSS features. For example, `color: rgba(255, 0, 0, 0.4)` will become `color: #f006` after minifying in production, which makes use of syntax from [CSS Color Module Level 4](https://drafts.csswg.org/css-color-4/#changes-from-3).
|
221
|
+
|
222
|
+
The new CSS nesting syntax is supported, and transformed into non-nested CSS for older browsers.
|
223
|
+
|
224
|
+
### Importing from JavaScript
|
225
|
+
|
226
|
+
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.
|
227
|
+
|
228
|
+
```jsx
|
229
|
+
import './button.css'
|
230
|
+
|
231
|
+
export let Button = ({ text }) => {
|
232
|
+
return <div className="button">{text}</div>
|
233
|
+
}
|
234
|
+
```
|
235
|
+
|
236
|
+
### CSS Modules
|
162
237
|
|
163
238
|
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 work everywhere.
|
164
239
|
|
@@ -189,7 +264,7 @@ It is important to note that the exported object of CSS module names is actually
|
|
189
264
|
|
190
265
|
Also, importing a CSS module from another CSS module will result in the same digest string for all classes.
|
191
266
|
|
192
|
-
|
267
|
+
### CSS Mixins
|
193
268
|
|
194
269
|
Proscenium provides functionality for including or "mixing in" onr or more CSS classes into another. This is similar to the `composes` property of CSS Modules, but works everywhere, and is not limited to CSS Modules.
|
195
270
|
|
@@ -238,27 +313,49 @@ p {
|
|
238
313
|
|
239
314
|
CSS modules and Mixins works perfectly together. You can include a mixin in a CSS module.
|
240
315
|
|
241
|
-
|
316
|
+
### CSS Caveats
|
242
317
|
|
243
|
-
|
318
|
+
There are a few important caveats as far as CSS is concerned. These are [detailed on the esbuild site](https://esbuild.github.io/content-types/#css-caveats).
|
244
319
|
|
245
|
-
##
|
320
|
+
## Typescript
|
246
321
|
|
247
|
-
|
322
|
+
Typescript and TSX is supported out of the box, and has built-in support for parsing TypeScript syntax and discarding the type annotations. Just rename your files to `.ts` or `.tsx` and you're good to go.
|
248
323
|
|
249
|
-
|
250
|
-
|
324
|
+
Please note that Proscenium does not do any type checking so you will still need to run `tsc -noEmit` in parallel with Proscenium to check types.
|
325
|
+
|
326
|
+
### Typescript Caveats
|
327
|
+
|
328
|
+
There are a few important caveats as far as Typescript is concerned. These are [detailed on the esbuild site](https://esbuild.github.io/content-types/#typescript-caveats).
|
329
|
+
|
330
|
+
## JSX
|
331
|
+
|
332
|
+
Using JSX syntax usually requires you to manually import the JSX library you are using. For example, if you are using React, by default you will need to import React into each JSX file like this:
|
333
|
+
|
334
|
+
```javascript
|
335
|
+
import * as React from 'react'
|
336
|
+
render(<div/>)
|
251
337
|
```
|
252
338
|
|
253
|
-
|
339
|
+
This is because the JSX transform turns JSX syntax into a call to `React.createElement` but it does not itself import anything, so the React variable is not automatically present.
|
254
340
|
|
255
|
-
|
341
|
+
Proscenium generates these import statements for you. Keep in mind that this also completely changes how the JSX transform works, so it may break your code if you are using a JSX library that is not React.
|
256
342
|
|
257
|
-
|
343
|
+
In the [not too distant] future, you will be able to configure Proscenium to use a different JSX library, or to disable this auto-import completely.
|
258
344
|
|
259
|
-
|
260
|
-
|
261
|
-
|
345
|
+
## JSON
|
346
|
+
|
347
|
+
Importing .json files parses the JSON file into a JavaScript object, and exports the object as the default export. Using it looks something like this:
|
348
|
+
|
349
|
+
```javascript
|
350
|
+
import object from './example.json'
|
351
|
+
console.log(object)
|
352
|
+
```
|
353
|
+
|
354
|
+
In addition to the default export, there are also named exports for each top-level property in the JSON object. Importing a named export directly means Proscenium can automatically remove unused parts of the JSON file from the bundle, leaving only the named exports that you actually used. For example, this code will only include the version field when bundled:
|
355
|
+
|
356
|
+
```javascript
|
357
|
+
import { version } from './package.json'
|
358
|
+
console.log(version)
|
262
359
|
```
|
263
360
|
|
264
361
|
## Phlex Support
|
@@ -307,11 +404,33 @@ Proscenium brings back RJS! Any path ending in .rjs will be served from your Rai
|
|
307
404
|
|
308
405
|
*docs needed*
|
309
406
|
|
407
|
+
## Thanks 🙏
|
408
|
+
|
409
|
+
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.
|
410
|
+
|
411
|
+
Because Proscenium uses esbuild extensively, some of these docs are taken directly from the esbuild docs, with links back to the [esbuild site](https://esbuild.github.io/) where appropriate.
|
412
|
+
|
310
413
|
## Development
|
311
414
|
|
312
|
-
|
415
|
+
Before doing anything else, you will need compile a local version of the Go binary. This is because the Go binary is not checked into the repo. To compile the binary, run:
|
416
|
+
|
417
|
+
```bash
|
418
|
+
bundle exec rake compile:local
|
419
|
+
```
|
420
|
+
|
421
|
+
### Running tests
|
313
422
|
|
314
|
-
|
423
|
+
We have tests for both Ruby and Go. To run the Ruby tests:
|
424
|
+
|
425
|
+
```bash
|
426
|
+
bundle exec rake test
|
427
|
+
```
|
428
|
+
|
429
|
+
To run the Go tests:
|
430
|
+
|
431
|
+
```bash
|
432
|
+
go test ./test
|
433
|
+
```
|
315
434
|
|
316
435
|
### Running Go benchmarks
|
317
436
|
|
Binary file
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'open3'
|
4
3
|
require 'oj'
|
5
4
|
|
6
5
|
module Proscenium
|
@@ -71,9 +70,13 @@ module Proscenium
|
|
71
70
|
end
|
72
71
|
|
73
72
|
def content_type
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
case ::File.extname(path_to_build)
|
74
|
+
when '.js', '.mjs', '.ts', '.tsx', '.jsx' then 'application/javascript'
|
75
|
+
when '.css' then 'text/css'
|
76
|
+
when '.map' then 'application/json'
|
77
|
+
else
|
78
|
+
::Rack::Mime.mime_type(::File.extname(path_to_build), nil) || 'application/javascript'
|
79
|
+
end
|
77
80
|
end
|
78
81
|
|
79
82
|
def render_response(content)
|
@@ -30,30 +30,23 @@ module Proscenium
|
|
30
30
|
|
31
31
|
# file_handler.attempt(request.env) || type.attempt(request)
|
32
32
|
|
33
|
-
type.attempt
|
33
|
+
type.attempt request
|
34
34
|
end
|
35
35
|
|
36
|
-
# Returns the type of file being requested using Proscenium::MIDDLEWARE_GLOB_TYPES.
|
37
36
|
def find_type(request)
|
38
|
-
|
39
|
-
|
40
|
-
return Url if request.path.match?(glob_types[:url])
|
41
|
-
return Esbuild if path.fnmatch?(application_glob_type, File::FNM_EXTGLOB)
|
42
|
-
end
|
43
|
-
|
44
|
-
# TODO: handle precompiled assets
|
45
|
-
def file_handler
|
46
|
-
::ActionDispatch::FileHandler.new Rails.public_path.join('assets').to_s,
|
47
|
-
headers: { 'X-Proscenium-Middleware' => 'precompiled' }
|
37
|
+
return Url if request.path.match?(%r{^/https?%3A%2F%2F})
|
38
|
+
return Esbuild if Pathname.new(request.path).fnmatch?(path_glob, File::FNM_EXTGLOB)
|
48
39
|
end
|
49
40
|
|
50
|
-
def
|
51
|
-
@glob_types ||= Proscenium::MIDDLEWARE_GLOB_TYPES
|
52
|
-
end
|
53
|
-
|
54
|
-
def application_glob_type
|
41
|
+
def path_glob
|
55
42
|
paths = Rails.application.config.proscenium.include_paths.join(',')
|
56
|
-
"/{#{paths}}#{
|
43
|
+
"/{#{paths}}/**.{#{FILE_EXTENSIONS.join(',')}}"
|
57
44
|
end
|
45
|
+
|
46
|
+
# TODO: handle precompiled assets
|
47
|
+
# def file_handler
|
48
|
+
# ::ActionDispatch::FileHandler.new Rails.public_path.join('assets').to_s,
|
49
|
+
# headers: { 'X-Proscenium-Middleware' => 'precompiled' }
|
50
|
+
# end
|
58
51
|
end
|
59
52
|
end
|
data/lib/proscenium/railtie.rb
CHANGED
@@ -6,12 +6,8 @@ require 'proscenium/log_subscriber'
|
|
6
6
|
ENV['RAILS_ENV'] = Rails.env
|
7
7
|
|
8
8
|
module Proscenium
|
9
|
-
FILE_EXTENSIONS = ['js', 'mjs', 'jsx', 'css', 'js.map', 'mjs.map', 'jsx.map',
|
10
|
-
|
11
|
-
MIDDLEWARE_GLOB_TYPES = {
|
12
|
-
application: "/**.{#{FILE_EXTENSIONS.join(',')}}",
|
13
|
-
url: %r{^/https?%3A%2F%2F}
|
14
|
-
}.freeze
|
9
|
+
FILE_EXTENSIONS = ['js', 'mjs', 'ts', 'jsx', 'tsx', 'css', 'js.map', 'mjs.map', 'jsx.map',
|
10
|
+
'ts.map', 'tsx.map', 'css.map'].freeze
|
15
11
|
|
16
12
|
APPLICATION_INCLUDE_PATHS = ['config', 'app/views', 'lib', 'node_modules'].freeze
|
17
13
|
|
@@ -7,7 +7,7 @@ module Proscenium
|
|
7
7
|
|
8
8
|
out = []
|
9
9
|
Proscenium::Current.loaded[:css].delete_if do |path|
|
10
|
-
out << stylesheet_link_tag(path)
|
10
|
+
out << stylesheet_link_tag(path, extname: false)
|
11
11
|
end
|
12
12
|
out.join("\n").html_safe
|
13
13
|
end
|
@@ -17,7 +17,7 @@ module Proscenium
|
|
17
17
|
|
18
18
|
out = []
|
19
19
|
Proscenium::Current.loaded[:js].delete_if do |path|
|
20
|
-
out << javascript_include_tag(path, options)
|
20
|
+
out << javascript_include_tag(path, extname: false, **options)
|
21
21
|
end
|
22
22
|
out.join("\n").html_safe
|
23
23
|
end
|
data/lib/proscenium/side_load.rb
CHANGED
@@ -11,13 +11,19 @@ module Proscenium
|
|
11
11
|
autoload :EnsureLoaded
|
12
12
|
|
13
13
|
EXTENSIONS = %i[js css].freeze
|
14
|
-
EXTENSION_MAP = {
|
14
|
+
EXTENSION_MAP = {
|
15
|
+
'.css' => :css,
|
16
|
+
# '.tsx' => :js,
|
17
|
+
'.ts' => :js,
|
18
|
+
# '.jsx' => :js,
|
19
|
+
'.js' => :js
|
20
|
+
}.freeze
|
15
21
|
|
16
22
|
attr_reader :path
|
17
23
|
|
18
24
|
class << self
|
19
|
-
# Side load the given asset `path`, by appending it to `Proscenium::Current.loaded`, which is
|
20
|
-
# Set of 'js' and 'css' asset paths. This is idempotent, so side loading will never include
|
25
|
+
# Side load the given asset `path`, by appending it to `Proscenium::Current.loaded`, which is
|
26
|
+
# a Set of 'js' and 'css' asset paths. This is idempotent, so side loading will never include
|
21
27
|
# duplicates.
|
22
28
|
#
|
23
29
|
# @return [Array] appended URL paths
|
data/lib/proscenium/version.rb
CHANGED