Add plugin system for bun#2020
Conversation
Removes the inline CSS aliases plugin and injects plugins into the configuration and build flows.
Remove comments that are just restating the method name and clean up the code a bit.
The `cssAliases` plugin just resolved aliases inside a `url()`. The plugin has now been renamed to `aliases` and can be used for for CSS and JS imports as well.
Don't include the globbed directly's name itself.
In some cases where two globbed dirs contained a file with the same name, ther could be a variable name clash resultig in a subtile bug.
|
Okay, I keep tweaking here but these are the last bits I think. 😊 I like this setup so much that I created a Ruby gem for it to use in our Rails apps: https://github.com/wout/bun_bun_bundle. While implementing it some unforeseen issues popped up. One is a 15-year old Rails app and the codebase contains about 160 CSS, 500 JS files and 80 other assets (fonts and images) across different directories. So that was a good exercise to test this setup. The change (from Vite) was fairly easy. The whole build went from a few seconds in Vite to about 100 ms in Bun. So now the documentation for this whole Bun setup is also as good as done. I only need to do the Lucky part now. |
Vim saves files by copying the original file → file~, then writing the new file. The fs.watch() command looses the inode and does not report a change. In this fix both file and file~ are watched and trigger a rebuild, and a debounce is added to prevent double builds for any given file. This also adds better error reporting in case there are build errors.
jwoertink
left a comment
There was a problem hiding this comment.
I need to understand this a bit more, but I guess let's just get it in and moving 🥳
|
Great, let me know if something isn't entirely clear. I'm going to keep the JS in this repo and in the bun_bun_bundle gem in sync manually for now. Except for a few paths in the default configs ( The ruby gem is in production in a Rails app since this week, and our front-end dev is very happy with it. It cleaned up the codebase because CSS has a dedicated pipeline (no more CSS imports in JS) and the production build in development is also a huge bonus. And the day before we merged it in, Vite got updated to version 8, inexplicably braking some parts of Alpine JS. So that was right on time. 😄 |

Purpose
This PR adds a plugin system for Bun, glob functionality for CSS and JS imports, and a few tweaks to Lucky (see also #2019).
Description
The plugin system hooks in to the JS and CSS transformation chains. Three plugins are included now and activated by default.
1.
cssAliasesThis plugin was already present but was hardcoded. It resolves
$root aliases in CSSurl()references, so you can avoid the use of relative paths for images and fonts. For example:url('$/images/foo.png')→url('/absolute/src/images/foo.png')2.
cssGlobsThis is a new plugin to allow glob patterns in CSS imports:
This will be intercepted by the plugin and expanded to a list of imports for individual files in alphabetical order.
3.
jsGlobsIn Bun there's no such thing like
import.meta.globin Vite. This plugin enables a similar thing with a special syntax for imports:Which will be expanded to something like:
The
componentsobject can then be used to for example load and register a directory of Alpine.js components or Stimulus.js controllers.Custom CSS/JS transform plugins
Plugins to hook into the CSS and JS transformation chains look as follows:
Or async:
The
contextargument in the plugin factory function contains the following properties:context.root(string) the Lucky project's root directorycontext.config(object) the fully resolved config from bun.jsoncontext.dev(boolean) whether the--devflag is used or notcontext.prod(boolean) whether the--prodflag is used or notcontext.manifest(object) the asset manifest being builtImportant
The CSS/JS transform plugins above are bundled together into one Bun plugin per type. This is necessary because Bun can only register one loader for a given path matcher.
Bun plugins
Raw Bun plugins can be added as well:
Registering plugins
Custom plugins can be registered in the
bun.json. By default, the three built-in plugins are loaded and custom plugins can be added using the full path relative to Lucky's root:{ "entryPoints": { "js": ["src/js/main.js"], "css": ["src/css/main.css"] }, "plugins": { "css": ["cssAliases", "cssGlobs", "config/bun/plugins/luckyCssPlugin.js"], "js": ["jsGlobs"] }, ... }Lucky::DevAssetCacheHandlerThis is a new handler to disable browser caching for static assets in development. Currently I added it to the handlers listin
AppServerlike this:But I wonder if that is the most elegant way to do it. Essentially this will just continue to the next handler if it's not enabled, so it's an empty call. This could also be an option of course:
[ # ... (Lucky::DevAssetCacheHandler.new if LuckyEnv.development?), # ... ].select(HTTP::Handler)Not unrelated, in the upload implementation we'll need to do a similar thing with a
Lucky::StaticFileHandlerin development, so users can render images from a local upload directory if they choose to use file system uploads. This handler will also need to be added only in environments where aFileSystemstorage is used. So I think it's a good idea to formalise a way to enable some handlers in certain environments.Checklist
crystal tool format spec src./script/setup./script/test