proscenium 0.1.2-arm64-darwin → 0.2.1-arm64-darwin
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +29 -4
- data/bin/esbuild +0 -0
- data/lib/proscenium/compilers/esbuild/resolve_plugin.js +26 -25
- data/lib/proscenium/compilers/esbuild.bench.js +3 -2
- data/lib/proscenium/compilers/esbuild.js +14 -7
- data/lib/proscenium/helper.rb +9 -1
- data/lib/proscenium/middleware/base.rb +4 -0
- data/lib/proscenium/middleware/esbuild.rb +11 -6
- data/lib/proscenium/middleware/outside_root.rb +26 -0
- data/lib/proscenium/middleware.rb +7 -0
- data/lib/proscenium/railtie.rb +4 -1
- data/lib/proscenium/runtime/auto_reload.js +21 -3
- data/lib/proscenium/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d944d36dfe023a4b4362445785ba3474b821abcad06b4937f011ebe4f1ebd84
|
4
|
+
data.tar.gz: 63782a1bb192110a39f96aa9ad2ca75897fa10f272076b78263cf850a7d44088
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ac677e20d44ded3f3e49e96265cc31d7263bd35453b86d789b714b58223763cf0e4bcd0ded9ec097d5890793eea5692ad8f68b7038a5cef99634a8782617cc6
|
7
|
+
data.tar.gz: f145d102c93d03fee83966982d497f702bc12e066e2cc6d16ce7bab2ca3e330115f2c6f42bac2637666e3e3519e5f6122aaa4750fe6639d242a6a31ab1a7aaa7
|
data/README.md
CHANGED
@@ -110,6 +110,10 @@ resulting in conflicts. For example, esm.sh also supports a `?bundle` param, bun
|
|
110
110
|
dependencies into a single file. Instead, you should install the module locally using your favourite
|
111
111
|
package manager.
|
112
112
|
|
113
|
+
Note that `?bundle` will only bundle that exact path. It will not bundle any descendant imports. You
|
114
|
+
can bundle all imports within a file by using the `?bundle-all` query string. Use this with caution,
|
115
|
+
as you could end up swallowing everything, resulting in a very large file.
|
116
|
+
|
113
117
|
## Import Map
|
114
118
|
|
115
119
|
Import map for both JS and CSS is supported out of the box, and works with no regard to the browser
|
@@ -246,6 +250,31 @@ p {
|
|
246
250
|
}
|
247
251
|
```
|
248
252
|
|
253
|
+
## Cache Busting
|
254
|
+
|
255
|
+
By default, all assets are not cached by the browser. But if in production, you populate the
|
256
|
+
`REVISION` env variable, all CSS and JS URL's will be appended with its value as a query string, and
|
257
|
+
the `Cache-Control` response header will be set to `public` and a max-age of 30 days.
|
258
|
+
|
259
|
+
For example, if you set `REVISION=v1`, URL's will be appended with `?v1`: `/my/imported/file.js?v1`.
|
260
|
+
|
261
|
+
It is assumed that the `REVISION` env var will be unique between deploys. If it isn't, then assets
|
262
|
+
will continue to be cached as the same version between deploys. I recommend you assign a version
|
263
|
+
number or to use the Git commit hash of the deploy. Just make sure it is unique for each deploy.
|
264
|
+
|
265
|
+
You can set the `cache_query_string` config option directly to define any query string you wish:
|
266
|
+
|
267
|
+
```ruby
|
268
|
+
Rails.application.config.proscenium.cache_query_string = 'my-cache-busting-version-string'
|
269
|
+
```
|
270
|
+
|
271
|
+
The cache is set with a `max-age` of 30 days. You can customise this with the `cache_max_age` config
|
272
|
+
option:
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
Rails.application.config.proscenium.cache_max_age = 12.months.to_i
|
276
|
+
```
|
277
|
+
|
249
278
|
## How It Works
|
250
279
|
|
251
280
|
Proscenium provides a Rails middleware that proxies requests for your frontend code. By default, it will simply search for a file of the same name in your Rails root. For example, a request for '/app/views/layouts/application.js' or '/lib/hooks.js' will return that exact file relative to your Rails root.
|
@@ -258,10 +287,6 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
258
287
|
|
259
288
|
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).
|
260
289
|
|
261
|
-
### Compile the compilers
|
262
|
-
|
263
|
-
`deno compile --no-config -o bin/compilers/esbuild --import-map import_map.json -A lib/proscenium/compilers/esbuild.js`
|
264
|
-
|
265
290
|
## Contributing
|
266
291
|
|
267
292
|
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).
|
data/bin/esbuild
CHANGED
Binary file
|
@@ -11,6 +11,9 @@ export default setup('resolve', (build, options) => {
|
|
11
11
|
const runtimeCwdAlias = `${cwd}/proscenium-runtime`
|
12
12
|
let bundled = false
|
13
13
|
|
14
|
+
const env = Deno.env.get('RAILS_ENV')
|
15
|
+
const isProd = env === 'production'
|
16
|
+
|
14
17
|
return [
|
15
18
|
{
|
16
19
|
type: 'onResolve',
|
@@ -21,6 +24,8 @@ export default setup('resolve', (build, options) => {
|
|
21
24
|
args.path = path
|
22
25
|
args.suffix = `?${query}`
|
23
26
|
args.queryParams = new URLSearchParams(query)
|
27
|
+
} else if (options.cacheQueryString && options.cacheQueryString !== '') {
|
28
|
+
args.suffix = `?${options.cacheQueryString}`
|
24
29
|
}
|
25
30
|
|
26
31
|
// Mark remote modules as external.
|
@@ -28,24 +33,7 @@ export default setup('resolve', (build, options) => {
|
|
28
33
|
return { external: true }
|
29
34
|
}
|
30
35
|
|
31
|
-
//
|
32
|
-
// if (args.path.startsWith('@proscenium/')) {
|
33
|
-
// const result = { suffix: args.suffix }
|
34
|
-
|
35
|
-
// if (args.queryParams?.has('bundle-all')) {
|
36
|
-
// bundled = true
|
37
|
-
// }
|
38
|
-
|
39
|
-
// if (bundled || args.queryParams?.has('bundle')) {
|
40
|
-
// result.path = join(runtimeDir, `${args.path.replace(/^@proscenium/, '')}/index.js`)
|
41
|
-
// } else {
|
42
|
-
// result.path = `${args.path.replace(/^@proscenium/, '/proscenium-runtime')}/index.js`
|
43
|
-
// result.external = true
|
44
|
-
// }
|
45
|
-
|
46
|
-
// return result
|
47
|
-
// }
|
48
|
-
|
36
|
+
// Rewrite the path to the actual runtime directory.
|
49
37
|
if (args.path.startsWith(runtimeCwdAlias)) {
|
50
38
|
return { path: join(runtimeDir, args.path.slice(runtimeCwdAlias.length)) }
|
51
39
|
}
|
@@ -88,11 +76,12 @@ export default setup('resolve', (build, options) => {
|
|
88
76
|
// Resolve the path using esbuild's internal resolution. This allows us to import node packages
|
89
77
|
// and extension-less paths without custom code, as esbuild with resolve them for us.
|
90
78
|
const resolveResult = await build.resolve(result.path, {
|
91
|
-
// If path is a bare module (node_modules), and resolveDir is the Proscenium runtime dir,
|
92
|
-
// use `cwd` as the `resolveDir`, otherwise pass it through
|
93
|
-
// node_modules are resolved correctly.
|
79
|
+
// If path is a bare module (node_modules), and resolveDir is the Proscenium runtime dir, or
|
80
|
+
// is the current working dir, then use `cwd` as the `resolveDir`, otherwise pass it through
|
81
|
+
// as is. This ensures that nested node_modules are resolved correctly.
|
94
82
|
resolveDir:
|
95
|
-
isBareModule(result.path) &&
|
83
|
+
isBareModule(result.path) &&
|
84
|
+
(!params.resolveDir.startsWith(cwd) || params.resolveDir.startsWith(runtimeDir))
|
96
85
|
? cwd
|
97
86
|
: params.resolveDir,
|
98
87
|
pluginData: {
|
@@ -118,9 +107,17 @@ export default setup('resolve', (build, options) => {
|
|
118
107
|
|
119
108
|
if (resolveResult.path.startsWith(runtimeDir)) {
|
120
109
|
result.path = '/proscenium-runtime' + resolveResult.path.slice(runtimeDir.length)
|
121
|
-
} else if (!resolveResult.path.startsWith(cwd)) {
|
122
|
-
//
|
123
|
-
|
110
|
+
} else if (!resolveResult.path.startsWith(cwd) && !isProd) {
|
111
|
+
// Resolved path is not in the current working directory. It could be linked to a file outside
|
112
|
+
// the CWD, or it's just invalid. If not in production, return as an outsideRoot namespaced,
|
113
|
+
// and externally suffixed path. This lets the Rails Proscenium::Middleware::OutsideRoot
|
114
|
+
// handle the import.
|
115
|
+
return {
|
116
|
+
...resolveResult,
|
117
|
+
namespace: 'outsideRoot',
|
118
|
+
path: `${resolveResult.path}?outsideRoot`,
|
119
|
+
external: true
|
120
|
+
}
|
124
121
|
} else {
|
125
122
|
result.path = resolveResult.path.slice(cwd.length)
|
126
123
|
}
|
@@ -138,6 +135,10 @@ export default setup('resolve', (build, options) => {
|
|
138
135
|
result.external = true
|
139
136
|
}
|
140
137
|
|
138
|
+
if (result.suffix && result.suffix !== '') {
|
139
|
+
result.path = `${result.path}${result.suffix}`
|
140
|
+
}
|
141
|
+
|
141
142
|
return result
|
142
143
|
}
|
143
144
|
})
|
@@ -3,11 +3,12 @@ import { join } from 'std/path/mod.ts'
|
|
3
3
|
import compile from './esbuild.js'
|
4
4
|
|
5
5
|
const root = join(Deno.cwd(), 'test', 'internal')
|
6
|
+
const lightningcssBin = join(Deno.cwd(), 'bin', 'lightningcss')
|
6
7
|
|
7
8
|
Deno.bench('esbuild js', async () => {
|
8
|
-
await compile(['lib/foo.js'], { root })
|
9
|
+
await compile(['lib/foo.js'], { root, lightningcssBin })
|
9
10
|
})
|
10
11
|
|
11
12
|
Deno.bench('esbuild css', async () => {
|
12
|
-
await compile(['lib/foo.css'], { root })
|
13
|
+
await compile(['lib/foo.css'], { root, lightningcssBin })
|
13
14
|
})
|
@@ -23,18 +23,20 @@ import throwCompileError from './esbuild/compile_error.js'
|
|
23
23
|
* esbuild [OPTIONS] <PATHS_ARG>...
|
24
24
|
*
|
25
25
|
* ARGS:
|
26
|
-
* <PATHS_ARG>...
|
26
|
+
* <PATHS_ARG>... One or more file paths or globs to compile.
|
27
27
|
*
|
28
28
|
* OPTIONS:
|
29
|
-
* --root
|
29
|
+
* --root <PATH>
|
30
30
|
* Relative or absolute path to the root or current working directory when compilation will
|
31
31
|
* take place.
|
32
|
-
* --import-map
|
32
|
+
* --import-map <PATH>
|
33
33
|
* Path to an import map, relative to the <root>.
|
34
|
-
* --lightningcss-bin
|
34
|
+
* --lightningcss-bin <PATH>
|
35
35
|
* Path to the lightningcss CLI binary.
|
36
36
|
* --write
|
37
37
|
* Write output to the filesystem according to esbuild logic.
|
38
|
+
* --cache-query-string <STRING>
|
39
|
+
* Query string to append to all imports as a cache buster. Example: `v1`.
|
38
40
|
* --debug
|
39
41
|
* Debug output,
|
40
42
|
*/
|
@@ -42,10 +44,11 @@ if (import.meta.main) {
|
|
42
44
|
!Deno.env.get('RAILS_ENV') && Deno.env.set('RAILS_ENV', 'development')
|
43
45
|
|
44
46
|
const { _: paths, ...options } = parseArgs(Deno.args, {
|
45
|
-
string: ['root', 'import-map', 'lightningcss-bin'],
|
47
|
+
string: ['root', 'import-map', 'lightningcss-bin', 'cache-query-string'],
|
46
48
|
boolean: ['write', 'debug'],
|
47
49
|
alias: {
|
48
50
|
'import-map': 'importMap',
|
51
|
+
'cache-query-string': 'cacheQueryString',
|
49
52
|
'lightningcss-bin': 'lightningcssBin'
|
50
53
|
}
|
51
54
|
})
|
@@ -80,8 +83,8 @@ async function main(paths = [], options = {}) {
|
|
80
83
|
const env = Deno.env.get('RAILS_ENV')
|
81
84
|
const isProd = env === 'production'
|
82
85
|
const isTest = env === 'test'
|
83
|
-
|
84
86
|
const entryPoints = new Set()
|
87
|
+
|
85
88
|
for (let i = 0; i < paths.length; i++) {
|
86
89
|
const path = paths[i]
|
87
90
|
|
@@ -89,6 +92,10 @@ async function main(paths = [], options = {}) {
|
|
89
92
|
for await (const file of expandGlob(path, { root })) {
|
90
93
|
file.isFile && entryPoints.add(file.path)
|
91
94
|
}
|
95
|
+
} else if (path.startsWith('/')) {
|
96
|
+
// Path is absolute, so it must be outsideRoot. Don't prefix the root.
|
97
|
+
// See Proscenium::Middleware::OutsideRoot.
|
98
|
+
entryPoints.add(path)
|
92
99
|
} else {
|
93
100
|
entryPoints.add(join(root, path))
|
94
101
|
}
|
@@ -123,7 +130,7 @@ async function main(paths = [], options = {}) {
|
|
123
130
|
bundle: true,
|
124
131
|
plugins: [
|
125
132
|
envPlugin(),
|
126
|
-
resolvePlugin({ runtimeDir, importMap, debug }),
|
133
|
+
resolvePlugin({ runtimeDir, importMap, debug, cacheQueryString: options.cacheQueryString }),
|
127
134
|
cssPlugin({ lightningcssBin: options.lightningcssBin, debug })
|
128
135
|
],
|
129
136
|
metafile: write,
|
data/lib/proscenium/helper.rb
CHANGED
@@ -3,7 +3,15 @@
|
|
3
3
|
module Proscenium
|
4
4
|
module Helper
|
5
5
|
def compute_asset_path(path, options = {})
|
6
|
-
|
6
|
+
if %i[javascript stylesheet].include?(options[:type])
|
7
|
+
result = "/#{path}"
|
8
|
+
|
9
|
+
if (qs = Proscenium.config.cache_query_string)
|
10
|
+
result << "?#{qs}"
|
11
|
+
end
|
12
|
+
|
13
|
+
return result
|
14
|
+
end
|
7
15
|
|
8
16
|
super
|
9
17
|
end
|
@@ -60,6 +60,10 @@ module Proscenium
|
|
60
60
|
response.content_type = content_type
|
61
61
|
response['X-Proscenium-Middleware'] = name
|
62
62
|
|
63
|
+
if Proscenium.config.cache_query_string && Proscenium.config.cache_max_age
|
64
|
+
response['Cache-Control'] = "public, max-age=#{Proscenium.config.cache_max_age}"
|
65
|
+
end
|
66
|
+
|
63
67
|
yield response if block_given?
|
64
68
|
|
65
69
|
response.finish
|
@@ -15,9 +15,11 @@ module Proscenium
|
|
15
15
|
|
16
16
|
def attempt
|
17
17
|
benchmark :esbuild do
|
18
|
-
render_response build(
|
19
|
-
"#{cli} --root #{root}
|
20
|
-
|
18
|
+
render_response build([
|
19
|
+
"#{cli} --root #{root}",
|
20
|
+
cache_query_string,
|
21
|
+
"--lightningcss-bin #{lightningcss_cli} #{path}"
|
22
|
+
].compact.join(' '))
|
21
23
|
end
|
22
24
|
rescue CompileError => e
|
23
25
|
render_response "export default #{e.detail.to_json}" do |response|
|
@@ -33,9 +35,7 @@ module Proscenium
|
|
33
35
|
|
34
36
|
def cli
|
35
37
|
if ENV['PROSCENIUM_TEST']
|
36
|
-
|
37
|
-
'deno run -q --import-map import_map.json -A', 'lib/proscenium/compilers/esbuild.js'
|
38
|
-
].join(' ')
|
38
|
+
'deno run -q --import-map import_map.json -A lib/proscenium/compilers/esbuild.js'
|
39
39
|
else
|
40
40
|
Gem.bin_path 'proscenium', 'esbuild'
|
41
41
|
end
|
@@ -48,6 +48,11 @@ module Proscenium
|
|
48
48
|
Gem.bin_path 'proscenium', 'lightningcss'
|
49
49
|
end
|
50
50
|
end
|
51
|
+
|
52
|
+
def cache_query_string
|
53
|
+
q = Proscenium.config.cache_query_string
|
54
|
+
q ? "--cache-query-string #{q}" : nil
|
55
|
+
end
|
51
56
|
end
|
52
57
|
end
|
53
58
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Proscenium
|
4
|
+
class Middleware
|
5
|
+
# Provides a way to render files outside of the Rails root during non-production. This is
|
6
|
+
# primarily to support linked NPM modules, for example when using `pnpm link ...`.
|
7
|
+
class OutsideRoot < Esbuild
|
8
|
+
private
|
9
|
+
|
10
|
+
# @override [Esbuild] reassigns root to '/'.
|
11
|
+
def renderable?
|
12
|
+
old_root = root
|
13
|
+
@root = Pathname.new('/')
|
14
|
+
|
15
|
+
super
|
16
|
+
ensure
|
17
|
+
@root = old_root
|
18
|
+
end
|
19
|
+
|
20
|
+
# @override [Esbuild] does not remove leading slash, ensuring it is an absolute path.
|
21
|
+
def path
|
22
|
+
@request.path
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -10,6 +10,7 @@ module Proscenium
|
|
10
10
|
autoload :Base
|
11
11
|
autoload :Esbuild
|
12
12
|
autoload :Runtime
|
13
|
+
autoload :OutsideRoot
|
13
14
|
|
14
15
|
def initialize(app)
|
15
16
|
@app = app
|
@@ -38,6 +39,12 @@ module Proscenium
|
|
38
39
|
def find_type(request)
|
39
40
|
path = Pathname.new(request.path)
|
40
41
|
|
42
|
+
# Non-production only!
|
43
|
+
if request.query_string == 'outsideRoot'
|
44
|
+
return if Rails.env.production?
|
45
|
+
return OutsideRoot if path.fnmatch?(glob_types[:outsideRoot], File::FNM_EXTGLOB)
|
46
|
+
end
|
47
|
+
|
41
48
|
return Runtime if path.fnmatch?(glob_types[:runtime], File::FNM_EXTGLOB)
|
42
49
|
return Esbuild if path.fnmatch?(glob_types[:esbuild], File::FNM_EXTGLOB)
|
43
50
|
end
|
data/lib/proscenium/railtie.rb
CHANGED
@@ -13,7 +13,8 @@ module Proscenium
|
|
13
13
|
# See https://doc.deno.land/https://deno.land/std@0.145.0/path/mod.ts/~/globToRegExp
|
14
14
|
DEFAULT_GLOB_TYPES = {
|
15
15
|
esbuild: '/{config,app,lib,node_modules}/**.{js,mjs,jsx,css}',
|
16
|
-
runtime: '/proscenium-runtime/**.{js,jsx}'
|
16
|
+
runtime: '/proscenium-runtime/**.{js,jsx}',
|
17
|
+
outsideRoot: '/**/*.{js,jsx,mjs,css}'
|
17
18
|
}.freeze
|
18
19
|
|
19
20
|
class << self
|
@@ -27,6 +28,8 @@ module Proscenium
|
|
27
28
|
|
28
29
|
config.proscenium = ActiveSupport::OrderedOptions.new
|
29
30
|
config.proscenium.side_load = true
|
31
|
+
config.proscenium.cache_query_string = Rails.env.production? && ENV.fetch('REVISION', nil)
|
32
|
+
config.proscenium.cache_max_age = 2_592_000 # 30 days
|
30
33
|
config.proscenium.auto_reload = Rails.env.development?
|
31
34
|
config.proscenium.auto_reload_paths ||= %w[lib app config]
|
32
35
|
config.proscenium.auto_reload_extensions ||= /\.(css|jsx?)$/
|
@@ -1,5 +1,4 @@
|
|
1
|
-
import { createConsumer } from 'https://esm.sh/@rails/actioncable@
|
2
|
-
import debounce from 'https://esm.sh/debounce@1.2.1'
|
1
|
+
import { createConsumer } from 'https://esm.sh/v96/@rails/actioncable@7.0.4/es2022/actioncable.js'
|
3
2
|
|
4
3
|
export default socketPath => {
|
5
4
|
const uid = (Date.now() + ((Math.random() * 100) | 0)).toString()
|
@@ -9,7 +8,7 @@ export default socketPath => {
|
|
9
8
|
received: debounce(() => {
|
10
9
|
console.log('[Proscenium] Files changed; reloading...')
|
11
10
|
location.reload()
|
12
|
-
}, 200),
|
11
|
+
}, 200, true),
|
13
12
|
|
14
13
|
connected() {
|
15
14
|
console.log('[Proscenium] Auto-reload websocket connected')
|
@@ -20,3 +19,22 @@ export default socketPath => {
|
|
20
19
|
}
|
21
20
|
})
|
22
21
|
}
|
22
|
+
|
23
|
+
function debounce(func, wait, immediate) {
|
24
|
+
let timeout
|
25
|
+
|
26
|
+
return function () {
|
27
|
+
const args = arguments
|
28
|
+
|
29
|
+
const later = () => {
|
30
|
+
timeout = null
|
31
|
+
!immediate && func.apply(this, args)
|
32
|
+
}
|
33
|
+
|
34
|
+
const callNow = immediate && !timeout
|
35
|
+
clearTimeout(timeout)
|
36
|
+
timeout = setTimeout(later, wait)
|
37
|
+
|
38
|
+
callNow && func.apply(this, args)
|
39
|
+
}
|
40
|
+
}
|
data/lib/proscenium/version.rb
CHANGED
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.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: arm64-darwin
|
6
6
|
authors:
|
7
7
|
- Joel Moss
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actioncable
|
@@ -167,6 +167,7 @@ files:
|
|
167
167
|
- lib/proscenium/middleware/base.rb
|
168
168
|
- lib/proscenium/middleware/esbuild.rb
|
169
169
|
- lib/proscenium/middleware/lightningcss.rb
|
170
|
+
- lib/proscenium/middleware/outside_root.rb
|
170
171
|
- lib/proscenium/middleware/runtime.rb
|
171
172
|
- lib/proscenium/middleware/static.rb
|
172
173
|
- lib/proscenium/phlex.rb
|