proscenium 0.6.0-x86_64-linux → 0.7.0-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +128 -107
  3. data/lib/proscenium/css_module/class_names_resolver.rb +66 -0
  4. data/lib/proscenium/css_module/resolver.rb +76 -0
  5. data/lib/proscenium/css_module.rb +18 -39
  6. data/lib/proscenium/esbuild/golib.rb +97 -0
  7. data/lib/proscenium/esbuild.rb +32 -0
  8. data/lib/proscenium/ext/proscenium +0 -0
  9. data/lib/proscenium/ext/proscenium.h +109 -0
  10. data/lib/proscenium/helper.rb +0 -23
  11. data/lib/proscenium/log_subscriber.rb +26 -0
  12. data/lib/proscenium/middleware/base.rb +28 -36
  13. data/lib/proscenium/middleware/esbuild.rb +18 -44
  14. data/lib/proscenium/middleware/url.rb +1 -6
  15. data/lib/proscenium/middleware.rb +12 -16
  16. data/lib/proscenium/phlex/component_concerns.rb +27 -0
  17. data/lib/proscenium/phlex/page.rb +62 -0
  18. data/lib/proscenium/phlex/react_component.rb +52 -8
  19. data/lib/proscenium/phlex/resolve_css_modules.rb +67 -0
  20. data/lib/proscenium/phlex.rb +34 -33
  21. data/lib/proscenium/railtie.rb +41 -67
  22. data/lib/proscenium/side_load/ensure_loaded.rb +25 -0
  23. data/lib/proscenium/side_load/helper.rb +25 -0
  24. data/lib/proscenium/side_load/monkey.rb +48 -0
  25. data/lib/proscenium/side_load.rb +58 -52
  26. data/lib/proscenium/version.rb +1 -1
  27. data/lib/proscenium/view_component/react_component.rb +14 -0
  28. data/lib/proscenium/view_component.rb +28 -18
  29. data/lib/proscenium.rb +79 -2
  30. metadata +35 -77
  31. data/app/channels/proscenium/connection.rb +0 -13
  32. data/app/channels/proscenium/reload_channel.rb +0 -9
  33. data/bin/esbuild +0 -0
  34. data/bin/lightningcss +0 -0
  35. data/config/routes.rb +0 -7
  36. data/lib/proscenium/compiler.js +0 -84
  37. data/lib/proscenium/compilers/esbuild/argument_error.js +0 -24
  38. data/lib/proscenium/compilers/esbuild/compile_error.js +0 -148
  39. data/lib/proscenium/compilers/esbuild/css/postcss.js +0 -67
  40. data/lib/proscenium/compilers/esbuild/css_plugin.js +0 -172
  41. data/lib/proscenium/compilers/esbuild/env_plugin.js +0 -46
  42. data/lib/proscenium/compilers/esbuild/http_bundle_plugin.js +0 -53
  43. data/lib/proscenium/compilers/esbuild/import_map/parser.js +0 -178
  44. data/lib/proscenium/compilers/esbuild/import_map/read.js +0 -64
  45. data/lib/proscenium/compilers/esbuild/import_map/resolver.js +0 -95
  46. data/lib/proscenium/compilers/esbuild/import_map/utils.js +0 -25
  47. data/lib/proscenium/compilers/esbuild/resolve_plugin.js +0 -207
  48. data/lib/proscenium/compilers/esbuild/setup_plugin.js +0 -45
  49. data/lib/proscenium/compilers/esbuild/solidjs_plugin.js +0 -24
  50. data/lib/proscenium/compilers/esbuild.bench.js +0 -14
  51. data/lib/proscenium/compilers/esbuild.js +0 -179
  52. data/lib/proscenium/link_to_helper.rb +0 -40
  53. data/lib/proscenium/middleware/lightningcss.rb +0 -64
  54. data/lib/proscenium/middleware/outside_root.rb +0 -26
  55. data/lib/proscenium/middleware/runtime.rb +0 -22
  56. data/lib/proscenium/middleware/static.rb +0 -14
  57. data/lib/proscenium/phlex/component.rb +0 -9
  58. data/lib/proscenium/precompile.rb +0 -31
  59. data/lib/proscenium/runtime/auto_reload.js +0 -40
  60. data/lib/proscenium/runtime/react_shim/index.js +0 -1
  61. data/lib/proscenium/runtime/react_shim/package.json +0 -5
  62. data/lib/proscenium/utils.js +0 -12
  63. data/lib/tasks/assets.rake +0 -19
@@ -1,207 +0,0 @@
1
- import { join, resolve } from 'std/path/mod.ts'
2
- import resolveFromImportMap from './import_map/resolver.js'
3
- import { cache } from 'cache'
4
-
5
- import setup from './setup_plugin.js'
6
- import { isBareModule } from '../../utils.js'
7
-
8
- const importKinds = ['import-statement', 'dynamic-import', 'require-call', 'import-rule']
9
-
10
- export default setup('resolve', (build, options) => {
11
- const { runtimeDir, importMap } = options
12
- const cwd = build.initialOptions.absWorkingDir
13
- const runtimeCwdAlias = `${cwd}/proscenium-runtime`
14
- let bundled = false
15
-
16
- const env = Deno.env.get('RAILS_ENV')
17
- const isProd = env === 'production'
18
-
19
- return [
20
- {
21
- // Filters for imports starting with `url:http://` or `url:https://`; returning the path
22
- // without the `url:` prefix, and a namespace of 'url`
23
- type: 'onResolve',
24
- filter: /^url:https?:\/\//,
25
- callback(args) {
26
- return {
27
- path: args.path.slice(4),
28
- namespace: 'url'
29
- }
30
- }
31
- },
32
-
33
- {
34
- type: 'onResolve',
35
- filter: /.*/,
36
- namespace: 'url',
37
- callback(args) {
38
- if (!isBareModule(args.path)) {
39
- return {
40
- path: new URL(args.path, args.importer).toString(),
41
- namespace: 'url'
42
- }
43
- }
44
- }
45
- },
46
-
47
- {
48
- type: 'onLoad',
49
- filter: /.*/,
50
- namespace: 'url',
51
- async callback(args) {
52
- const file = await cache(args.path)
53
- const contents = await Deno.readTextFile(file.path)
54
-
55
- return { contents }
56
- }
57
- },
58
-
59
- {
60
- type: 'onResolve',
61
- filter: /.*/,
62
- async callback(args) {
63
- if (args.path.includes('?')) {
64
- const [path, query] = args.path.split('?')
65
- args.path = path
66
- args.suffix = `?${query}`
67
- args.queryParams = new URLSearchParams(query)
68
- } else if (options.cacheQueryString && options.cacheQueryString !== '') {
69
- args.suffix = `?${options.cacheQueryString}`
70
- }
71
-
72
- // Mark remote modules as external. If not css, then the path is prefixed with "url:", which
73
- // is then handled by the Url Middleware.
74
- if (
75
- !args.importer.endsWith('.css') &&
76
- (args.path.startsWith('http://') || args.path.startsWith('https://'))
77
- ) {
78
- return { path: `/url:${encodeURIComponent(args.path)}`, external: true }
79
- }
80
-
81
- // Rewrite the path to the actual runtime directory.
82
- if (args.path.startsWith(runtimeCwdAlias)) {
83
- return { path: join(runtimeDir, args.path.slice(runtimeCwdAlias.length)) }
84
- }
85
-
86
- // Everything else is unbundled.
87
- if (importKinds.includes(args.kind)) {
88
- return await unbundleImport(args)
89
- }
90
- }
91
- }
92
- ]
93
-
94
- // Resolve the given `params.path` to a path relative to the Rails root.
95
- //
96
- // Examples:
97
- // 'react' -> '/.../node_modules/react/index.js'
98
- // './my_module' -> '/.../app/my_module.js'
99
- // '/app/my_module' -> '/.../app/my_module.js'
100
- async function unbundleImport(params) {
101
- const result = { path: params.path, suffix: params.suffix }
102
-
103
- if (importMap) {
104
- let baseURL
105
- if (params.importer.startsWith('https://') || params.importer.startsWith('http://')) {
106
- baseURL = new URL(params.importer)
107
- } else {
108
- baseURL = new URL(params.importer.slice(cwd.length), 'file://')
109
- }
110
-
111
- const { matched, resolvedImport } = resolveFromImportMap(params.path, importMap, baseURL)
112
- // console.log({ importMap, matched, resolvedImport })
113
-
114
- if (matched) {
115
- if (resolvedImport instanceof URL) {
116
- if (resolvedImport.protocol === 'file:') {
117
- params.path = resolvedImport.pathname
118
- } else {
119
- if (params.importer.endsWith('.css')) {
120
- return { path: resolvedImport.href, external: true }
121
- }
122
-
123
- return { path: `/url:${encodeURIComponent(resolvedImport.href)}`, external: true }
124
- }
125
- } else {
126
- result.path = resolvedImport
127
- }
128
- }
129
- }
130
-
131
- // Absolute path - append to current working dir.
132
- if (params.path.startsWith('/')) {
133
- result.path = resolve(cwd, params.path.slice(1))
134
- }
135
-
136
- const resOptions = {
137
- // If path is a bare module (node_modules), and resolveDir is the Proscenium runtime dir, or
138
- // is the current working dir, then use `cwd` as the `resolveDir`, otherwise pass it through
139
- // as is. This ensures that nested node_modules are resolved correctly.
140
- resolveDir:
141
- isBareModule(result.path) &&
142
- (!params.resolveDir.startsWith(cwd) || params.resolveDir.startsWith(runtimeDir))
143
- ? cwd
144
- : params.resolveDir,
145
- kind: params.kind,
146
- pluginData: {
147
- // We use this property later on, as we should ignore this resolution call.
148
- isResolvingPath: true
149
- }
150
- }
151
-
152
- // Resolve the path using esbuild's internal resolution. This allows us to import node packages
153
- // and extension-less paths without custom code, as esbuild with resolve them for us.
154
- const resolveResult = await build.resolve(result.path, resOptions)
155
-
156
- // Simple return the resolved result if we have an error. Usually happens when module is not
157
- // found.
158
- if (resolveResult.errors.length > 0) return resolveResult
159
-
160
- // If 'bundle-all' queryParam is defined, return the resolveResult.
161
- if (bundled || params.queryParams?.has('bundle-all')) {
162
- bundled = true
163
- return { ...resolveResult, suffix: '?bundle-all' }
164
- }
165
-
166
- // If 'bundle' queryParam is defined, return the resolveResult.
167
- if (params.queryParams?.has('bundle')) {
168
- return { ...resolveResult, suffix: '?bundle' }
169
- }
170
-
171
- if (resolveResult.path.startsWith(runtimeDir)) {
172
- result.path = '/proscenium-runtime' + resolveResult.path.slice(runtimeDir.length)
173
- } else if (!resolveResult.path.startsWith(cwd) && !isProd) {
174
- // Resolved path is not in the current working directory. It could be linked to a file outside
175
- // the CWD, or it's just invalid. If not in production, return as an outsideRoot namespaced,
176
- // and externally suffixed path. This lets the Rails Proscenium::Middleware::OutsideRoot
177
- // handle the import.
178
- return {
179
- ...resolveResult,
180
- namespace: 'outsideRoot',
181
- path: `${resolveResult.path}?outsideRoot`,
182
- external: true
183
- }
184
- } else {
185
- result.path = resolveResult.path.slice(cwd.length)
186
- }
187
-
188
- result.sideEffects = resolveResult.sideEffects
189
-
190
- if (
191
- params.path.endsWith('.css') &&
192
- params.kind === 'import-statement' &&
193
- /\.jsx?$/.test(params.importer)
194
- ) {
195
- // We're importing a CSS file from JS(X).
196
- return { ...resolveResult, pluginData: { importedFromJs: true } }
197
- } else {
198
- result.external = true
199
- }
200
-
201
- if (result.suffix && result.suffix !== '') {
202
- result.path = `${result.path}${result.suffix}`
203
- }
204
-
205
- return result
206
- }
207
- })
@@ -1,45 +0,0 @@
1
- export default (pluginName, pluginFn) => {
2
- return (options = {}) => ({
3
- name: pluginName,
4
- async setup(build) {
5
- const callbacks = await pluginFn(build, options)
6
-
7
- callbacks.forEach(({ type, callback, filter, namespace }) => {
8
- if (type === 'onResolve') {
9
- build.onResolve({ filter, namespace }, async params => {
10
- if (params.pluginData?.isResolvingPath) return
11
-
12
- let results
13
-
14
- if (options.debug) {
15
- console.debug()
16
- console.group(`plugin(${pluginName}):onResolve`, { filter, namespace })
17
- console.debug('params:', params)
18
-
19
- try {
20
- results = await callback(params)
21
- console.debug('results:', results)
22
- } finally {
23
- console.groupEnd()
24
- }
25
- } else {
26
- results = await callback(params)
27
- }
28
-
29
- return results
30
- })
31
- } else if (type === 'onLoad') {
32
- build.onLoad({ filter, namespace }, async params => {
33
- options.debug && console.debug(`plugin(${pluginName}):onLoad`, { params })
34
-
35
- const results = await callback(params)
36
-
37
- options.debug && console.debug(`plugin(${pluginName}):onLoad`, { results })
38
-
39
- return results
40
- })
41
- }
42
- })
43
- }
44
- })
45
- }
@@ -1,24 +0,0 @@
1
- import { basename } from 'std/path/mod.ts'
2
- import { transformAsync } from '@babel/core'
3
- import solid from 'babel-preset-solid'
4
-
5
- import { setup } from './setup_plugin.js'
6
-
7
- export default setup('solidjs', () => {
8
- return [
9
- {
10
- type: 'onLoad',
11
- filter: /\.jsx$/,
12
- async callback(args) {
13
- const source = await Deno.readTextFile(args.path)
14
-
15
- const { code } = await transformAsync(source, {
16
- presets: [solid],
17
- filename: basename(args.path)
18
- })
19
-
20
- return { contents: code, loader: 'js' }
21
- }
22
- }
23
- ]
24
- })
@@ -1,14 +0,0 @@
1
- import { join } from 'std/path/mod.ts'
2
-
3
- import compile from './esbuild.js'
4
-
5
- const root = join(Deno.cwd(), 'test', 'internal')
6
- const lightningcssBin = join(Deno.cwd(), 'bin', 'lightningcss')
7
-
8
- Deno.bench('esbuild js', async () => {
9
- await compile(['lib/foo.js'], { root, lightningcssBin })
10
- })
11
-
12
- Deno.bench('esbuild css', async () => {
13
- await compile(['lib/foo.css'], { root, lightningcssBin })
14
- })
@@ -1,179 +0,0 @@
1
- import { writeAll } from 'std/streams/mod.ts'
2
- import { parse as parseArgs } from 'std/flags/mod.ts'
3
- import { expandGlob } from 'std/fs/mod.ts'
4
- import { join, isGlob, resolve, dirname, fromFileUrl } from 'std/path/mod.ts'
5
- import { build, stop } from 'esbuild'
6
-
7
- import readImportMap from './esbuild/import_map/read.js'
8
- import envPlugin from './esbuild/env_plugin.js'
9
- import cssPlugin from './esbuild/css_plugin.js'
10
- import resolvePlugin from './esbuild/resolve_plugin.js'
11
- import ArgumentError from './esbuild/argument_error.js'
12
- import throwCompileError from './esbuild/compile_error.js'
13
-
14
- /**
15
- * Compile the given paths, outputting the result to stdout. This is designed to be called as a CLI:
16
- *
17
- * Example with Deno run (dev and test):
18
- * deno run -A lib/proscenium/compilers/esbuild.js --root ./test/internal lib/foo.js
19
- * Example with Deno compiled binary:
20
- * bin/esbuild lib/proscenium/compilers/esbuild.js --root ./test/internal lib/foo.js
21
- *
22
- * USAGE:
23
- * esbuild [OPTIONS] <PATHS_ARG>...
24
- *
25
- * ARGS:
26
- * <PATHS_ARG>... One or more file paths or globs to compile.
27
- *
28
- * OPTIONS:
29
- * --root <PATH>
30
- * Relative or absolute path to the root or current working directory when compilation will
31
- * take place.
32
- * --import-map <PATH>
33
- * Path to an import map, relative to the <root>.
34
- * --lightningcss-bin <PATH>
35
- * Path to the lightningcss CLI binary.
36
- * --write
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`.
40
- * --debug
41
- * Debug output,
42
- */
43
- if (import.meta.main) {
44
- !Deno.env.get('RAILS_ENV') && Deno.env.set('RAILS_ENV', 'development')
45
-
46
- const { _: paths, ...options } = parseArgs(Deno.args, {
47
- string: ['root', 'import-map', 'lightningcss-bin', 'cache-query-string'],
48
- boolean: ['write', 'debug'],
49
- alias: {
50
- 'import-map': 'importMap',
51
- 'cache-query-string': 'cacheQueryString',
52
- 'lightningcss-bin': 'lightningcssBin'
53
- }
54
- })
55
-
56
- let result = await main(paths, options)
57
-
58
- // `result` is an error object, so return to stderr as JSON, and an exit code of 1.
59
- if (isPlainObject(result)) {
60
- result = new TextEncoder().encode(`(${throwCompileError()})(${JSON.stringify(result)})`)
61
- }
62
-
63
- await writeAll(Deno.stdout, result)
64
- }
65
-
66
- async function main(paths = [], options = {}) {
67
- const { write, debug } = { write: false, ...options }
68
-
69
- if (!Array.isArray(paths) || paths.length < 1) throw new ArgumentError('pathsRequired')
70
- if (!options.root) throw new ArgumentError('rootRequired')
71
- if (!options.lightningcssBin) throw new ArgumentError('lightningcssBinRequired')
72
-
73
- const root = resolve(options.root)
74
-
75
- // Make sure that `root` is a valid directory.
76
- try {
77
- const stat = Deno.lstatSync(root)
78
- if (!stat.isDirectory) throw new ArgumentError('rootUnknown', { root })
79
- } catch {
80
- throw new ArgumentError('rootUnknown', { root })
81
- }
82
-
83
- const env = Deno.env.get('RAILS_ENV')
84
- const isProd = env === 'production'
85
- const isTest = env === 'test'
86
- const entryPoints = new Set()
87
-
88
- for (let i = 0; i < paths.length; i++) {
89
- const path = paths[i]
90
-
91
- if (isGlob(path)) {
92
- for await (const file of expandGlob(path, { root })) {
93
- file.isFile && entryPoints.add(file.path)
94
- }
95
- } else if (path.startsWith('/') || /^url:https?:\/\//.test(path)) {
96
- // Path is absolute, or is prefixed with 'url:', so it must be outsideRoot, or Url. Don't
97
- // prefix the root.
98
- // See Proscenium::Middleware::[OutsideRoot|Url].
99
- entryPoints.add(path)
100
- } else {
101
- entryPoints.add(join(root, path))
102
- }
103
- }
104
-
105
- let importMap
106
- try {
107
- importMap = readImportMap(options.importMap, root)
108
- } catch (error) {
109
- return {
110
- detail: error.stack,
111
- text: `Cannot read/parse import map: ${error.message}`,
112
- location: {
113
- file: error.file
114
- }
115
- }
116
- }
117
-
118
- const runtimeDir = resolve(dirname(fromFileUrl(import.meta.url)), '../runtime')
119
-
120
- const params = {
121
- entryPoints: Array.from(entryPoints),
122
- absWorkingDir: root,
123
- logLevel: 'silent',
124
- logLimit: 1,
125
- outdir: 'public/assets',
126
- outbase: './',
127
- format: 'esm',
128
- jsx: 'automatic',
129
- jsxDev: !isTest && !isProd,
130
- minify: isProd,
131
- bundle: true,
132
-
133
- // The Esbuild default places browser before module, but we're building for modern browsers
134
- // which support esm. So we prioritise that. Some libraries export a "browser" build that still
135
- // uses CJS.
136
- mainFields: ['module', 'browser', 'main'],
137
-
138
- plugins: [
139
- envPlugin(),
140
- resolvePlugin({ runtimeDir, importMap, debug, cacheQueryString: options.cacheQueryString }),
141
- cssPlugin({ lightningcssBin: options.lightningcssBin, debug })
142
- ],
143
- metafile: write,
144
- write
145
- }
146
-
147
- if (!debug) {
148
- params.sourcemap = isProd || isTest ? false : 'inline'
149
- }
150
-
151
- let result
152
- try {
153
- result = await build(params)
154
- } catch (error) {
155
- if (debug) {
156
- throw error
157
- }
158
-
159
- return { ...error.errors[0] }
160
- } finally {
161
- stop()
162
- }
163
-
164
- if (write) {
165
- return new TextEncoder().encode(JSON.stringify(result))
166
- } else {
167
- const fileIndex = params.sourcemap === 'linked' ? 1 : 0
168
- return result.outputFiles[fileIndex].contents
169
- }
170
- }
171
-
172
- export function isPlainObject(value) {
173
- if (Object.prototype.toString.call(value) !== '[object Object]') return false
174
-
175
- const prototype = Object.getPrototypeOf(value)
176
- return prototype === null || prototype === Object.prototype
177
- }
178
-
179
- export default main
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Proscenium
4
- module LinkToHelper
5
- # Overrides ActionView::Helpers::UrlHelper#link_to to allow passing a component instance as the
6
- # URL, which will build the URL from the component path, eg. `/components/my_component`. The
7
- # resulting link tag will also populate the `data` attribute with the component props.
8
- #
9
- # Example:
10
- # link_to 'Go to', MyComponent
11
- #
12
- # TODO: ummm, todo it! ;)
13
- end
14
-
15
- # Component handling for the `link_to` helper.
16
- class LinkToComponentArguments
17
- def initialize(options, name_argument_index, context)
18
- @options = options
19
- @name_argument_index = name_argument_index
20
- @component = @options[@name_argument_index]
21
-
22
- # We have to render the component, and then extract the props from the component. Rendering
23
- # first ensures that we have all the correct props.
24
- context.render @component
25
- end
26
-
27
- def helper_options
28
- @options[@name_argument_index] = "/components#{@component.virtual_path}"
29
- @options[@name_argument_index += 1] ||= {}
30
- @options[@name_argument_index][:rel] = 'nofollow'
31
- @options[@name_argument_index][:data] ||= {}
32
- @options[@name_argument_index][:data][:component] = {
33
- path: @component.virtual_path,
34
- props: @component.props
35
- }
36
-
37
- @options
38
- end
39
- end
40
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'oj'
4
-
5
- module Proscenium
6
- class Middleware
7
- class Lightningcss < Base
8
- def attempt
9
- benchmark :lightningcss do
10
- with_custom_media { |path| build path }
11
- end
12
- end
13
-
14
- private
15
-
16
- def with_custom_media
17
- if custom_media?
18
- Tempfile.create do |f|
19
- contents = Pathname.new("#{root}#{@request.path}").read
20
- f.write contents, "\n", custom_media_path.read
21
- f.rewind
22
-
23
- yield f.path
24
- end
25
- else
26
- yield "#{root}#{@request.path}"
27
- end
28
- end
29
-
30
- def build(path)
31
- results = super("#{cli} #{cli_options.join ' '} #{path}")
32
- render_response css_module? ? Oj.load(results, mode: :strict)['code'] : results
33
- end
34
-
35
- def custom_media?
36
- @custom_media ||= custom_media_path.exist?
37
- end
38
-
39
- def custom_media_path
40
- @custom_media_path ||= Rails.root.join('lib', 'custom_media_queries.css')
41
- end
42
-
43
- def cli
44
- Gem.bin_path 'proscenium', 'lightningcss'
45
- end
46
-
47
- def cli_options
48
- options = ['--nesting', '--targets', "'>= 0.25%'"]
49
- options << '--custom-media' if custom_media?
50
-
51
- if css_module?
52
- hash = Digest::SHA1.hexdigest(@request.path)[..7]
53
- options += ['--css-modules', '--css-modules-pattern', "'[local]#{hash}'"]
54
- end
55
-
56
- Rails.env.production? ? options << '-m' : options
57
- end
58
-
59
- def css_module?
60
- @css_module ||= /\.module\.css$/i.match?(@request.path_info)
61
- end
62
- end
63
- end
64
- end
@@ -1,26 +0,0 @@
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
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Proscenium
4
- class Middleware
5
- class Runtime < Esbuild
6
- private
7
-
8
- def renderable?
9
- old_root = root
10
- old_path_info = @request.path_info
11
-
12
- @root = Pathname.new(__dir__).join('../')
13
- @request.path_info = @request.path_info.sub(%r{^/proscenium-runtime/}, 'runtime/')
14
-
15
- super
16
- ensure
17
- @request.path_info = old_path_info
18
- @root = old_root
19
- end
20
- end
21
- end
22
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Proscenium
4
- module Middleware
5
- # Serves static files from disk that end with .js or .css.
6
- class Static < Base
7
- def attempt
8
- benchmark :static do
9
- Rack::File.new(root, { 'X-Proscenium-Middleware' => 'static' }).call(@request.env)
10
- end
11
- end
12
- end
13
- end
14
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Proscenium::Phlex::Component < Proscenium::Phlex
4
- private
5
-
6
- def virtual_path
7
- "/#{self.class.name.underscore}"
8
- end
9
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'open3'
4
-
5
- module Proscenium
6
- class Precompile
7
- def self.call
8
- new.call
9
- end
10
-
11
- def call
12
- Rails.application.config.proscenium.glob_types.find do |type, globs|
13
- cmd = "#{cli type} --root #{Rails.root} '#{globs.join "' '"}' --write"
14
- _, stderr, status = Open3.capture3(cmd)
15
-
16
- raise stderr unless status.success?
17
- raise "#{type} compiliation failed -- #{stderr}" unless stderr.empty?
18
- end
19
- end
20
-
21
- private
22
-
23
- def cli(type)
24
- if ENV['PROSCENIUM_TEST']
25
- "deno run -q --import-map import_map.json -A lib/proscenium/compilers/#{type}.js"
26
- else
27
- Gem.bin_path 'proscenium', type.to_s
28
- end
29
- end
30
- end
31
- end