bun_bun_bundle 0.1.2 → 0.3.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 +157 -37
- data/lib/bun/bun_bundle.js +1 -1
- data/lib/bun/plugins/aliases.js +9 -0
- data/lib/bun/plugins/index.js +2 -2
- data/lib/bun_bun_bundle/hanami.rb +3 -2
- data/lib/bun_bun_bundle/version.rb +1 -1
- data/lib/bun_bun_bundle.rb +16 -1
- metadata +2 -2
- data/lib/bun/plugins/cssAliases.js +0 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 11c05e743bc0de032fa96e01847eab10641fecb9cf59151b62f14fdfb4b8384f
|
|
4
|
+
data.tar.gz: 3d6f0044f6c3afcbb38dcc847ac2250eec8616c5a09bf51c7022468fff86e766
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9063a677cbb30db62e3162e7c0b753dd1f34b3b36ecc1c076efeba45ad3d3d09b7dac00ca575c6159cd0ea9ea13066963a053a7d2928501b9ebc879e4eecb52e
|
|
7
|
+
data.tar.gz: 8e9b0d27cb3f11dadfd88ac64deb1b52c54f20b63bb738d55dbb196d40b83049a1cb1285eb68ee379cc60cffbcb9f516d15864c74b9c2a05497c4fa1713f044c
|
data/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Bun, Bun, Bundle
|
|
2
2
|
|
|
3
3
|
A self-contained asset bundler for Ruby powered by [Bun](https://bun.sh). No
|
|
4
|
-
development dependencies, no complex configuration.
|
|
5
|
-
hot-reloading, fingerprinting, live reload, and a flexible plugin system.
|
|
6
|
-
with Rails, Hanami, or any Rack app.
|
|
4
|
+
development dependencies, no complex configuration. Lightning fast builds with
|
|
5
|
+
CSS hot-reloading, fingerprinting, live reload, and a flexible plugin system.
|
|
6
|
+
Works with Rails, Hanami, or any Rack app.
|
|
7
7
|
|
|
8
8
|
## Why use BunBunBundle?
|
|
9
9
|
|
|
@@ -28,18 +28,18 @@ browsers always fetch the right version.
|
|
|
28
28
|
|
|
29
29
|
Development and production builds go through the exact same pipeline. The only
|
|
30
30
|
differences are fingerprinting and minification being enabled in production,
|
|
31
|
-
but nothing is holding you back
|
|
31
|
+
but nothing is holding you back from enabling them in development as well.
|
|
32
32
|
|
|
33
33
|
### Extensible plugin system
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
imports. Plugins are simple, plain JS files, so you can create your
|
|
37
|
-
transformers, and raw Bun plugins are supported as well.
|
|
35
|
+
BunBunBundle comes with built-in plugins for root aliases, CSS glob imports,
|
|
36
|
+
and JS glob imports. Plugins are simple, plain JS files, so you can create your
|
|
37
|
+
own JS/CSS transformers, and raw Bun plugins are supported as well.
|
|
38
38
|
|
|
39
39
|
### Just one dependency: Bun
|
|
40
40
|
|
|
41
|
-
The bundler ships with the gem. Bun is the only external requirement, so
|
|
42
|
-
are
|
|
41
|
+
The bundler ships with the gem. Bun is the only external requirement, so other
|
|
42
|
+
than that, there are no dev dependencies.
|
|
43
43
|
|
|
44
44
|
## Installation
|
|
45
45
|
|
|
@@ -59,6 +59,18 @@ are zero dev dependencies.
|
|
|
59
59
|
|
|
60
60
|
## Usage with Rails
|
|
61
61
|
|
|
62
|
+
BunBunBundle completely bypasses the Rails asset pipeline. If you're adding it
|
|
63
|
+
to an existing app, you can remove Sprockets/Propshaft:
|
|
64
|
+
|
|
65
|
+
- Remove `gem 'sprockets-rails'` or `gem 'propshaft'` from your `Gemfile`
|
|
66
|
+
- Delete `config/initializers/assets.rb` if present
|
|
67
|
+
|
|
68
|
+
For new apps, generate them without the asset pipeline:
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
rails new myapp --minimal --skip-asset-pipeline --skip-javascript
|
|
72
|
+
```
|
|
73
|
+
|
|
62
74
|
The gem auto-configures itself through a Railtie. All helpers are available in
|
|
63
75
|
your views immediately:
|
|
64
76
|
|
|
@@ -81,7 +93,13 @@ stale asset caching.
|
|
|
81
93
|
|
|
82
94
|
## Usage with Hanami
|
|
83
95
|
|
|
84
|
-
|
|
96
|
+
Hanami ships with its own esbuild-based asset pipeline. Since BunBunBundle
|
|
97
|
+
replaces it entirely, you can clean up the default setup:
|
|
98
|
+
|
|
99
|
+
- Remove `gem 'hanami-assets'` from your `Gemfile`
|
|
100
|
+
- Delete `config/assets.js`, `package.json`, and `node_modules/`
|
|
101
|
+
|
|
102
|
+
1. Set up the Hanami integration:
|
|
85
103
|
|
|
86
104
|
```ruby
|
|
87
105
|
# config/app.rb
|
|
@@ -90,12 +108,15 @@ stale asset caching.
|
|
|
90
108
|
|
|
91
109
|
module MyApp
|
|
92
110
|
class App < Hanami::App
|
|
93
|
-
BunBunBundle.setup(root: root)
|
|
94
|
-
config.middleware.use BunBunBundle::DevCacheMiddleware if Hanami.env?(:development)
|
|
111
|
+
BunBunBundle.setup(root: root, hanami: config)
|
|
95
112
|
end
|
|
96
113
|
end
|
|
97
114
|
```
|
|
98
115
|
|
|
116
|
+
This loads the manifest, and in development automatically registers the
|
|
117
|
+
cache-busting middleware and configures the CSP to allow the live reload
|
|
118
|
+
script and WebSocket connection.
|
|
119
|
+
|
|
99
120
|
2. Include the helpers in your views:
|
|
100
121
|
|
|
101
122
|
```ruby
|
|
@@ -111,7 +132,7 @@ stale asset caching.
|
|
|
111
132
|
end
|
|
112
133
|
```
|
|
113
134
|
|
|
114
|
-
|
|
135
|
+
3. Use them in your templates:
|
|
115
136
|
|
|
116
137
|
```erb
|
|
117
138
|
<%= bun_css_tag('css/app.css') %>
|
|
@@ -132,7 +153,8 @@ BunBunBundle.asset_host = 'https://cdn.example.com'
|
|
|
132
153
|
|
|
133
154
|
## Helpers
|
|
134
155
|
|
|
135
|
-
All helpers are prefixed with `bun_` to avoid conflicts with framework
|
|
156
|
+
All helpers are prefixed with `bun_` to avoid conflicts with existing framework
|
|
157
|
+
helpers:
|
|
136
158
|
|
|
137
159
|
| Helper | Description |
|
|
138
160
|
| -------------------------------- | ------------------------------------------------ |
|
|
@@ -185,46 +207,144 @@ Place a `config/bun.json` in your project root:
|
|
|
185
207
|
"secure": false
|
|
186
208
|
},
|
|
187
209
|
"plugins": {
|
|
188
|
-
"css": ["
|
|
189
|
-
"js": ["jsGlobs"]
|
|
210
|
+
"css": ["aliases", "cssGlobs"],
|
|
211
|
+
"js": ["aliases", "jsGlobs"]
|
|
190
212
|
}
|
|
191
213
|
}
|
|
192
214
|
```
|
|
193
215
|
|
|
194
|
-
All values shown above are defaults
|
|
216
|
+
All values shown above are defaults. You only need to specify what you want to
|
|
195
217
|
override.
|
|
196
218
|
|
|
197
219
|
## Plugins
|
|
198
220
|
|
|
199
|
-
Three plugins are included out of the box
|
|
221
|
+
Three plugins are included out of the box.
|
|
222
|
+
|
|
223
|
+
### `aliases`
|
|
224
|
+
|
|
225
|
+
Resolves `$/` root aliases to absolute paths in both CSS and JS files. This
|
|
226
|
+
lets you reference assets and modules from the project root without worrying
|
|
227
|
+
about relative paths.
|
|
228
|
+
|
|
229
|
+
In CSS:
|
|
230
|
+
|
|
231
|
+
```css
|
|
232
|
+
@import '$/app/assets/css/reset.css';
|
|
233
|
+
|
|
234
|
+
.logo {
|
|
235
|
+
background: url('$/app/assets/images/logo.png');
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
In JS:
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
import utils from '$/lib/utils.js'
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
All `$/` references are resolved to your project root.
|
|
246
|
+
|
|
247
|
+
### `cssGlobs`
|
|
248
|
+
|
|
249
|
+
Expands glob patterns in CSS `@import` statements. Instead of manually listing
|
|
250
|
+
every file, you can import an entire directory at once:
|
|
251
|
+
|
|
252
|
+
```css
|
|
253
|
+
@import './components/**/*.css';
|
|
254
|
+
```
|
|
200
255
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
256
|
+
This will be expanded into individual `@import` lines for each matching file,
|
|
257
|
+
sorted alphabetically.
|
|
258
|
+
|
|
259
|
+
> [!NOTE]
|
|
260
|
+
> A warning is logged if the pattern matches no files.
|
|
261
|
+
|
|
262
|
+
### `jsGlobs`
|
|
263
|
+
|
|
264
|
+
Compiles glob imports into an object that maps file paths to their default
|
|
265
|
+
exports. Use the special `glob:` prefix in an import statement:
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
import components from 'glob:./components/**/*.js'
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
This will generate individual imports and builds an object mapping. For
|
|
272
|
+
example:
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
import _glob_components_theme from './components/theme.js'
|
|
276
|
+
import _glob_components_shared_tooltip from './components/shared/tooltip.js'
|
|
277
|
+
const components = {
|
|
278
|
+
'components/theme': _glob_components_theme,
|
|
279
|
+
'components/shared/tooltip': _glob_components_shared_tooltip
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
> [!NOTE]
|
|
284
|
+
> If no files match the pattern, an empty object is assigned.
|
|
206
285
|
|
|
207
286
|
### Custom plugins
|
|
208
287
|
|
|
209
|
-
|
|
288
|
+
Custom plugins are JS files referenced by their path in the config. Each file
|
|
289
|
+
must export a factory function that receives a context object with `root`
|
|
290
|
+
(project root path) and `prod` (boolean indicating production mode). What the
|
|
291
|
+
factory returns determines the plugin type.
|
|
292
|
+
|
|
293
|
+
#### Simple transform plugins
|
|
294
|
+
|
|
295
|
+
A simple transform plugin returns a function that receives the file content as
|
|
296
|
+
a string and an `args` object with the file's `path`. It should return the
|
|
297
|
+
transformed content. The transform can be synchronous or asynchronous.
|
|
298
|
+
|
|
299
|
+
Transforms are chained in the order they appear in the config, so each
|
|
300
|
+
transform receives the output of the previous one.
|
|
210
301
|
|
|
211
302
|
```javascript
|
|
212
303
|
// config/bun/banner.js
|
|
213
304
|
|
|
214
|
-
export default function banner({
|
|
215
|
-
return
|
|
216
|
-
const stamp = prod ?
|
|
217
|
-
return `/* My App${stamp} */\n${content}
|
|
218
|
-
}
|
|
305
|
+
export default function banner({prod}) {
|
|
306
|
+
return content => {
|
|
307
|
+
const stamp = prod ? '' : ` (dev build ${new Date().toISOString()})`
|
|
308
|
+
return `/* My App${stamp} */\n${content}`
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
#### Raw Bun plugins
|
|
314
|
+
|
|
315
|
+
If the factory returns an object with a `setup` method instead of a function,
|
|
316
|
+
it is treated as a raw
|
|
317
|
+
[Bun plugin](https://bun.sh/docs/bundler/plugins). This gives you full access
|
|
318
|
+
to Bun's plugin API, including `onLoad`, `onResolve`, and custom loaders.
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
// config/bun/svg.js
|
|
322
|
+
|
|
323
|
+
export default function svg() {
|
|
324
|
+
return {
|
|
325
|
+
name: 'svg-loader',
|
|
326
|
+
setup(build) {
|
|
327
|
+
build.onLoad({filter: /\.svg$/}, async args => {
|
|
328
|
+
const text = await Bun.file(args.path).text()
|
|
329
|
+
return {
|
|
330
|
+
contents: `export default ${JSON.stringify(text)}`,
|
|
331
|
+
loader: 'js'
|
|
332
|
+
}
|
|
333
|
+
})
|
|
334
|
+
}
|
|
335
|
+
}
|
|
219
336
|
}
|
|
220
337
|
```
|
|
221
338
|
|
|
222
|
-
|
|
339
|
+
#### Registering custom plugins
|
|
340
|
+
|
|
341
|
+
Reference custom plugins by their file path in your config:
|
|
223
342
|
|
|
224
343
|
```json
|
|
225
344
|
{
|
|
226
345
|
"plugins": {
|
|
227
|
-
"css": ["
|
|
346
|
+
"css": ["aliases", "cssGlobs", "config/bun/banner.js"],
|
|
347
|
+
"js": ["aliases", "jsGlobs", "config/bun/svg.js"]
|
|
228
348
|
}
|
|
229
349
|
}
|
|
230
350
|
```
|
|
@@ -252,8 +372,8 @@ your-app/
|
|
|
252
372
|
|
|
253
373
|
BunBunBundle was originally built for [Fluck](https://fluck.site), a
|
|
254
374
|
self-hostable website builder using [Lucky
|
|
255
|
-
Framework](https://luckyframework.org/). I wanted to have a fast
|
|
256
|
-
asset bundler that would
|
|
375
|
+
Framework](https://luckyframework.org/). I wanted to have a fast and modern
|
|
376
|
+
asset bundler that would require minimal maintenance in the long term.
|
|
257
377
|
|
|
258
378
|
Bun was the natural choice because it does almost everything:
|
|
259
379
|
|
|
@@ -265,10 +385,10 @@ Bun was the natural choice because it does almost everything:
|
|
|
265
385
|
- Extendability with simple plugins
|
|
266
386
|
|
|
267
387
|
It's also fast and reliable. We use this setup heavily in two Lucky apps and it
|
|
268
|
-
is rock solid
|
|
388
|
+
is rock solid. It has since been adopted by Lucky as the default builder.
|
|
269
389
|
|
|
270
|
-
I wanted to have the same setup in my Ruby apps as
|
|
271
|
-
|
|
390
|
+
This Gem was born because I wanted to have the same setup in my Ruby apps as
|
|
391
|
+
well. I hope you enjoy it too!
|
|
272
392
|
|
|
273
393
|
## Contributing
|
|
274
394
|
|
data/lib/bun/bun_bundle.js
CHANGED
|
@@ -42,7 +42,7 @@ export default {
|
|
|
42
42
|
loadConfig() {
|
|
43
43
|
const defaults = {
|
|
44
44
|
entryPoints: {js: ['app/assets/js/app.js'], css: ['app/assets/css/app.css']},
|
|
45
|
-
plugins: {css: ['
|
|
45
|
+
plugins: {css: ['aliases', 'cssGlobs'], js: ['aliases', 'jsGlobs']},
|
|
46
46
|
staticDirs: ['app/assets/images', 'app/assets/fonts'],
|
|
47
47
|
outDir: 'public/assets',
|
|
48
48
|
publicPath: '/assets',
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const REGEX = /(url\(\s*['"]?|(?<!\w)['"])\$\//g
|
|
2
|
+
|
|
3
|
+
// Resolves `$/` root aliases in CSS url() references and JS/CSS imports.
|
|
4
|
+
// e.g. url('$/app/assets/images/foo.png') → url('/absolute/root/app/assets/images/foo.png')
|
|
5
|
+
// import x from '$/lib/utils.js' → import x from '/absolute/root/lib/utils.js'
|
|
6
|
+
// @import '$/app/assets/css/reset.css' → @import '/absolute/root/app/assets/css/reset.css'
|
|
7
|
+
export default function aliases({root}) {
|
|
8
|
+
return content => content.replace(REGEX, `$1${root}/`)
|
|
9
|
+
}
|
data/lib/bun/plugins/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {join} from 'path'
|
|
2
|
-
import
|
|
2
|
+
import aliases from './aliases.js'
|
|
3
3
|
import cssGlobs from './cssGlobs.js'
|
|
4
4
|
import jsGlobs from './jsGlobs.js'
|
|
5
5
|
|
|
6
|
-
const builtins = {
|
|
6
|
+
const builtins = {aliases, cssGlobs, jsGlobs}
|
|
7
7
|
const TYPE_REGEXES = {
|
|
8
8
|
css: /\.css$/,
|
|
9
9
|
js: /\.(js|ts|jsx|tsx)$/
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'bun_bun_bundle'
|
|
4
|
+
|
|
3
5
|
module BunBunBundle
|
|
4
6
|
# Hanami integration for BunBunBundle.
|
|
5
7
|
#
|
|
@@ -9,8 +11,7 @@ module BunBunBundle
|
|
|
9
11
|
#
|
|
10
12
|
# module MyApp
|
|
11
13
|
# class App < Hanami::App
|
|
12
|
-
# BunBunBundle.setup(root: root)
|
|
13
|
-
# config.middleware.use BunBunBundle::DevCacheMiddleware if Hanami.env?(:development)
|
|
14
|
+
# BunBunBundle.setup(root: root, hanami: config)
|
|
14
15
|
# end
|
|
15
16
|
# end
|
|
16
17
|
#
|
data/lib/bun_bun_bundle.rb
CHANGED
|
@@ -38,10 +38,15 @@ module BunBunBundle
|
|
|
38
38
|
|
|
39
39
|
# Loads config and manifest. Call this from Hanami's config/app.rb or
|
|
40
40
|
# any Rack app's startup.
|
|
41
|
-
|
|
41
|
+
#
|
|
42
|
+
# Pass `hanami: config` from within a Hanami::App class body to
|
|
43
|
+
# automatically register middleware and configure CSP for development.
|
|
44
|
+
def setup(root: Dir.pwd, hanami: nil)
|
|
42
45
|
self.config = Config.load(root: root.to_s)
|
|
43
46
|
options = development? ? {} : { retries: 1, delay: 0 }
|
|
44
47
|
self.manifest = Manifest.load(root: root.to_s, **options)
|
|
48
|
+
|
|
49
|
+
configure_hanami(hanami) if hanami
|
|
45
50
|
end
|
|
46
51
|
|
|
47
52
|
# Returns the path to the bundled JS files shipped with the gem.
|
|
@@ -56,6 +61,16 @@ module BunBunBundle
|
|
|
56
61
|
@asset_host = nil
|
|
57
62
|
@environment = nil
|
|
58
63
|
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def configure_hanami(hanami_config)
|
|
68
|
+
return unless development?
|
|
69
|
+
|
|
70
|
+
hanami_config.middleware.use DevCacheMiddleware
|
|
71
|
+
hanami_config.actions.content_security_policy[:script_src] += " 'unsafe-inline'"
|
|
72
|
+
hanami_config.actions.content_security_policy[:connect_src] += " #{config.dev_server.ws_url}"
|
|
73
|
+
end
|
|
59
74
|
end
|
|
60
75
|
end
|
|
61
76
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bun_bun_bundle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Wout Fierens
|
|
@@ -36,7 +36,7 @@ files:
|
|
|
36
36
|
- exe/bun_bun_bundle
|
|
37
37
|
- lib/bun/bake.js
|
|
38
38
|
- lib/bun/bun_bundle.js
|
|
39
|
-
- lib/bun/plugins/
|
|
39
|
+
- lib/bun/plugins/aliases.js
|
|
40
40
|
- lib/bun/plugins/cssGlobs.js
|
|
41
41
|
- lib/bun/plugins/index.js
|
|
42
42
|
- lib/bun/plugins/jsGlobs.js
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import {join} from 'path'
|
|
2
|
-
|
|
3
|
-
const REGEX = /url\(\s*['"]?\$\//g
|
|
4
|
-
|
|
5
|
-
// Resolves `$` root aliases in CSS url() references.
|
|
6
|
-
// e.g. url('$/images/foo.png') → url('/absolute/src/images/foo.png')
|
|
7
|
-
export default function cssAliases({root}) {
|
|
8
|
-
const srcDir = join(root, 'src')
|
|
9
|
-
return content => content.replace(REGEX, `url('${srcDir}/`)
|
|
10
|
-
}
|