bun_bun_bundle 0.9.1 → 0.11.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 +82 -19
- data/lib/bun/plugins/aliases.js +7 -2
- 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: d45723ba4d7826f7a860af793c4acf6fbceda366e442f9b9858ec2c1f340e5ec
|
|
4
|
+
data.tar.gz: 13a119627c68cd7009975c40e0caa22f91adc35797b74f7604c35237960a69c8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7e7f845bfaff50c0c3a3b18e5dfcac5900929d9d2f261b3931a5bbac47775629d77a834c9e581a6c0dbea04004cbfd4d7a561a7d013524a55a67837e5b3cf42a
|
|
7
|
+
data.tar.gz: 3d17dbcfe26e03538d349bb2a8ba48ec5ecd52b203712ab0296ebaa4502485c7b4275e0a4cfd8764a1d8e6dd2cb56651430ed42ac05c621151d807439eb54e11
|
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,50 @@ 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} = Array.isArray(
|
|
33
|
+
input
|
|
34
|
+
)
|
|
35
|
+
? this.parseArgv(input)
|
|
36
|
+
: input
|
|
29
37
|
if (debug != null) this.debug = debug
|
|
30
38
|
if (dev != null) this.dev = dev
|
|
31
39
|
if (prod != null) this.prod = prod
|
|
40
|
+
if (fingerprint != null) this.fingerprint = fingerprint
|
|
41
|
+
else if (prod === true) this.fingerprint = true
|
|
42
|
+
if (minify != null) this.minify = minify
|
|
43
|
+
else if (prod === true) this.minify = true
|
|
44
|
+
if (sourcemap != null) this.sourcemap = sourcemap
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
SOURCEMAP_KINDS: ['inline', 'linked', 'external', 'none'],
|
|
48
|
+
|
|
49
|
+
parseArgv(argv) {
|
|
50
|
+
const opts = {}
|
|
51
|
+
if (argv.includes('--debug')) opts.debug = true
|
|
52
|
+
if (argv.includes('--dev')) opts.dev = true
|
|
53
|
+
if (argv.includes('--prod')) opts.prod = true
|
|
54
|
+
if (argv.includes('--fingerprint')) opts.fingerprint = true
|
|
55
|
+
if (argv.includes('--minify')) opts.minify = true
|
|
56
|
+
const sm = argv.find(
|
|
57
|
+
a => a === '--sourcemap' || a.startsWith('--sourcemap=')
|
|
58
|
+
)
|
|
59
|
+
if (sm) {
|
|
60
|
+
const value = sm.includes('=') ? sm.split('=')[1] : 'linked'
|
|
61
|
+
if (this.SOURCEMAP_KINDS.includes(value)) opts.sourcemap = value
|
|
62
|
+
else
|
|
63
|
+
console.warn(
|
|
64
|
+
` ▸ Ignoring --sourcemap=${value} (valid: ${this.SOURCEMAP_KINDS.join(', ')})`
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
return opts
|
|
32
68
|
},
|
|
33
69
|
|
|
34
70
|
deepMerge(target, source) {
|
|
@@ -43,7 +79,10 @@ export default {
|
|
|
43
79
|
|
|
44
80
|
loadConfig() {
|
|
45
81
|
const defaults = {
|
|
46
|
-
entryPoints: {
|
|
82
|
+
entryPoints: {
|
|
83
|
+
js: ['app/assets/js/app.js'],
|
|
84
|
+
css: ['app/assets/css/app.css']
|
|
85
|
+
},
|
|
47
86
|
plugins: {css: ['aliases', 'cssGlobs'], js: ['aliases', 'jsGlobs']},
|
|
48
87
|
watchDirs: ['app/assets'],
|
|
49
88
|
staticDirs: ['app/assets/images', 'app/assets/fonts'],
|
|
@@ -69,6 +108,9 @@ export default {
|
|
|
69
108
|
config: this.config,
|
|
70
109
|
dev: this.dev,
|
|
71
110
|
prod: this.prod,
|
|
111
|
+
fingerprint: this.fingerprint,
|
|
112
|
+
minify: this.minify,
|
|
113
|
+
sourcemap: this.sourcemap,
|
|
72
114
|
manifest: this.manifest
|
|
73
115
|
})
|
|
74
116
|
},
|
|
@@ -79,8 +121,8 @@ export default {
|
|
|
79
121
|
return join(this.root, this.config.outDir)
|
|
80
122
|
},
|
|
81
123
|
|
|
82
|
-
|
|
83
|
-
if (!this.
|
|
124
|
+
fingerprintName(name, ext, content) {
|
|
125
|
+
if (!this.fingerprint) return `${name}${ext}`
|
|
84
126
|
|
|
85
127
|
const hash = Bun.hash(content).toString(16).slice(0, 8)
|
|
86
128
|
return `${name}-${hash}${ext}`
|
|
@@ -107,7 +149,7 @@ export default {
|
|
|
107
149
|
try {
|
|
108
150
|
result = await Bun.build({
|
|
109
151
|
entrypoints: [entryPath],
|
|
110
|
-
minify: this.
|
|
152
|
+
minify: this.minify,
|
|
111
153
|
plugins: this.plugins,
|
|
112
154
|
...options
|
|
113
155
|
})
|
|
@@ -124,16 +166,26 @@ export default {
|
|
|
124
166
|
continue
|
|
125
167
|
}
|
|
126
168
|
|
|
127
|
-
const
|
|
128
|
-
if (!
|
|
169
|
+
const mainOutput = result.outputs.find(o => o.path.endsWith(ext))
|
|
170
|
+
if (!mainOutput) {
|
|
129
171
|
console.error(` ▸ No ${type.toUpperCase()} output for ${entry}`)
|
|
130
172
|
continue
|
|
131
173
|
}
|
|
174
|
+
const mapOutput = result.outputs.find(o => o.kind === 'sourcemap')
|
|
175
|
+
|
|
176
|
+
let content = await mainOutput.text()
|
|
177
|
+
const fileName = this.fingerprintName(entryName, ext, content)
|
|
178
|
+
|
|
179
|
+
if (mapOutput) {
|
|
180
|
+
const mapFileName = `${fileName}.map`
|
|
181
|
+
content = content.replace(
|
|
182
|
+
/\/\/# sourceMappingURL=\S+/,
|
|
183
|
+
() => `//# sourceMappingURL=${mapFileName}`
|
|
184
|
+
)
|
|
185
|
+
await Bun.write(join(outDir, mapFileName), await mapOutput.text())
|
|
186
|
+
}
|
|
132
187
|
|
|
133
|
-
const content = await output.text()
|
|
134
|
-
const fileName = this.fingerprint(entryName, ext, content)
|
|
135
188
|
await Bun.write(join(outDir, fileName), content)
|
|
136
|
-
|
|
137
189
|
this.manifest[`${type}/${entryName}${ext}`] = `${type}/${fileName}`
|
|
138
190
|
}
|
|
139
191
|
},
|
|
@@ -142,7 +194,7 @@ export default {
|
|
|
142
194
|
await this.buildAssets('js', {
|
|
143
195
|
target: 'browser',
|
|
144
196
|
format: 'iife',
|
|
145
|
-
sourcemap: this.dev ? 'inline' : '
|
|
197
|
+
sourcemap: this.sourcemap || (this.dev ? 'inline' : 'linked')
|
|
146
198
|
})
|
|
147
199
|
},
|
|
148
200
|
|
|
@@ -166,7 +218,11 @@ export default {
|
|
|
166
218
|
|
|
167
219
|
const ext = extname(file)
|
|
168
220
|
const name = file.slice(0, -ext.length) || file
|
|
169
|
-
const fileName = this.
|
|
221
|
+
const fileName = this.fingerprintName(
|
|
222
|
+
name,
|
|
223
|
+
ext,
|
|
224
|
+
new Uint8Array(content)
|
|
225
|
+
)
|
|
170
226
|
const destPath = join(destDir, fileName)
|
|
171
227
|
|
|
172
228
|
mkdirSync(dirname(destPath), {recursive: true})
|
|
@@ -223,6 +279,10 @@ export default {
|
|
|
223
279
|
},
|
|
224
280
|
|
|
225
281
|
async watch() {
|
|
282
|
+
const extras = this.config.watchExtensions || {}
|
|
283
|
+
const cssExts = ['css', ...(extras.css || [])]
|
|
284
|
+
const jsExts = ['js', 'ts', 'jsx', 'tsx', ...(extras.js || [])]
|
|
285
|
+
|
|
226
286
|
const handler = (event, filename) => {
|
|
227
287
|
if (!filename) return
|
|
228
288
|
|
|
@@ -239,16 +299,18 @@ export default {
|
|
|
239
299
|
|
|
240
300
|
// Debounce: multiple events for the same file (e.g. actual save + backup)
|
|
241
301
|
if (this.watchTimers.has(normalizedFilename)) return
|
|
242
|
-
this.watchTimers.set(
|
|
243
|
-
|
|
244
|
-
|
|
302
|
+
this.watchTimers.set(
|
|
303
|
+
normalizedFilename,
|
|
304
|
+
setTimeout(() => {
|
|
305
|
+
this.watchTimers.delete(normalizedFilename)
|
|
306
|
+
}, 100)
|
|
307
|
+
)
|
|
245
308
|
|
|
246
309
|
console.log(` ▸ ${normalizedFilename} changed`)
|
|
247
|
-
|
|
248
310
|
;(async () => {
|
|
249
311
|
try {
|
|
250
|
-
if (ext
|
|
251
|
-
else if (
|
|
312
|
+
if (cssExts.includes(ext)) await this.buildCSS()
|
|
313
|
+
else if (jsExts.includes(ext)) await this.buildJS()
|
|
252
314
|
else if (base.includes('.')) await this.copyStaticAssets()
|
|
253
315
|
|
|
254
316
|
await this.writeManifest()
|
|
@@ -295,7 +357,8 @@ export default {
|
|
|
295
357
|
},
|
|
296
358
|
close(ws) {
|
|
297
359
|
wsClients.delete(ws)
|
|
298
|
-
if (debug)
|
|
360
|
+
if (debug)
|
|
361
|
+
console.log(` ▸ Client disconnected (${wsClients.size})\n\n`)
|
|
299
362
|
},
|
|
300
363
|
message() {}
|
|
301
364
|
}
|
data/lib/bun/plugins/aliases.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
const
|
|
1
|
+
const CSS_REGEX = /((?:url\(\s*|@import\s+)['"]?(?:glob:)?)\$\//g
|
|
2
|
+
const JS_REGEX =
|
|
3
|
+
/((?:from\s+|require\s*\(\s*|import\s*\(\s*)['"](?:glob:)?)\$\//g
|
|
2
4
|
|
|
3
5
|
// Resolves `$/` root aliases in CSS url() references and JS/CSS imports.
|
|
4
6
|
// e.g. url('$/app/assets/images/foo.png') → url('/absolute/root/app/assets/images/foo.png')
|
|
5
7
|
// import x from '$/lib/utils.js' → import x from '/absolute/root/lib/utils.js'
|
|
6
8
|
// @import '$/app/assets/css/reset.css' → @import '/absolute/root/app/assets/css/reset.css'
|
|
7
9
|
export default function aliases({root}) {
|
|
8
|
-
return content =>
|
|
10
|
+
return (content, args) => {
|
|
11
|
+
const regex = args.path.endsWith('.css') ? CSS_REGEX : JS_REGEX
|
|
12
|
+
return content.replace(regex, `$1${root}/`)
|
|
13
|
+
}
|
|
9
14
|
}
|
|
@@ -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>
|