proscenium 0.5.1-x86_64-darwin → 0.7.0-x86_64-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 +128 -92
- data/bin/proscenium +0 -0
- data/bin/proscenium.h +109 -0
- data/config/routes.rb +0 -3
- 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/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 -72
- 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/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.js +0 -59
- data/lib/proscenium/compilers/esbuild/resolve_plugin.js +0 -205
- 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 -8
- data/lib/tasks/assets.rake +0 -19
@@ -1,172 +0,0 @@
|
|
1
|
-
import { crypto } from 'std/crypto/mod.ts'
|
2
|
-
import { join, dirname, basename } from 'std/path/mod.ts'
|
3
|
-
|
4
|
-
import { fileExists } from '../../utils.js'
|
5
|
-
import postcss from './css/postcss.js'
|
6
|
-
import setup from './setup_plugin.js'
|
7
|
-
|
8
|
-
export default setup('css', async (build, options) => {
|
9
|
-
const cwd = build.initialOptions.absWorkingDir
|
10
|
-
|
11
|
-
let customMedia
|
12
|
-
try {
|
13
|
-
customMedia = await Deno.readTextFile(join(cwd, 'config', 'custom_media_queries.css'))
|
14
|
-
} catch {
|
15
|
-
// do nothing, as we don't require custom media.
|
16
|
-
}
|
17
|
-
|
18
|
-
return [
|
19
|
-
{
|
20
|
-
type: 'onLoad',
|
21
|
-
filter: /\.css$/,
|
22
|
-
namespace: 'file',
|
23
|
-
async callback(args) {
|
24
|
-
const hash = await digest(args.path.slice(cwd.length))
|
25
|
-
const isCssModule = args.path.endsWith('.module.css')
|
26
|
-
|
27
|
-
// If path is a CSS module, imported from JS, and a side-loaded ViewComponent stylesheet,
|
28
|
-
// simply return a JS proxy of the class names. The stylesheet itself will have already been
|
29
|
-
// side loaded. This avoids compiling the CSS all over again.
|
30
|
-
if (isCssModule && args.pluginData?.importedFromJs && (await isViewComponent(args.path))) {
|
31
|
-
return {
|
32
|
-
resolveDir: cwd,
|
33
|
-
loader: 'js',
|
34
|
-
contents: cssModulesProxyTemplate(hash)
|
35
|
-
}
|
36
|
-
}
|
37
|
-
|
38
|
-
let cmd = [
|
39
|
-
options.lightningcssBin,
|
40
|
-
'--nesting',
|
41
|
-
'--error-recovery',
|
42
|
-
args.pluginData?.importedFromJs && '--minify',
|
43
|
-
'--targets',
|
44
|
-
'>= 0.25%'
|
45
|
-
].filter(Boolean)
|
46
|
-
|
47
|
-
// This will process the CSS with Postcss only if it needs to.
|
48
|
-
let [tmpFile, contents] = await postcss(cwd, args.path)
|
49
|
-
|
50
|
-
// As custom media are defined in their own file, we have to append the file contents to our
|
51
|
-
// stylesheet, so that the custom media can be used.
|
52
|
-
if (customMedia) {
|
53
|
-
cmd.push('--custom-media')
|
54
|
-
|
55
|
-
if (!tmpFile && !contents) {
|
56
|
-
tmpFile = await Deno.makeTempFile()
|
57
|
-
contents = await Deno.readTextFile(args.path)
|
58
|
-
}
|
59
|
-
|
60
|
-
contents += customMedia
|
61
|
-
}
|
62
|
-
|
63
|
-
if (tmpFile && contents) {
|
64
|
-
await Deno.writeTextFile(tmpFile, contents)
|
65
|
-
}
|
66
|
-
|
67
|
-
if (isCssModule) {
|
68
|
-
cmd = cmd.concat(['--css-modules', '--css-modules-pattern', `[local]${hash}`])
|
69
|
-
}
|
70
|
-
|
71
|
-
const p = Deno.run({
|
72
|
-
cmd: [...cmd, tmpFile || args.path],
|
73
|
-
stdout: 'piped',
|
74
|
-
stderr: 'piped'
|
75
|
-
})
|
76
|
-
|
77
|
-
const { code } = await p.status()
|
78
|
-
const rawOutput = await p.output()
|
79
|
-
const rawError = await p.stderrOutput()
|
80
|
-
|
81
|
-
// Even though Deno docs say that reading the outputs (above) closes their pipes, warnings
|
82
|
-
// are raised during tests that the child process have not been closed. So we manually close
|
83
|
-
// here.
|
84
|
-
p.close()
|
85
|
-
|
86
|
-
// Success!
|
87
|
-
if (code === 0) {
|
88
|
-
let contents = new TextDecoder().decode(rawOutput)
|
89
|
-
if (isCssModule) {
|
90
|
-
contents = JSON.parse(contents)
|
91
|
-
}
|
92
|
-
|
93
|
-
// If stylesheet is imported from JS, then we return JS code that appends the stylesheet
|
94
|
-
// in a <style> in the <head> of the page, and if the stylesheet is a CSS module, it
|
95
|
-
// exports a plain object of class names.
|
96
|
-
if (args.pluginData?.importedFromJs) {
|
97
|
-
const code = isCssModule ? contents.code : contents
|
98
|
-
const mod = [
|
99
|
-
`let e = document.querySelector('#_${hash}');`,
|
100
|
-
'if (!e) {',
|
101
|
-
"e = document.createElement('style');",
|
102
|
-
`e.id = '_${hash}';`,
|
103
|
-
'document.head.appendChild(e);',
|
104
|
-
`e.appendChild(document.createTextNode(\`${code}\`));`,
|
105
|
-
'}'
|
106
|
-
]
|
107
|
-
|
108
|
-
if (isCssModule) {
|
109
|
-
const classes = {}
|
110
|
-
for (const key in contents.exports) {
|
111
|
-
if (Object.hasOwnProperty.call(contents.exports, key)) {
|
112
|
-
classes[key] = contents.exports[key].name
|
113
|
-
}
|
114
|
-
}
|
115
|
-
mod.push(`export default ${JSON.stringify(classes)};`)
|
116
|
-
}
|
117
|
-
|
118
|
-
// We are importing from JS, so return the entire result from LightningCSS via the js
|
119
|
-
// loader.
|
120
|
-
return {
|
121
|
-
resolveDir: cwd,
|
122
|
-
loader: 'js',
|
123
|
-
contents: mod.join('')
|
124
|
-
}
|
125
|
-
}
|
126
|
-
|
127
|
-
return { loader: 'css', contents: isCssModule ? contents.code : contents }
|
128
|
-
} else {
|
129
|
-
const errorString = new TextDecoder().decode(rawError)
|
130
|
-
throw errorString
|
131
|
-
}
|
132
|
-
}
|
133
|
-
}
|
134
|
-
]
|
135
|
-
})
|
136
|
-
|
137
|
-
async function digest(value) {
|
138
|
-
value = new TextEncoder().encode(value)
|
139
|
-
const view = new DataView(await crypto.subtle.digest('SHA-1', value))
|
140
|
-
|
141
|
-
let hexCodes = ''
|
142
|
-
for (let index = 0; index < view.byteLength; index += 4) {
|
143
|
-
hexCodes += view.getUint32(index).toString(16).padStart(8, '0')
|
144
|
-
}
|
145
|
-
|
146
|
-
return hexCodes.slice(0, 8)
|
147
|
-
}
|
148
|
-
|
149
|
-
async function isViewComponent(path) {
|
150
|
-
const fileName = basename(path)
|
151
|
-
const dirName = dirname(path)
|
152
|
-
|
153
|
-
return (
|
154
|
-
(fileName === 'component.module.css' && (await fileExists(join(dirName, 'component.rb')))) ||
|
155
|
-
(fileName.endsWith('_component.module.css') &&
|
156
|
-
(await fileExists(join(dirName, fileName.replace(/\.module\.css$/, '.rb')))))
|
157
|
-
)
|
158
|
-
}
|
159
|
-
|
160
|
-
function cssModulesProxyTemplate(hash) {
|
161
|
-
return [
|
162
|
-
`export default new Proxy( {}, {`,
|
163
|
-
` get(target, prop, receiver) {`,
|
164
|
-
` if (prop in target || typeof prop === 'symbol') {`,
|
165
|
-
` return Reflect.get(target, prop, receiver)`,
|
166
|
-
` } else {`,
|
167
|
-
` return prop + '${hash}'`,
|
168
|
-
` }`,
|
169
|
-
` }`,
|
170
|
-
`})`
|
171
|
-
].join('')
|
172
|
-
}
|
@@ -1,46 +0,0 @@
|
|
1
|
-
import setup from './setup_plugin.js'
|
2
|
-
|
3
|
-
// Export environment variables as named exports only. You can also import from `env:ENV_VAR_NAME`,
|
4
|
-
// which will return the value of the environment variable as the default export. This allows you to
|
5
|
-
// safely import a variable regardless of its existence.
|
6
|
-
export default setup('env', () => {
|
7
|
-
return [
|
8
|
-
{
|
9
|
-
type: 'onResolve',
|
10
|
-
filter: /^env(:.+)?$/,
|
11
|
-
callback({ path }) {
|
12
|
-
return { path, namespace: 'env' }
|
13
|
-
}
|
14
|
-
},
|
15
|
-
|
16
|
-
{
|
17
|
-
type: 'onLoad',
|
18
|
-
filter: /.*/,
|
19
|
-
namespace: 'env',
|
20
|
-
callback({ path }) {
|
21
|
-
if (path.includes(':')) {
|
22
|
-
const name = Deno.env.get(path.split(':')[1])
|
23
|
-
|
24
|
-
return {
|
25
|
-
loader: 'js',
|
26
|
-
contents: name ? `export default '${name}'` : `export default ${name}`
|
27
|
-
}
|
28
|
-
}
|
29
|
-
|
30
|
-
const env = Deno.env.toObject()
|
31
|
-
const contents = []
|
32
|
-
|
33
|
-
for (const key in env) {
|
34
|
-
if (Object.hasOwnProperty.call(env, key)) {
|
35
|
-
contents.push(`export const ${key} = '${env[key]}'`)
|
36
|
-
}
|
37
|
-
}
|
38
|
-
|
39
|
-
return {
|
40
|
-
loader: 'js',
|
41
|
-
contents: contents.join(';')
|
42
|
-
}
|
43
|
-
}
|
44
|
-
}
|
45
|
-
]
|
46
|
-
})
|
@@ -1,53 +0,0 @@
|
|
1
|
-
import setup from './setup_plugin.js'
|
2
|
-
|
3
|
-
export default setup('httpBundle', () => {
|
4
|
-
return [
|
5
|
-
{
|
6
|
-
type: 'onResolve',
|
7
|
-
filter: /^https?:\/\//,
|
8
|
-
callback(args) {
|
9
|
-
let queryParams, suffix
|
10
|
-
if (args.path.includes('?')) {
|
11
|
-
const [path, query] = args.path.split('?')
|
12
|
-
queryParams = new URLSearchParams(query)
|
13
|
-
suffix = `?${query}`
|
14
|
-
args.path = path
|
15
|
-
}
|
16
|
-
|
17
|
-
if (queryParams?.has('bundle')) {
|
18
|
-
return { path: args.path, namespace: 'httpBundle', suffix }
|
19
|
-
} else {
|
20
|
-
return { external: true }
|
21
|
-
}
|
22
|
-
}
|
23
|
-
},
|
24
|
-
|
25
|
-
// Intercept all import paths inside downloaded files and resolve them against the original URL.
|
26
|
-
{
|
27
|
-
type: 'onResolve',
|
28
|
-
filter: /.*/,
|
29
|
-
namespace: 'httpBundle',
|
30
|
-
callback(args) {
|
31
|
-
return {
|
32
|
-
path: new URL(args.path, args.importer).toString(),
|
33
|
-
namespace: 'httpBundle'
|
34
|
-
}
|
35
|
-
}
|
36
|
-
},
|
37
|
-
|
38
|
-
// Download and return the content.
|
39
|
-
//
|
40
|
-
// TODO: cache this!
|
41
|
-
{
|
42
|
-
type: 'onLoad',
|
43
|
-
filter: /.*/,
|
44
|
-
namespace: 'httpBundle',
|
45
|
-
async callback(args) {
|
46
|
-
const textResponse = await fetch(args.path)
|
47
|
-
const contents = await textResponse.text()
|
48
|
-
|
49
|
-
return { contents }
|
50
|
-
}
|
51
|
-
}
|
52
|
-
]
|
53
|
-
})
|
@@ -1,59 +0,0 @@
|
|
1
|
-
import { join } from 'std/path/mod.ts'
|
2
|
-
import { parseFromString } from 'import-maps/resolve'
|
3
|
-
|
4
|
-
const baseURL = new URL('file://')
|
5
|
-
|
6
|
-
class ImportMapError extends Error {
|
7
|
-
constructor(fileName, ...params) {
|
8
|
-
super(...params)
|
9
|
-
|
10
|
-
if (Error.captureStackTrace) {
|
11
|
-
Error.captureStackTrace(this, ImportMapError)
|
12
|
-
}
|
13
|
-
|
14
|
-
this.name = 'ImportMapError'
|
15
|
-
this.file = fileName
|
16
|
-
}
|
17
|
-
}
|
18
|
-
|
19
|
-
export function readImportMap(fileName, rootDir) {
|
20
|
-
let importMap
|
21
|
-
|
22
|
-
if (fileName) {
|
23
|
-
importMap = readFile(fileName, rootDir, true)
|
24
|
-
} else {
|
25
|
-
fileName = ['config/import_map.json', 'config/import_map.js'].find(f => {
|
26
|
-
const result = readFile(f, rootDir)
|
27
|
-
if (result) {
|
28
|
-
importMap = result
|
29
|
-
return true
|
30
|
-
}
|
31
|
-
})
|
32
|
-
}
|
33
|
-
|
34
|
-
return importMap
|
35
|
-
}
|
36
|
-
|
37
|
-
function readFile(file, rootDir, required = false) {
|
38
|
-
let contents = null
|
39
|
-
|
40
|
-
try {
|
41
|
-
contents = Deno.readTextFileSync(join(rootDir, file))
|
42
|
-
} catch (error) {
|
43
|
-
if (required) {
|
44
|
-
throw new ImportMapError(file, error.message, { cause: error })
|
45
|
-
}
|
46
|
-
}
|
47
|
-
|
48
|
-
if (contents === null) return null
|
49
|
-
|
50
|
-
try {
|
51
|
-
if (file.endsWith('.js')) {
|
52
|
-
contents = JSON.stringify(eval(contents)(Deno.env.get('RAILS_ENV')))
|
53
|
-
}
|
54
|
-
|
55
|
-
return parseFromString(contents, baseURL)
|
56
|
-
} catch (error) {
|
57
|
-
throw new ImportMapError(file, error.message, { cause: error })
|
58
|
-
}
|
59
|
-
}
|
@@ -1,205 +0,0 @@
|
|
1
|
-
import { join, resolve } from 'std/path/mod.ts'
|
2
|
-
import { resolve as resolveFromImportMap } from 'import-maps/resolve'
|
3
|
-
import { cache } from 'cache'
|
4
|
-
|
5
|
-
import setup from './setup_plugin.js'
|
6
|
-
|
7
|
-
const importKinds = ['import-statement', 'dynamic-import', 'require-call', 'import-rule']
|
8
|
-
|
9
|
-
export default setup('resolve', (build, options) => {
|
10
|
-
const { runtimeDir, importMap } = options
|
11
|
-
const cwd = build.initialOptions.absWorkingDir
|
12
|
-
const runtimeCwdAlias = `${cwd}/proscenium-runtime`
|
13
|
-
let bundled = false
|
14
|
-
|
15
|
-
const env = Deno.env.get('RAILS_ENV')
|
16
|
-
const isProd = env === 'production'
|
17
|
-
|
18
|
-
return [
|
19
|
-
{
|
20
|
-
// Filters for imports starting with `url:http://` or `url:https://`; returning the path
|
21
|
-
// without the `url:` prefix, and a namespace of 'url`
|
22
|
-
type: 'onResolve',
|
23
|
-
filter: /^url:https?:\/\//,
|
24
|
-
callback(args) {
|
25
|
-
return {
|
26
|
-
path: args.path.slice(4),
|
27
|
-
namespace: 'url'
|
28
|
-
}
|
29
|
-
}
|
30
|
-
},
|
31
|
-
|
32
|
-
{
|
33
|
-
type: 'onResolve',
|
34
|
-
filter: /.*/,
|
35
|
-
namespace: 'url',
|
36
|
-
callback(args) {
|
37
|
-
if (!isBareModule(args.path)) {
|
38
|
-
return {
|
39
|
-
path: new URL(args.path, args.importer).toString(),
|
40
|
-
namespace: 'url'
|
41
|
-
}
|
42
|
-
}
|
43
|
-
}
|
44
|
-
},
|
45
|
-
|
46
|
-
{
|
47
|
-
type: 'onLoad',
|
48
|
-
filter: /.*/,
|
49
|
-
namespace: 'url',
|
50
|
-
async callback(args) {
|
51
|
-
const file = await cache(args.path)
|
52
|
-
const contents = await Deno.readTextFile(file.path)
|
53
|
-
|
54
|
-
return { contents }
|
55
|
-
}
|
56
|
-
},
|
57
|
-
|
58
|
-
{
|
59
|
-
type: 'onResolve',
|
60
|
-
filter: /.*/,
|
61
|
-
async callback(args) {
|
62
|
-
if (args.path.includes('?')) {
|
63
|
-
const [path, query] = args.path.split('?')
|
64
|
-
args.path = path
|
65
|
-
args.suffix = `?${query}`
|
66
|
-
args.queryParams = new URLSearchParams(query)
|
67
|
-
} else if (options.cacheQueryString && options.cacheQueryString !== '') {
|
68
|
-
args.suffix = `?${options.cacheQueryString}`
|
69
|
-
}
|
70
|
-
|
71
|
-
// Mark remote modules as external. If not css, then the path is prefixed with "url:", which
|
72
|
-
// is then handled by the Url Middleware.
|
73
|
-
if (
|
74
|
-
!args.importer.endsWith('.css') &&
|
75
|
-
(args.path.startsWith('http://') || args.path.startsWith('https://'))
|
76
|
-
) {
|
77
|
-
return { path: `/url:${encodeURIComponent(args.path)}`, external: true }
|
78
|
-
}
|
79
|
-
|
80
|
-
// Rewrite the path to the actual runtime directory.
|
81
|
-
if (args.path.startsWith(runtimeCwdAlias)) {
|
82
|
-
return { path: join(runtimeDir, args.path.slice(runtimeCwdAlias.length)) }
|
83
|
-
}
|
84
|
-
|
85
|
-
// Everything else is unbundled.
|
86
|
-
if (importKinds.includes(args.kind)) {
|
87
|
-
return await unbundleImport(args)
|
88
|
-
}
|
89
|
-
}
|
90
|
-
}
|
91
|
-
]
|
92
|
-
|
93
|
-
// Resolve the given `params.path` to a path relative to the Rails root.
|
94
|
-
//
|
95
|
-
// Examples:
|
96
|
-
// 'react' -> '/.../node_modules/react/index.js'
|
97
|
-
// './my_module' -> '/.../app/my_module.js'
|
98
|
-
// '/app/my_module' -> '/.../app/my_module.js'
|
99
|
-
async function unbundleImport(params) {
|
100
|
-
const result = { path: params.path, suffix: params.suffix }
|
101
|
-
|
102
|
-
if (importMap) {
|
103
|
-
let baseURL
|
104
|
-
if (params.importer.startsWith('https://') || params.importer.startsWith('http://')) {
|
105
|
-
baseURL = new URL(params.importer)
|
106
|
-
} else {
|
107
|
-
baseURL = new URL(params.importer.slice(cwd.length), 'file://')
|
108
|
-
}
|
109
|
-
|
110
|
-
const { matched, resolvedImport } = resolveFromImportMap(params.path, importMap, baseURL)
|
111
|
-
|
112
|
-
if (matched) {
|
113
|
-
if (resolvedImport.protocol === 'file:') {
|
114
|
-
params.path = resolvedImport.pathname
|
115
|
-
} else {
|
116
|
-
if (params.importer.endsWith('.css')) {
|
117
|
-
return { path: resolvedImport.href, external: true }
|
118
|
-
}
|
119
|
-
|
120
|
-
return { path: `/url:${encodeURIComponent(resolvedImport.href)}`, external: true }
|
121
|
-
}
|
122
|
-
}
|
123
|
-
}
|
124
|
-
|
125
|
-
// Absolute path - append to current working dir.
|
126
|
-
if (params.path.startsWith('/')) {
|
127
|
-
result.path = resolve(cwd, params.path.slice(1))
|
128
|
-
}
|
129
|
-
|
130
|
-
const resOptions = {
|
131
|
-
// If path is a bare module (node_modules), and resolveDir is the Proscenium runtime dir, or
|
132
|
-
// is the current working dir, then use `cwd` as the `resolveDir`, otherwise pass it through
|
133
|
-
// as is. This ensures that nested node_modules are resolved correctly.
|
134
|
-
resolveDir:
|
135
|
-
isBareModule(result.path) &&
|
136
|
-
(!params.resolveDir.startsWith(cwd) || params.resolveDir.startsWith(runtimeDir))
|
137
|
-
? cwd
|
138
|
-
: params.resolveDir,
|
139
|
-
kind: params.kind,
|
140
|
-
pluginData: {
|
141
|
-
// We use this property later on, as we should ignore this resolution call.
|
142
|
-
isResolvingPath: true
|
143
|
-
}
|
144
|
-
}
|
145
|
-
|
146
|
-
// Resolve the path using esbuild's internal resolution. This allows us to import node packages
|
147
|
-
// and extension-less paths without custom code, as esbuild with resolve them for us.
|
148
|
-
const resolveResult = await build.resolve(result.path, resOptions)
|
149
|
-
|
150
|
-
// Simple return the resolved result if we have an error. Usually happens when module is not
|
151
|
-
// found.
|
152
|
-
if (resolveResult.errors.length > 0) return resolveResult
|
153
|
-
|
154
|
-
// If 'bundle-all' queryParam is defined, return the resolveResult.
|
155
|
-
if (bundled || params.queryParams?.has('bundle-all')) {
|
156
|
-
bundled = true
|
157
|
-
return { ...resolveResult, suffix: '?bundle-all' }
|
158
|
-
}
|
159
|
-
|
160
|
-
// If 'bundle' queryParam is defined, return the resolveResult.
|
161
|
-
if (params.queryParams?.has('bundle')) {
|
162
|
-
return { ...resolveResult, suffix: '?bundle' }
|
163
|
-
}
|
164
|
-
|
165
|
-
if (resolveResult.path.startsWith(runtimeDir)) {
|
166
|
-
result.path = '/proscenium-runtime' + resolveResult.path.slice(runtimeDir.length)
|
167
|
-
} else if (!resolveResult.path.startsWith(cwd) && !isProd) {
|
168
|
-
// Resolved path is not in the current working directory. It could be linked to a file outside
|
169
|
-
// the CWD, or it's just invalid. If not in production, return as an outsideRoot namespaced,
|
170
|
-
// and externally suffixed path. This lets the Rails Proscenium::Middleware::OutsideRoot
|
171
|
-
// handle the import.
|
172
|
-
return {
|
173
|
-
...resolveResult,
|
174
|
-
namespace: 'outsideRoot',
|
175
|
-
path: `${resolveResult.path}?outsideRoot`,
|
176
|
-
external: true
|
177
|
-
}
|
178
|
-
} else {
|
179
|
-
result.path = resolveResult.path.slice(cwd.length)
|
180
|
-
}
|
181
|
-
|
182
|
-
result.sideEffects = resolveResult.sideEffects
|
183
|
-
|
184
|
-
if (
|
185
|
-
params.path.endsWith('.css') &&
|
186
|
-
params.kind === 'import-statement' &&
|
187
|
-
/\.jsx?$/.test(params.importer)
|
188
|
-
) {
|
189
|
-
// We're importing a CSS file from JS(X).
|
190
|
-
return { ...resolveResult, pluginData: { importedFromJs: true } }
|
191
|
-
} else {
|
192
|
-
result.external = true
|
193
|
-
}
|
194
|
-
|
195
|
-
if (result.suffix && result.suffix !== '') {
|
196
|
-
result.path = `${result.path}${result.suffix}`
|
197
|
-
}
|
198
|
-
|
199
|
-
return result
|
200
|
-
}
|
201
|
-
})
|
202
|
-
|
203
|
-
function isBareModule(mod) {
|
204
|
-
return !mod.startsWith('/') && !mod.startsWith('.')
|
205
|
-
}
|
@@ -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
|
-
})
|