proscenium 0.8.2-x86_64-linux → 0.9.0-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0befa74ca37e255e40d47294992f4dde37fd92636b7de4d6bcbd3e7078d26585
4
- data.tar.gz: 3ee198704c19fb58cd64ef2b3dfe9ccd76d0b4359507c5d66dfbd9973e0f16f4
3
+ metadata.gz: e89c958a1a78e610ea61941c833eead456c32f9030c1f880afe5270633158fdb
4
+ data.tar.gz: 6f80d724798b69aa1e9cf8bb92cecd60ec84b99e314f40c36ba44bb7a0b74c8d
5
5
  SHA512:
6
- metadata.gz: b4e97ebe2e7bcd9a85112f3ab3d043472e26a2f8378605c65342cd2c411ec47225955f4b87c8732c749e3a82e400feeb9160cb4ae7cdf41fe8f0d2abc2d2bf63
7
- data.tar.gz: 0bacb942fb31e630a47a2a7e5ef6991d05c31a624b53ce4d1aa9ef7027cb94c04241897cfd96e78f0e32ddd17d391a929c482133b216dc437c187837aeae0c0b
6
+ metadata.gz: 4241bcc1c617d80496be4f10e373fd15e6cf75227c5fbb0a9f974568276a0c5b490c8cd99efab7818208b595209eb6e068f03942e05073d4e314a7a267d9f70b
7
+ data.tar.gz: bf1e4c6cd00298f4210ac1a6228dd15a0f022c2b33b8b2a01b14753ef7cc0f35c5989e0d7e9e755728492e71699203d958fdef6400b44a2a7750fbe0d306aa7d
data/README.md CHANGED
@@ -1,18 +1,19 @@
1
- # Proscenium - Modern Client-Side Tooling for Rails
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
- - No additional process or server - Just run Rails!
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 JS(X), TS(X) and CSS from NPM, URL, and locally.
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
- ## Side Loading
162
+ ## Importing SVG from JS(X) and TS(X)
133
163
 
134
- Proscenium has built in support for automatically side loading JS and CSS with your views and
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
- Just create a JS and/or CSS file with the same name as any view or layout, and make sure your
138
- layouts include `<%= side_load_stylesheets %>` and `<%= side_load_javascripts %>`. Something like
139
- this:
166
+ ## Environment Variables
140
167
 
141
- ```html
142
- <!DOCTYPE html>
143
- <html>
144
- <head>
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
- On each page request, Proscenium will check if your layout and view has a JS/CSS file of the same
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
- Side loading is enabled by default, but you can disable it by setting `config.proscenium.side_load`
159
- to `false`.
176
+ ## Importing i18n
160
177
 
161
- ## CSS Modules
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
- ## CSS Mixins
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
- ## Importing SVG from JS(X)
316
+ ### CSS Caveats
242
317
 
243
- Importing SVG from JS(X) will bundle the SVG source code. Additionally, if importing from JSX, the SVG source code will be rendered as a JSX component.
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
- ## Environment Variables
320
+ ## Typescript
246
321
 
247
- Import any environment variables into your JS(X) code.
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
- ```js
250
- import RAILS_ENV from '@proscenium/env/RAILS_ENV'
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
- You can only access environment variables that are explicitly named. It will export `undefined` if the env variable does not exist.
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
- ## Importing i18n
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
- Basic support is provided for importing your Rails locale files from `config/locales/*.yml`, exporting them as JSON.
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
- ```js
260
- import translations from '@proscenium/i18n'
261
- // translations.en.*
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
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
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
- @content_type ||
75
- ::Rack::Mime.mime_type(::File.extname(path_to_build), nil) ||
76
- 'application/javascript'
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(request)
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
- path = Pathname.new(request.path)
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 glob_types
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}}#{glob_types[:application]}"
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
@@ -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', 'css.map'].freeze
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
@@ -11,13 +11,19 @@ module Proscenium
11
11
  autoload :EnsureLoaded
12
12
 
13
13
  EXTENSIONS = %i[js css].freeze
14
- EXTENSION_MAP = { '.css' => :css, '.js' => :js }.freeze
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 a
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Proscenium
4
- VERSION = '0.8.2'
4
+ VERSION = '0.9.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proscenium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.0
5
5
  platform: x86_64-linux
6
6
  authors:
7
7
  - Joel Moss