proscenium 0.6.0-x86_64-linux → 0.7.0-x86_64-linux
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 +128 -107
- data/lib/proscenium/css_module/class_names_resolver.rb +66 -0
- data/lib/proscenium/css_module/resolver.rb +76 -0
- data/lib/proscenium/css_module.rb +18 -39
- data/lib/proscenium/esbuild/golib.rb +97 -0
- data/lib/proscenium/esbuild.rb +32 -0
- data/lib/proscenium/ext/proscenium +0 -0
- data/lib/proscenium/ext/proscenium.h +109 -0
- data/lib/proscenium/helper.rb +0 -23
- data/lib/proscenium/log_subscriber.rb +26 -0
- data/lib/proscenium/middleware/base.rb +28 -36
- data/lib/proscenium/middleware/esbuild.rb +18 -44
- data/lib/proscenium/middleware/url.rb +1 -6
- data/lib/proscenium/middleware.rb +12 -16
- data/lib/proscenium/phlex/component_concerns.rb +27 -0
- data/lib/proscenium/phlex/page.rb +62 -0
- data/lib/proscenium/phlex/react_component.rb +52 -8
- data/lib/proscenium/phlex/resolve_css_modules.rb +67 -0
- data/lib/proscenium/phlex.rb +34 -33
- data/lib/proscenium/railtie.rb +41 -67
- data/lib/proscenium/side_load/ensure_loaded.rb +25 -0
- data/lib/proscenium/side_load/helper.rb +25 -0
- data/lib/proscenium/side_load/monkey.rb +48 -0
- data/lib/proscenium/side_load.rb +58 -52
- data/lib/proscenium/version.rb +1 -1
- data/lib/proscenium/view_component/react_component.rb +14 -0
- data/lib/proscenium/view_component.rb +28 -18
- data/lib/proscenium.rb +79 -2
- metadata +35 -77
- data/app/channels/proscenium/connection.rb +0 -13
- data/app/channels/proscenium/reload_channel.rb +0 -9
- data/bin/esbuild +0 -0
- data/bin/lightningcss +0 -0
- data/config/routes.rb +0 -7
- data/lib/proscenium/compiler.js +0 -84
- data/lib/proscenium/compilers/esbuild/argument_error.js +0 -24
- data/lib/proscenium/compilers/esbuild/compile_error.js +0 -148
- data/lib/proscenium/compilers/esbuild/css/postcss.js +0 -67
- data/lib/proscenium/compilers/esbuild/css_plugin.js +0 -172
- data/lib/proscenium/compilers/esbuild/env_plugin.js +0 -46
- data/lib/proscenium/compilers/esbuild/http_bundle_plugin.js +0 -53
- data/lib/proscenium/compilers/esbuild/import_map/parser.js +0 -178
- data/lib/proscenium/compilers/esbuild/import_map/read.js +0 -64
- data/lib/proscenium/compilers/esbuild/import_map/resolver.js +0 -95
- data/lib/proscenium/compilers/esbuild/import_map/utils.js +0 -25
- data/lib/proscenium/compilers/esbuild/resolve_plugin.js +0 -207
- data/lib/proscenium/compilers/esbuild/setup_plugin.js +0 -45
- data/lib/proscenium/compilers/esbuild/solidjs_plugin.js +0 -24
- data/lib/proscenium/compilers/esbuild.bench.js +0 -14
- data/lib/proscenium/compilers/esbuild.js +0 -179
- data/lib/proscenium/link_to_helper.rb +0 -40
- data/lib/proscenium/middleware/lightningcss.rb +0 -64
- data/lib/proscenium/middleware/outside_root.rb +0 -26
- data/lib/proscenium/middleware/runtime.rb +0 -22
- data/lib/proscenium/middleware/static.rb +0 -14
- data/lib/proscenium/phlex/component.rb +0 -9
- data/lib/proscenium/precompile.rb +0 -31
- data/lib/proscenium/runtime/auto_reload.js +0 -40
- data/lib/proscenium/runtime/react_shim/index.js +0 -1
- data/lib/proscenium/runtime/react_shim/package.json +0 -5
- data/lib/proscenium/utils.js +0 -12
- 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,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
|