Bud v6.4.0 released

bud v6.4.0 released

Lots of fixes, features, and performance improvements. As always, you can read enhanced release notes at bud.js.org.


hot reload middleware

Internally, bud.js has fully replaced webpack-hot-middleware and its associated client scripts.

What you can expect:

  • If you have an error in your code that fully breaks hot module reloading the client
    will automatically perform a full page reload.
  • You should have far fewer duplicate log messages about module updates.

proxy url replacement

If you are using bud.proxy you don’t need to do anything. But, if you wanted to use this script directly it is now a lot more flexible.

There are two ways to utilize it:

1. add to your entry imports array

@roots/bud-client/lib/proxy-client-interceptor.js accepts URL parameters for search and replace strings.

  app: [
    // ... app scripts and styles

2. import it in a client script

@roots/bud-client/lib/intercept.js can be imported directly and called from application code.

import intercept from '@roots/bud-client/lib/intercept.js'

intercept('http://example.com', '/')

improved: bud.config.local support

If you are on a team and team members have different needs for their local development environment, you can now use bud.config.local.mjs to override bud.config.mjs settings.

.local configs will always be applied after the base config.

improved: bud.assets

You can now specify copy options to apply to all copy patterns as a second parameter.

So the second parameter will be merged onto each pattern:

    {from: 'images', to: 'images'},
    {from: 'fonts', to: 'fonts'},
  {context: app.path('@assets')},

This is the same as:

    from: 'images',
    to: 'images',
    context: app.path('@assets'),
    from: 'fonts',
    to: 'fonts',
    context: app.path(`assets`),

This also works with string or [from, to] tuples, as well.

new: bud.sh

bud.sh is a new config function that allows for executing arbitrary shell commands. It is a wrapper around the execa package.

It’s async and returns the ExecaChildProcess object. It will pipe the process stdout/stderr to the console automatically.

await bud.sh('echo "hello world"')

Ideal for a hook like compiler.done, if you wanted to fire off a command when finalizing a build.


Enhanced build summary

Here’s what you can expect:

β—‰  @tests/project ./dist [6c3fa82de0a7a70e5e45]
β”œβ”€ entrypoints
β”‚ β”œβ”€ app
β”‚ β”‚ └─ js/app.js           28.34 kB
β”‚ β”œβ”€ app2
β”‚ β”‚ └─ js/app2.js          26.73 kB
β”‚ └─ dev-client
β”‚   └─ js/dev-client.js    84.61 kB
β”œβ”€ assets
β”‚ β”œβ”€ images/image.jpeg          761.41 kB
β”‚ β”œβ”€ images/nested/image.jpeg   761.41 kB
β”‚ └─ images/.gitkeep
└─ compiled 41 modules in 709ms

β—‰  HtmlWebpackCompiler ./dist [bce8eedbb4952eca25f3]
└─ compiled 6 modules in 262ms

β„Ή server
β”œβ”€ internal: http://localhost:3015 (http://localhost:3015)
└─ external: (

… watching project sources

Some of the changes you may notice:

  • Displays information for multiple compilations.
  • Labeled (can be useful if running builds in parallel with yarn/npm workspaces).
    • tip: set your compilation label using the name field of package.json
  • Indicates the directory being emitted to (also handy for identification purposes).
  • Includes the oft-requested β€œexternal IP” for use over LAN.
  • Visually grouped by entrypoint
  • Improved display of compiler error messages
  • Improved display of compiler warning messages

bud repl

Start a repl to play around with bud: $ bud repl

option description default
--indent,-i indentation level 1
--depth,-d recursion depth 2

Some example queries you may wish to try:

  • $ bud.hooks.events.store
  • $ bud.extensions.get('webpack:define-plugin')
  • $ bud.make('test').then(bud => bud.get('test').label)
  • $ bud.extensions.make()
  • $ bud.hooks.filter('build.optimization')

bud view

Explore the bud object with $ yarn bud view. You can use dot notation to dive through properties.

option description default
--indent,-i indentation level 2
--color,-c color true

Interesting examples:

See what functions were called: $ yarn bud view api.trace

View the generated config: $ yarn bud view build.config

You can go as deep as you need but if you are accessing an array by index you’ll probably need to escape the brackets with quotes:

$ yarn bud view 'build.config.module.rules[1].oneOf[0]'

bud webpack

This is a passthrough command for the webpack cli. Get webpack usage help $ yarn bud webpack -- --help

To run a build with webpack you’d probably want to create a new file named webpack.config.js in your project and do something like this:

// webpack.config.mjs

import {get} from '@roots/bud/factory'

export default async () => {
  const bud = await get()
  return await bud.build.make()

Run it with $ yarn bud webpack.



Set the application base directory. Default: process.cwd()


Now accepts an (optional) string to open the project in a specific browser. The exact string is system dependent. Check the sindresorhus/open docs


Will run bud.js all the way up until it’s time to actually instantiate the compiler or the dev server, and then it bails.


Set logging level.

Flag Level
-v error
-vv warning
-vvv log
-vvvv info (verbose)

default: -vv.


Emit artifacts to storage directory for debugging bud.js context or the emitted webpack configuration. In earlier versions of bud.js a snapshot of the finalized webpack configuration and a snapshot of bud.js state was always saved to storage prior to compilation. If your project is working correctly this is just needless fs overhead.

default: false


allow bud.js to hard reload the browser window when an error is encountered that breaks hot module reloading.

default: true

Extensions can register commands

Extensions can now register commands.

So far a few commands have been implemented:

  • yarn bud ts check will typecheck source assets (registered by @roots/bud-typescript).
  • yarn bud lint (alias: yarn bud eslint) will lint source assets (registered by @roots/bud-eslint).
  • yarn bud tailwindcss will transpile tailwindcss (registered by @roots/bud-tailwindcss).
  • yarn bud format (alias: yarn bud prettier) will format source assets (registered by @roots/bud-prettier).



bud.hooks.fromMap can be used to set multiple hooks in one call.

  'build.node': false,
  'build.resolve.extensions': ext => ext.add('.mjml'),


bud.hooks.fromAsyncMap can be used in the same way to set hooks with async callbacks.

  'build.plugins': async () => await app.extensions.make(),
  'build.resolve.modules': async () => [


Services have access to some new methods that are called when the associated lifecycle event takes place.

In the order they are called:

method name associated lifecycle event
configAfter config.after
compileBefore compile.before
buildBefore build.before
buildAfter build.after
compileAfter compile.after


Extensions have access to some new methods that are called when the associated lifecycle event takes place.

In the order they are called:

method name associated lifecycle event
configAfter config.after
buildBefore build.before
buildAfter build.after

:sparkles: Improve: builds now labeled by package.json name field

In earlier versions of bud.js the bud.label property was always set to bud (for the parent compiler). Now, it will be set to the name field
of your project (as set in package.json). If you don’t have a name set the new default is default.

In addition to the clearer output summary labeling (see above), you should also find that logs are better labeled now:

[bud@6.4.0] [my-project] β€Ί importing @roots/bud-terser/css-minimizer

:information_source: Release information

For more information review the diff to see what’s changed.