bun_bun_bundle 0.9.0 → 0.10.0
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 +25 -4
- data/exe/bun_bun_bundle +11 -5
- data/lib/bun/bake.js +1 -5
- data/lib/bun/bun_bundle.js +52 -11
- data/lib/bun/plugins/jsGlobs.js +36 -14
- data/lib/bun_bun_bundle/reload_tag.rb +15 -2
- data/lib/bun_bun_bundle/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 29e412dc1eeee94ba33c0f47186a649d6a8843b2a4edaf01cf7b72e7f66b29c2
|
|
4
|
+
data.tar.gz: 3744a8ccad103452e0099c6cb8e5bae65ed7a8c4eeb820cad2d52e8accb9384f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9d9e25a4d96f7a17e5231fdb211e01a231114dc6a3cec1c4c29373ed153896943abb13f5b518c954259d39ffd5d6985058323fa95d9125c1baa8bd4fb8c309e2
|
|
7
|
+
data.tar.gz: 16530cfc8cbbf16e2f56874b9697fcb0b41aa3aa83266116672f516b9778768b0836886a9456dd24c0dae3b1653e6059290b74a7150e5673400c4847653d9afc
|
data/README.md
CHANGED
|
@@ -174,13 +174,30 @@ bun_bun_bundle dev
|
|
|
174
174
|
# Build assets
|
|
175
175
|
bun_bun_bundle build
|
|
176
176
|
|
|
177
|
-
# Build with fingerprinting and minification
|
|
177
|
+
# Build with fingerprinting and minification (shortcut)
|
|
178
178
|
bun_bun_bundle build --prod
|
|
179
179
|
|
|
180
|
+
# Fingerprint without minifying (e.g. for staging diagnostics)
|
|
181
|
+
bun_bun_bundle build --fingerprint
|
|
182
|
+
|
|
183
|
+
# Strip sourcemaps from a prod build
|
|
184
|
+
bun_bun_bundle build --prod --sourcemap=none
|
|
185
|
+
|
|
180
186
|
# Development with verbose WebSocket logging
|
|
181
187
|
bun_bun_bundle dev --debug
|
|
182
188
|
```
|
|
183
189
|
|
|
190
|
+
### Flags
|
|
191
|
+
|
|
192
|
+
- `--prod`: shortcut for `--fingerprint --minify`
|
|
193
|
+
- `--fingerprint`: hash asset filenames for cache busting
|
|
194
|
+
- `--minify`: minify JS and CSS output
|
|
195
|
+
- `--sourcemap[=KIND]`: `inline`, `linked`, `external`, or `none`. Defaults
|
|
196
|
+
to `inline` in `dev` and `linked` for builds, so production stack traces
|
|
197
|
+
and browser devtools stay debuggable. Pass `--sourcemap=none` when you
|
|
198
|
+
explicitly do not want maps shipped.
|
|
199
|
+
- `--debug`: verbose WebSocket logging
|
|
200
|
+
|
|
184
201
|
> [!NOTE]
|
|
185
202
|
> When running from a Procfile (e.g. with Overmind or Foreman), use
|
|
186
203
|
> `bundle exec bun_bun_bundle` to ensure the correct gem version is loaded.
|
|
@@ -320,7 +337,11 @@ The context object has the following properties:
|
|
|
320
337
|
- `root`: absolute path to the project root
|
|
321
338
|
- `config`: the resolved `bun.json` configuration object
|
|
322
339
|
- `dev`: `true` when running in development mode
|
|
323
|
-
- `prod`: `true` when
|
|
340
|
+
- `prod`: `true` when `--prod` was passed (shortcut flag)
|
|
341
|
+
- `fingerprint`: `true` when asset filenames will be content-hashed
|
|
342
|
+
- `minify`: `true` when output will be minified (use this to strip
|
|
343
|
+
comments, banners, or dev-only branches in your plugin)
|
|
344
|
+
- `sourcemap`: the sourcemap kind being produced (or `null` for default)
|
|
324
345
|
- `manifest`: the current asset manifest object
|
|
325
346
|
|
|
326
347
|
#### Simple transform plugins
|
|
@@ -337,9 +358,9 @@ transform receives the output of the previous one.
|
|
|
337
358
|
```javascript
|
|
338
359
|
// config/bun/banner.js
|
|
339
360
|
|
|
340
|
-
export default function banner({
|
|
361
|
+
export default function banner({minify}) {
|
|
341
362
|
return (content, args) => {
|
|
342
|
-
const stamp =
|
|
363
|
+
const stamp = minify ? '' : ` (dev ${args.path})`
|
|
343
364
|
return `/* My App${stamp} */\n${content}`
|
|
344
365
|
}
|
|
345
366
|
}
|
data/exe/bun_bun_bundle
CHANGED
|
@@ -22,13 +22,19 @@ else
|
|
|
22
22
|
build Build assets
|
|
23
23
|
|
|
24
24
|
Flags:
|
|
25
|
-
--prod
|
|
26
|
-
--
|
|
25
|
+
--prod Shortcut for --fingerprint --minify
|
|
26
|
+
--fingerprint Hash asset filenames for cache busting
|
|
27
|
+
--minify Minify JS and CSS output
|
|
28
|
+
--sourcemap[=KIND] Sourcemap kind: inline, linked, external, none
|
|
29
|
+
(dev defaults to inline, builds default to linked)
|
|
30
|
+
--debug Enable verbose WebSocket logging
|
|
27
31
|
|
|
28
32
|
Examples:
|
|
29
|
-
bun_bun_bundle dev
|
|
30
|
-
bun_bun_bundle build
|
|
31
|
-
bun_bun_bundle build --prod
|
|
33
|
+
bun_bun_bundle dev # live reload
|
|
34
|
+
bun_bun_bundle build # plain build
|
|
35
|
+
bun_bun_bundle build --prod # fingerprint + minify
|
|
36
|
+
bun_bun_bundle build --fingerprint # fingerprint only
|
|
37
|
+
bun_bun_bundle build --prod --sourcemap=none # strip sourcemaps
|
|
32
38
|
|
|
33
39
|
Configuration:
|
|
34
40
|
Place a config/bun.json in your project root to customize settings.
|
data/lib/bun/bake.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import BunBunBundle from "./bun_bundle.js";
|
|
2
2
|
|
|
3
|
-
BunBunBundle.flags(
|
|
4
|
-
debug: process.argv.includes("--debug"),
|
|
5
|
-
dev: process.argv.includes("--dev"),
|
|
6
|
-
prod: process.argv.includes("--prod"),
|
|
7
|
-
});
|
|
3
|
+
BunBunBundle.flags(process.argv);
|
|
8
4
|
|
|
9
5
|
await BunBunBundle.bake();
|
data/lib/bun/bun_bundle.js
CHANGED
|
@@ -21,14 +21,42 @@ export default {
|
|
|
21
21
|
debug: false,
|
|
22
22
|
dev: false,
|
|
23
23
|
prod: false,
|
|
24
|
+
fingerprint: false,
|
|
25
|
+
minify: false,
|
|
26
|
+
sourcemap: null,
|
|
24
27
|
wsClients: new Set(),
|
|
25
28
|
watchTimers: new Map(),
|
|
26
29
|
plugins: [],
|
|
27
30
|
|
|
28
|
-
flags(
|
|
31
|
+
flags(input) {
|
|
32
|
+
const {debug, dev, prod, fingerprint, minify, sourcemap} =
|
|
33
|
+
Array.isArray(input) ? this.parseArgv(input) : input
|
|
29
34
|
if (debug != null) this.debug = debug
|
|
30
35
|
if (dev != null) this.dev = dev
|
|
31
36
|
if (prod != null) this.prod = prod
|
|
37
|
+
if (fingerprint != null) this.fingerprint = fingerprint
|
|
38
|
+
else if (prod === true) this.fingerprint = true
|
|
39
|
+
if (minify != null) this.minify = minify
|
|
40
|
+
else if (prod === true) this.minify = true
|
|
41
|
+
if (sourcemap != null) this.sourcemap = sourcemap
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
SOURCEMAP_KINDS: ['inline', 'linked', 'external', 'none'],
|
|
45
|
+
|
|
46
|
+
parseArgv(argv) {
|
|
47
|
+
const opts = {}
|
|
48
|
+
if (argv.includes('--debug')) opts.debug = true
|
|
49
|
+
if (argv.includes('--dev')) opts.dev = true
|
|
50
|
+
if (argv.includes('--prod')) opts.prod = true
|
|
51
|
+
if (argv.includes('--fingerprint')) opts.fingerprint = true
|
|
52
|
+
if (argv.includes('--minify')) opts.minify = true
|
|
53
|
+
const sm = argv.find(a => a === '--sourcemap' || a.startsWith('--sourcemap='))
|
|
54
|
+
if (sm) {
|
|
55
|
+
const value = sm.includes('=') ? sm.split('=')[1] : 'linked'
|
|
56
|
+
if (this.SOURCEMAP_KINDS.includes(value)) opts.sourcemap = value
|
|
57
|
+
else console.warn(` ▸ Ignoring --sourcemap=${value} (valid: ${this.SOURCEMAP_KINDS.join(', ')})`)
|
|
58
|
+
}
|
|
59
|
+
return opts
|
|
32
60
|
},
|
|
33
61
|
|
|
34
62
|
deepMerge(target, source) {
|
|
@@ -69,6 +97,9 @@ export default {
|
|
|
69
97
|
config: this.config,
|
|
70
98
|
dev: this.dev,
|
|
71
99
|
prod: this.prod,
|
|
100
|
+
fingerprint: this.fingerprint,
|
|
101
|
+
minify: this.minify,
|
|
102
|
+
sourcemap: this.sourcemap,
|
|
72
103
|
manifest: this.manifest
|
|
73
104
|
})
|
|
74
105
|
},
|
|
@@ -79,8 +110,8 @@ export default {
|
|
|
79
110
|
return join(this.root, this.config.outDir)
|
|
80
111
|
},
|
|
81
112
|
|
|
82
|
-
|
|
83
|
-
if (!this.
|
|
113
|
+
fingerprintName(name, ext, content) {
|
|
114
|
+
if (!this.fingerprint) return `${name}${ext}`
|
|
84
115
|
|
|
85
116
|
const hash = Bun.hash(content).toString(16).slice(0, 8)
|
|
86
117
|
return `${name}-${hash}${ext}`
|
|
@@ -107,7 +138,7 @@ export default {
|
|
|
107
138
|
try {
|
|
108
139
|
result = await Bun.build({
|
|
109
140
|
entrypoints: [entryPath],
|
|
110
|
-
minify: this.
|
|
141
|
+
minify: this.minify,
|
|
111
142
|
plugins: this.plugins,
|
|
112
143
|
...options
|
|
113
144
|
})
|
|
@@ -124,16 +155,26 @@ export default {
|
|
|
124
155
|
continue
|
|
125
156
|
}
|
|
126
157
|
|
|
127
|
-
const
|
|
128
|
-
if (!
|
|
158
|
+
const mainOutput = result.outputs.find(o => o.path.endsWith(ext))
|
|
159
|
+
if (!mainOutput) {
|
|
129
160
|
console.error(` ▸ No ${type.toUpperCase()} output for ${entry}`)
|
|
130
161
|
continue
|
|
131
162
|
}
|
|
163
|
+
const mapOutput = result.outputs.find(o => o.kind === 'sourcemap')
|
|
164
|
+
|
|
165
|
+
let content = await mainOutput.text()
|
|
166
|
+
const fileName = this.fingerprintName(entryName, ext, content)
|
|
167
|
+
|
|
168
|
+
if (mapOutput) {
|
|
169
|
+
const mapFileName = `${fileName}.map`
|
|
170
|
+
content = content.replace(
|
|
171
|
+
/\/\/# sourceMappingURL=\S+/,
|
|
172
|
+
() => `//# sourceMappingURL=${mapFileName}`
|
|
173
|
+
)
|
|
174
|
+
await Bun.write(join(outDir, mapFileName), await mapOutput.text())
|
|
175
|
+
}
|
|
132
176
|
|
|
133
|
-
const content = await output.text()
|
|
134
|
-
const fileName = this.fingerprint(entryName, ext, content)
|
|
135
177
|
await Bun.write(join(outDir, fileName), content)
|
|
136
|
-
|
|
137
178
|
this.manifest[`${type}/${entryName}${ext}`] = `${type}/${fileName}`
|
|
138
179
|
}
|
|
139
180
|
},
|
|
@@ -142,7 +183,7 @@ export default {
|
|
|
142
183
|
await this.buildAssets('js', {
|
|
143
184
|
target: 'browser',
|
|
144
185
|
format: 'iife',
|
|
145
|
-
sourcemap: this.dev ? 'inline' : '
|
|
186
|
+
sourcemap: this.sourcemap || (this.dev ? 'inline' : 'linked')
|
|
146
187
|
})
|
|
147
188
|
},
|
|
148
189
|
|
|
@@ -166,7 +207,7 @@ export default {
|
|
|
166
207
|
|
|
167
208
|
const ext = extname(file)
|
|
168
209
|
const name = file.slice(0, -ext.length) || file
|
|
169
|
-
const fileName = this.
|
|
210
|
+
const fileName = this.fingerprintName(name, ext, new Uint8Array(content))
|
|
170
211
|
const destPath = join(destDir, fileName)
|
|
171
212
|
|
|
172
213
|
mkdirSync(dirname(destPath), {recursive: true})
|
data/lib/bun/plugins/jsGlobs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {dirname, extname} from 'path'
|
|
1
|
+
import {dirname, extname, isAbsolute, relative, join} from 'path'
|
|
2
2
|
import {Glob} from 'bun'
|
|
3
3
|
|
|
4
4
|
const REGEX = /import\s+(\w+)\s+from\s+['"]glob:([^'"]+)['"]/g
|
|
@@ -20,24 +20,46 @@ function excluded(file, matchers) {
|
|
|
20
20
|
|
|
21
21
|
function scanFiles(dir, pattern, excludes) {
|
|
22
22
|
const {clean, base} = splitBase(pattern)
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
.
|
|
23
|
+
const abs = isAbsolute(clean)
|
|
24
|
+
const cwd = abs ? base : dir
|
|
25
|
+
const globPart = abs ? clean.slice(base.length + 1) : clean
|
|
26
|
+
const matchers = excludes.map(e => {
|
|
27
|
+
const ex = e.replace(/^\.\//, '')
|
|
28
|
+
return new Glob(abs && isAbsolute(ex) ? ex.slice(base.length + 1) : ex)
|
|
29
|
+
})
|
|
30
|
+
const glob = new Glob(globPart)
|
|
31
|
+
const files = []
|
|
32
|
+
|
|
33
|
+
for (const file of glob.scanSync({cwd})) {
|
|
34
|
+
if (excluded(file, matchers)) continue
|
|
35
|
+
const absPath = join(cwd, file)
|
|
36
|
+
const rel = relative(dir, absPath)
|
|
37
|
+
files.push(rel)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return files.sort()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function keyBase(pattern) {
|
|
44
|
+
const {base} = splitBase(pattern)
|
|
45
|
+
if (!isAbsolute(base)) return base
|
|
46
|
+
const last = base.lastIndexOf('/')
|
|
47
|
+
return last > 0 ? base.slice(last + 1) : base
|
|
28
48
|
}
|
|
29
49
|
|
|
30
|
-
function buildImportMap(files, base) {
|
|
50
|
+
function buildImportMap(files, dir, base) {
|
|
31
51
|
const imports = []
|
|
32
52
|
const entries = []
|
|
33
53
|
|
|
34
54
|
for (const file of files) {
|
|
35
55
|
const ext = extname(file)
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
56
|
+
const key = file
|
|
57
|
+
.slice(0, -ext.length)
|
|
58
|
+
.replace(/^[./]+/, '')
|
|
59
|
+
.replace(new RegExp(`^.*${base}/`), '')
|
|
60
|
+
const safe = `_glob_${base}_${key}`.replace(/[^a-zA-Z0-9]/g, '_')
|
|
61
|
+
const rel = file.startsWith('.') ? file : `./${file}`
|
|
62
|
+
imports.push(`import ${safe} from '${rel}'`)
|
|
41
63
|
entries.push(` '${key}': ${safe}`)
|
|
42
64
|
}
|
|
43
65
|
|
|
@@ -48,13 +70,13 @@ export default function jsGlobs() {
|
|
|
48
70
|
return (content, args) => {
|
|
49
71
|
return content.replace(REGEX, (_, binding, raw) => {
|
|
50
72
|
const {pattern, excludes} = parseImport(raw)
|
|
51
|
-
const
|
|
73
|
+
const base = keyBase(pattern)
|
|
52
74
|
const dir = dirname(args.path)
|
|
53
75
|
const files = scanFiles(dir, pattern, excludes)
|
|
54
76
|
|
|
55
77
|
if (!files.length) return `const ${binding} = {}`
|
|
56
78
|
|
|
57
|
-
const {imports, entries} = buildImportMap(files, base)
|
|
79
|
+
const {imports, entries} = buildImportMap(files, dir, base)
|
|
58
80
|
|
|
59
81
|
return [
|
|
60
82
|
...imports,
|
|
@@ -33,6 +33,19 @@ module BunBunBundle
|
|
|
33
33
|
const ws = new WebSocket('#{config.dev_server.ws_url}')
|
|
34
34
|
let connected = false
|
|
35
35
|
|
|
36
|
+
const scrollKey = 'bun-scroll:' + location.pathname
|
|
37
|
+
addEventListener('load', () => {
|
|
38
|
+
const saved = sessionStorage.getItem(scrollKey)
|
|
39
|
+
if (saved !== null) {
|
|
40
|
+
sessionStorage.removeItem(scrollKey)
|
|
41
|
+
scrollTo(0, parseInt(saved, 10))
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
const reload = () => {
|
|
45
|
+
sessionStorage.setItem(scrollKey, String(scrollY))
|
|
46
|
+
location.reload()
|
|
47
|
+
}
|
|
48
|
+
|
|
36
49
|
ws.onmessage = (event) => {
|
|
37
50
|
const data = JSON.parse(event.data)
|
|
38
51
|
|
|
@@ -50,7 +63,7 @@ module BunBunBundle
|
|
|
50
63
|
console.error('\\u2716 Build error:', data.message)
|
|
51
64
|
} else {
|
|
52
65
|
console.log('\\u25b8 Reloading...')
|
|
53
|
-
|
|
66
|
+
reload()
|
|
54
67
|
}
|
|
55
68
|
}
|
|
56
69
|
|
|
@@ -59,7 +72,7 @@ module BunBunBundle
|
|
|
59
72
|
console.log('\\u25b8 Live reload connected')
|
|
60
73
|
}
|
|
61
74
|
ws.onclose = () => {
|
|
62
|
-
if (connected) setTimeout(
|
|
75
|
+
if (connected) setTimeout(reload, 2000)
|
|
63
76
|
}
|
|
64
77
|
})()
|
|
65
78
|
</script>
|