High-performance build system that supports SWC, esbuild, and Babel
MIT License
Bot releases are visible (Hide)
Published by kellymears almost 2 years ago
A bugfix release for bud v6.6.x.
bud.extensions.add('some-webpack-plugin')
bud.extensions.add(new SomeWebpackPlugin())
bud.extensions.add({apply: () => void 0})
For more information review the diff to see what's changed.
Published by kellymears almost 2 years ago
Features, improvements and fixes. Strongly recommended for multi-compiler users.
Read the release notes on bud.js.org
You can use bud.glob if you have need for this.
Example:
export default async bud => {
bud.entry(`app`, await bud.glob(`@src/*.{js,css}`))
}
label | description | exposed |
---|---|---|
@roots/bud-extensions/cdn | Adds remote import functionality | bud.cdn |
@roots/bud-extensions/esm | Adds ESM support functionality | bud.esm |
@roots/bud-extensions/clean-webpack-plugin | Cleans output directory on build | |
@roots/bud-extensions/copy-webpack-plugin | Copies assets (used by bud.assets) | |
@roots/bud-extensions/fix-style-only-entrypoints | Removes JS output from entrypoints which only contain CSS | |
@roots/bud-extensions/html-webpack-plugin | HTML functionality (used by bud.template) | |
@roots/bud-extensions/interpolate-html-webpack-plugin | Adds create-react-app -like template variable support for HTML files |
|
@roots/bud-extensions/mini-css-extract-plugin | Optimized CSS loading | |
@roots/bud-extensions/webpack-define-plugin | Defines variables which can be used in the application (used by bud.define) | |
@roots/bud-extensions/webpack-hot-module-replacement-plugin | Adds HMR support | |
@roots/bud-extensions/webpack-manifest-plugin | Emits manifest.json
|
|
@roots/bud-extensions/webpack-provide-plugin | Provides import(s) globally to the application |
If you were using one of these labels directly, you'll need to update it. The upshot of this is that your editor will likely not only tell you that it's wrong but also offer the new key as a suggestion.
Very convenient! Works for webpack plugins or bud.js extensions.
export default async bud => {
bud.use('browsersync-webpack-plugin')
}
export default async bud => {
await bud.extensions.add('browsersync-webpack-plugin')
}
This will only work if the plugin/extension is the default
export.
Variables sourced from .env files in the path to the project are now interpolated using env-expand.
Previously, only the project directory would be expanded.
If you have an unescaped string that causes the expansion to fail the error will be caught.
Each bud.js instance's entrypoints are now registered with @roots/bud-client/hot
. This helps to prevent conflicts
with reloaded modules when using multiple bud instances.
Some notes:
single
.build.dependencies
hook. Or, specify the dependencies in the context
argument passed to bud.make.Example of a custom dependsOn
when setting up a child instance:
export default async bud => {
bud.make({
label: `example`,
basedir: bud.path(`example`),
dependsOn: [`some-other-instance`],
})
}
bud upgrade
commandRun bud upgrade
to bump bud dependencies to the latest available version.
You will need to run the install after the command completes. This is a new command and is not yet unit tested.
Call bud.swc.plugins
to manage @swc/core
plugins. You can pass an array of plugins (as demonstrated in the swc docs) or a callback
if you want to modify what's already there:
export default async bud => {
bud.swc.plugins(plugins => {
plugins.push([`swc-plugin`, {option: true}])
})
}
If you haven't tried @roots/bud-swc you should consider it. This extension is no longer considered experimental. There is a strong case to be made for it replacing @roots/bud-babel in @roots/bud-preset-recommend for version 7 of bud.js.
If you have @roots/bud-swc installed, @roots/bud-emotion will register emotion support with @swc/core
.
Disable critical CSS extraction by calling bud.critical.extract(false)
. This isn't generally recommended.
@roots/bud-criticalcss remains an experimental extension.
This fix requires acorn v3 and you must set a public path. You can opt-in with bud.sage.setAcornVersion('v3')
.
With the acorn version set to v3
assets should load when using the proxy directly in dev mode. You will still see 404 errors for the /bud/hot
endpoint.
Nothing is required of you, but if you're curious, here's what's changed:
When files are added or removed from a watched directory path the browser will now reload.
You should now get useful, accurate intellisense and typechecking when using the bud.extensions
api directly.
It warns you to move it to the parent context. For now it also does this for you since it's an understandable mistake and will result in a TypeError
.
There should be less duplication of emitted errors, more meaningful stack traces, and highlighting of important
parts of the error message.
nodenext
to resolve node modulesWe're using the nodenext
tsc module
setting. This enables top-level await
for core bud.js packages 🥳.
strict
mode is enabled! We're beginning to implement runtime validation using zod.
We switched from jest to vitest because of esm compatibility issues. It's pretty nice!
Hopefully we'll be able to run unit tests on the CLI now.
For more information review the diff to see what's changed.
Published by kellymears almost 2 years ago
Bug fix for @roots/bud-sass
users.
An error thrown by Sass in development mode would cause the process to exit early. This issue could effect other plugins, but it surfaced via reports by @roots/bud-sass
users.
Regardless, the fix is general and should apply to all extensions.
For more information review the diff to see what's changed.
Published by kellymears almost 2 years ago
Bugfix release for multi-instance configurations. Read on bud.js.org.
Specifying an entrypoint is optional and, accordingly, its value may very well return undefined
. This possibility was not handled correctly by @roots/bud-server/inject
for multi-instance configurations, and would throw a TypeError
if a child didn't explicitly set an instance. This is now fixed.
In multi-instance configurations the last call to Extension.enable()
or Extension.disable()
would be applied to all instances. This has been fixed.
For more information review the diff to see what's changed.
Published by kellymears about 2 years ago
Small fixes and improvements related to argv
, package.json
and .env
settings.
argv
parsingThese flags were janky but now they are golden:
--devtool
- Set desired devtool--clean
- Enable or disable build cleaning--discovery
- Enable or disable automatic extension registration--flush
- Clean webpack cacheThis release also adds a --runtime
flag, which is new. It doesn't accept everything bud.runtime
does, but you can use it to specify basic options like single
or multiple
.
env
contextYou can now set certain values in your .env
:
APP_BASE_PATH
- the base path for your appAPP_PUBLIC_PATH
- the public path for your appAPP_SRC_PATH
- the @src
path for your appAPP_DIST_PATH
- the @dist
path for your appAPP_STORAGE_PATH
- the @storage
path for your appAPP_MODE
- desired build modepackage.json
contextThe options available under the bud
key in package.json
have been expanded:
{
"bud": {
"paths": {
"base": string,
"src": string,
"dist": string,
"storage": string
},
"publicPath": string,
"extensions": {
"allowlist": string[],
"denylist": string[],
"discovery": boolean
}
}
}
If you are using bud.allowlist
or bud.denylist
, please update to bud.extensions.allowlist
and bud.extensions.denylist
. You'll get a warning in your terminal for now; in a future release this will cause an error.
The implementation and documentation for the bud.serve
function had fallen out-of-sync. The bud.serve
documentation and development server configuration guides are now up-to-date.
Additionally, path rewrites for proxied URLs served over SSL were defaulting to 0.0.0.0
for hostname
. This has been fixed.
Example of the config which served as a test case for this release:
.proxy("https://ssl-test.test")
.serve({
host: "ssl-test.test",
cert: `${process.env.HOME}/.config/valet/Certificates/ssl-test.test.crt`,
key: `${process.env.HOME}/.config/valet/Certificates/ssl-test.test.key`,
})
To apply the hostname fix to earlier versions of bud you will need to apply the rewrite in your config:
// This is no longer necessary in 6.5.1
bud.proxy('https://ssl-test.test', [['0.0.0.0', 'ssl-test.test']])
For more information review the diff to see what's changed.
Published by kellymears about 2 years ago
Filesystem API, S3 uploads, and more.
⚠️ This release deprecates the
optIn
property and decorator for extensions. This doesn't matter unless you are authoring an extension. If you are, you can probably just usedependsOnOptional
instead.
bud.fs
is a new filesystem API for bud.js. It uses fs-jetpack and includes support for managing s3 assets.
Example of a file write operation:
await bud.fs.write(`README.md`, `# Hello, world!`);
Example of the S3 API which uploads @dist
contents to a bucket after compilation:
bud.fs
.setCredentials({
accessKeyId: `***`,
secretAccessKey: `***`,
})
.setEndpoint(`https://sfo2.digitaloceanspaces.com`)
.setBucket("bud-test")
.upload();
Check the bud.fs docs for more information.
Config function for executing tasks after the compilation is fully complete. This is useful for tasks that need to run after the compilation is complete, but don't need to be part of the compilation process (like uploading assets to s3!)
export default async (bud) => {
bud.after(async (bud) => {
await bud.fs.write(
`dist/credits.txt`,
`${bud.context.manifest.name} built by me!`
);
});
};
Execute a command with bud.sh:
export default async (bud) => {
bud.after(async (bud) => await bud.sh(`yarn jest`));
};
Check the bud.after docs for more information.
Some logs would be displayed twice in the terminal if they were emitted around the same time that the dashboard was being updated.
It was also possible, depending on user configuration, for requests for the dashboard to update to fire twice. This has been fixed.
console.*
events are now caught by a new service: bud.bufferConsole
. The service catches logs, trims and deduplicates them, and then emits them using an instance of the standard bud logger. If bud is invoked with the --ci
flag the service will let them pass through normally.bud.dashboard
service's stats
method is now debounced. Duplicative calls should be ignored.It's likely that our handling of process.stdout
is still imperfect, but this is a step in the right direction.
In dev
mode only the first compilation would result in a desktop notification. This has been fixed. You should now receive a notification for every compilation.
bud.env
is not an instance of Container
bud.env
was not an instance of Container
and therefore did not have methods like is
. This has been fixed and it should now behave as documented.
Dynamically imported chunks were not being hashed. This has been fixed.
A breaking change in the critical
package had broken this extension. This change has now been accounted for and the extension should work again. This extension is still listed as experimental.
For more information review the diff to see what's changed.
Published by kellymears about 2 years ago
A bugfix release for bud 6.4.x. Read release notes on bud.js.org
WP_HOME
WP_HOME
is now automatically set as a fallback proxy value. This means that if you don't call bud.proxy value in your bud.config.js
file, the extension will attempt to use WP_HOME
(if it is available and is a string value).
Previously, this value was set up front, which could cause errors if the value was malformed.
bud.wpjson.useTailwindFontSize
mutates configThis function no longer mutates the tailwind config. This caused tailwind to not generate css for font sizes.
theme.extend
If you wish to limit generated values in theme.json
to those included in theme.extend
, you can now do so with an optional parameter passed to useTailwindFontFamily
, useTailwindColors
, and useTailwindFontSize
.
export default async bud => {
/**
* Limit generated values to those used in theme.extend
*/
bud.wpjson.useTailwindFontFamily(true)
}
If called with no arguments, the default behavior is to generate all values resolved by tailwindcss.
bud.tailwindcss.resolveTailwindThemeValue
renamed to bud.tailwindcss.resolveThemeValue
This is an undocumented method but some of you may very well be using it. It's name changed.
--browser
flag not workingRegression introduced in 6.4.0. Fixed (with added unit tests).
For more information review the diff to see what's changed.
Published by kellymears about 2 years ago
A bugfix release for bud 6.4. Mainly focused on multi-instance configurations. Read on bud.js.org
Fixes an issue where @roots/bud-postcss was not applied to child compilations. (#1702).
Added documentation for configuring development server in a multi-instance setup to the multi-instance guide. (#1713)
For more information review the diff to see what's changed.
Published by kellymears about 2 years ago
Release notes are also available on bud.js.org
Errors no longer reported when not using tailwindcss in a @roots/sage project.
bud.wpjson
doesn't generate colorsColors now generated for theme.json
when using bud.wpjson.useTailwindColors()
You can now easily use tailwind theme values in your app code by importing them from the (virtual) @tailwind/*
alias.
An example:
import {black} from '@tailwind/colors'
import {sans} from '@tailwind/fontFamily'
export const main = () => {
document.body.style.backgroundColor = black
document.body.style.fontFamily = sans
}
Generating the imports can be memory intensive and increase build times, so it is opt-in.
app.tailwind.generateImports()
Better to generate imports only for specific keys (much less memory intensive):
app.tailwind.generateImports([`colors`, `fontFamily`])
This is a lot better than trying to import the actual tailwind.config.js
file to read these values as the values are fully resolved (merged with defaultTheme
, plugins applied, etc.)
And it's a lot better than importing tailwindcss/resolveConfig
and doing it in the app code because of the transitive dependencies taken on by that import.
It's also better than pre-compiling a static json file because these values are tree-shakeable. The entire generated json for the default tailwind config is ~100kb.
The above example adds ~5kb to the overall bundle (and only because tailwind has so many default colors). If you use terser (bud.minify) the difference is entirely negligible.
For more information review the diff to see what's changed.
Published by kellymears about 2 years ago
Release notes also available on bud.js.org
If you are not using @roots/bud-tailwindcss
you will see errors in the logs when running bud build
or bud dev
.
This is a known issue and will be resolved in the next release. It isn't a sign that anything is wrong in your project.
bud.wpjson
now fully resolves tailwind configsPreviously, bud.wpjson
could only generate a theme.json
based on a fully static tailwind config file. This excluded tailwind configs that
defined theme properties using functions and also meant that plugins would not be applied.
Now, bud.wpjson
functions related to tailwindcss will fully resolve the tailwind config file and generate a theme.json
based on the
processed config. This should mean that any tailwind config can be used in conjunction with bud.wpjson.useTailwindColors()
and similar functions.
For production builds, build errors will now result in a non-zero exit code. This regression was introduced in 6.4.0. It is now fixed.
eslint.config.js
configurations are now supported.
The bud repl
command has seen significant improvements since 6.4.0. It fixes a bug in 6.4.1 related to syntax highlighting.
For more information review the diff to see what's changed.
Published by kellymears about 2 years ago
Lots of fixes, features, and performance improvements. As always, you can read enhanced release notes at bud.js.org.
Internally, bud.js has fully replaced webpack-hot-middleware
and its associated client scripts.
What you can expect:
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:
@roots/bud-client/lib/proxy-client-interceptor.js
accepts URL parameters for search
and replace
strings.
bud.entry({
app: [
// ... app scripts and styles
`@roots/bud-client/lib/proxy-client-interceptor.js?search=http://example.com&replace=/`,
],
})
@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', '/')
bud.config.local
supportIf 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.
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:
bud.assets(
[
{from: 'images', to: 'images'},
{from: 'fonts', to: 'fonts'},
],
{context: app.path('@assets')},
)
This is the same as:
bud.assets([
{
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.
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.
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: http://192.168.194.103:3015 (http://192.168.194.103:3015)
… watching project sources
Some of the changes you may notice:
name
field of package.json
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')
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]'
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
.
--basedir
Set the application base directory. Default: process.cwd()
--browser
Now accepts an (optional) string to open the project in a specific browser. The exact string is system dependent. Check the sindresorhus/open docs
--dry
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.
-v,-vv,-vvv,-vvvv
Set logging level.
Flag | Level |
---|---|
-v |
error |
-vv |
warning |
-vvv |
log |
-vvvv |
info (verbose) |
default: -vv
.
--debug
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
--reload
allow bud.js to hard reload the browser window when an error is encountered that breaks hot module reloading.
default: true
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.
bud.hooks.fromMap({
'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.
bud.hooks.fromAsyncMap({
'build.plugins': async () => await app.extensions.make(),
'build.resolve.modules': async () => [
app.hooks.filter(`location.@src`),
app.hooks.filter(`location.@modules`),
],
})
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 |
name
fieldIn 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:
[[email protected]] [my-project] › importing @roots/bud-terser/css-minimizer
For more information review the diff to see what's changed.
Published by kellymears about 2 years ago
Read the release notes on bud.js.org
Paths resolved by bud.js's module resolve utility had spaces replaced with %20
in the path. This replacement was being made
by import-module-resolve
's resolve
function, which treats paths as browser-compatible URIs.
This small patch replaces %20
with
(U+0020) before returning resolved paths.
For more information review the diff to see what's changed.
Published by kellymears about 2 years ago
As always, release notes available at bud.js.org.
bud-error
componentThe bud-error
component is now only added to the DOM only when there is an error and is removed when there is not.
The bud.env docs have been updated to reflect the actual intended use of public env variables:
PUBLIC_APP_NAME="My App"
console.log(APP_NAME)
Previously, the envvars would have needed to include quotations in order to be output as a string (as in: PUBLIC_APP_NAME="'My App'"
).
Now, they are passed through JSON.stringify
automatically.
A number of extensions will attempt to use dependencies if they are available, falling back to more common
dependencies if they are not. Previously, bud.js would attempt to import the dependencies repeatedly, in cases
where more than one extension tried for the same optional, uninstalled dependency.
Not sure that this matters much in terms of performance because of the way that esmodules are cached. But, at the very least,
it cleans up the logs a bit.
@roots/bud-tailwindcss/stylelint-config/scss
errorHattip to @joshuafredrickson for the PR fixing this module import error.
For more information review the diff to see what's changed.
Published by kellymears over 2 years ago
Release notes also available on bud.js.org.
This is only relevant if you are writing an extension for bud.js.
All extension lifecycle methods now have a single signature:
interface Method {
(bud: Bud, options: Options): Promise<unknown>
}
This applies to: init
, register
, boot
, afterConfig
, beforeBuild
, make
, apply
and when
.
@roots/bud-sass
configuration optionsThe documentation for @roots/bud-sass has been updated.
Use the bud.sass.importGlobal
function to make a scss module available throughout your stylesheets, regardless of scope.
bud.sass.importGlobal('@src/styles/variables')
If you have more than one stylesheet to import, you may use an array:
bud.sass.importGlobal([
'@src/styles/variables',
'@src/styles/mixins',
'@src/styles/functions',
])
Use the bud.sass.registerGlobal
function to ensure global styles are made available throughout your sass stylesheets, regardless of scope.
This function differs from bud.sass.importGlobal
in that it can be passed arbitrary values.
bud.sass.registerGlobal('$foo: rgba(0, 0, 0, 1);')
If you want to divide these values up using an array, you may do so.
bud.sass.registerGlobal([
'$foo: rgba(0, 0, 0, 1);',
'$bar: rgba(255, 255, 255, 1);',
])
Resolved some inconsistencies between the function typings, documentation and implementation.
You are now able to use an array of values for an alias.The first resolvable module found will be used, checking in the order of the supplied array.
Example:
bud.alias('@app', [
bud.path('@src/scripts/app'),
bud.path('@src/scripts/utils'),
])
Finally, you may now also pass false
to ignore a specific module.
You can do this with a signifier or a path:
bud.alias({
'ignored-module': false,
[bud.path('./ignored-module')]: false,
})
For those who remember: this basically replaces null-loader
.
The hmr status indicator and client overlay are now using the shadow dom to more or less fully separate their styles from page styles.
All of the @roots/bud-client scripts remain dependency free.
For more information review the diff to see what's changed.
Published by kellymears over 2 years ago
Read the release on bud.js.org
An internal misconfiguration could have resulted in some app code errors hanging the HMR middleware. This has been addressed.
bud clean
commandThis command has been fixed. The problem stemmed from a change made for the benefit of multi-compilers in v6.
I didn't realize the project I was using to test bud in the context of Trellis/Bedrock/Acorn/Sage was using acorn v3 (which is still in alpha).
This caused some problems with public path in roots/sage projects using acorn@v2. Whoops!
Moving forward, I have set up an explicit e2e testing environment which includes acorn@v2 and acorn@v3 projects. Right now it is testing hmr compilation works in the browser.
In the future, there will be additional tests for:
@asset
directiveThis change from v6.3.1 has been reverted. Still, it is our current hope that users who enable esm
and have set a compatible build target will output es modules. What we're reverting is an enforcement of esm as an output format.
It turns out webpack also configures the output.chunkFormat
and output.chunkLoading
values based on the application's build target
option, which is usually set in a browserslist config.
In the case of conflict, the behavior has been varied but largely undesirable. Additional testing is required in order to have any confidence in the behavior that will result from settings these values.
For more information [review the diff to see what's changed(https://github.com/roots/bud/compare/v6.3.1...v6.3.2).
Published by kellymears over 2 years ago
For a better reading experience, read on bud.js.org.
@wordpress/browserslist-config is licensed in a way that is not compatible with bud's overall licensing ideals. Accordingly, we're offering a drop-in replacement: @roots/browserslist-config.
There are three configurations available, pick the one most suited to your requirements:
Export | Target | Description |
---|---|---|
@roots/browserslist-config | >1% usage | Similar to @wordpress/browserslist-config |
@roots/browserslist-config/current | >.5% usage | Similar to @facebook/docusaurus |
@roots/browserslist-config/broad | last 3 versions | Similar to @shopify/browserslist-config |
postcss-import
becomes import
postcss-nesting
becomes nesting
postcss-preset-env
becomes env
More information added to docs
Essentially 100% of postcss users want three things from postcss: @import
, nesting, and the arcane magic that is postcss-preset-env
. Some want more, but none want less. And out of that 100%, pretty much 100% of them want the plugins in that order.
That 100% figure is absolutely a fabrication, but I do think there is something to it.
Nobody wants nesting before import because it just doesn't work. Everything goes sideways immediately. You probably have an @import
right at the top and postcss has no way to know what to do with it.
So, that basic ordering is locked down now (at least by default — check the docs for information on how to override). The result is that its much simpler to play with the baseline config without breaking everything.
It's pretty passe to just go throwing the entirety of node_modules
into a vendor.js
file with bud.splitChunks.
Why not be cool and target only the dependencies that benefit from it?
Introducing a better, simpler way to code split: bud.bundle.
bud.bundle('react')
Or, group some dependencies you always use together:
bud.bundle('react', ['react', 'react-dom'])
Nice chunk!
You're not restricted to node_modules
, use your own code with it too, if you want. The only rule is that the chunk members are being addressed by directory. So, to match your own code you need to make a directory for it.
You can always use bud.splitChunks
if you need more control than that.
bud.js still sources envvars from process and its path, but will no longer attempt to expand values outside of the .env
found in the project root directory.
This could cause issues if ${
and other such character strings were used in bud's path without being escaped.
If you're using @roots/sage, you should try doing a dynamic import with @roots/sage/client/lazy
:
import lazy from '@roots/sage/client/lazy'
const makeConfetti = async () => {
await lazy(import('canvas-confetti'), confetti => confetti())
}
A small configuration issue in the @roots/bud-vue extension has been fixed and scoped stylesheets should no longer make total destroy.
I'm just going to come out and say it: if you are not serving from web root you should specify a public path.
This is what I'm imagining you saying right now:
Here are my responses:
In all seriousness we'll get more specific & explicit about this in the documentation but I can say that in the future bud will expect users not serving assets from web root to define a public path. Right now we characterize
it as "if you want to use dynamic imports", but it will be simplifying to just assume it is set.
I think it is a reasonable requirement and certainly a common one. And, for what it's worth, I'm afraid to take the L train, too.
Published by kellymears over 2 years ago
If you prefer, read the v6.2.0 release notes on bud.js.org. If only for the table of contents.
This release introduces a new extension: @roots/bud-swc.
The extension registers support for swc.
You can try it out by installing @roots/bud-swc
. Hopefully it "just works" out of the box for you, but check out the docs for details on how to configure swc for your project.
If you have the extension installed @roots/bud
will privilege it over @roots/bud-babel
when it is available. So, you really can give it a go by just adding @roots/bud-swc
to your project dependencies when upgrading.
The swc project claims upwards of a 70x performance improvement over babel. I don't see that in testing (MacOS ARM arch), but it is definitely faster (~20%).
I hear the difference is particularly pronounced in WSL2, although my means to test that is limited. Let me know how it goes!
For projects using a combination of @roots/bud-react
and either @roots/bud-typescript
, @roots/bud-swc
and/or @roots/bud-babel
, react fast refresh is now enabled by default.
If you don't want react fast refresh then you can disable it with:
bud.react.refresh.disable()
⚠️ If you are currently configuring fast-refresh using bud.reactRefresh()
you will need to update your call to use the new API.
Change this:
bud.reactRefresh(true)
to this:
bud.react.refresh.enable()
Depending on your project you may be able to use typescript without babel. Why not try it and find out?
bud.typescript.useBabel(false)
If you disable babel react-refresh will be enabled using the react-refresh-typescript
compiler plugin instead.
If you have installed this extension directly to your project you can remove it.
If you are using the new SWC extension terser will automatically be configured to use the swc minifier.
There was an issue with client scripts not being injected in zero configuration setups (more specifically: any setup that didn't explicitly set entrypoints with bud.entry).
It's been corrected; see #1506 for details
bud typecheck
TypeScript users can call bud typecheck
to run typechecking outside of compilation. There are a couple requirements, at least for this initial effort:
typescript
installedtsconfig.json
in your project rootThis is honestly not much more than a tsc --noEmit
alias right now.
But, it might be useful for you as-is and it will get better and more useful in future releases.
Thanks to @robrecord for a nice set of documentation fixes.
Published by kellymears over 2 years ago
For more information refer to the the v6.1.0 release notes on bud.js.org.
This release makes some changes to bud.assets in response to feedback from the roots/sage team and members of the Roots Discourse community. Specifically, you will find that directories listed in the bud.assets
call will have their structure preserved in the @dist
directory.
After upgrading, it is possible that assets will be emitted to a different directory than you expect. Likely you are anticipating that copied files will be available in the root of @dist
and are finding them now in a subdirectory.
You can specify the dist root as a target to compensate for the change:
// from this (will copy from images dir to dist/images)
bud.assets(['images'])
// to this (will copy from images dir to dist)
bud.assets([['images', './']])
bud.assets is no longer variadic. If you are specifying copy jobs using multiple parameters just wrap them in an array:
// from this
bud.assets('images', 'fonts')
// to this
bud.assets(['images', 'fonts'])
bud.denylist
Bud extensions are automatically utilized in a build if they are listed under the devDependencies
or dependencies
field of package.json
.
They are also automatically utilized when marked as a dep of another extension.
You can add a bud.denylist
field to package.json
to prevent certain extensions from being registered, regardless.
{
"bud": {
"denylist": ["@roots/bud-criticalcss"]
}
}
There is also a bud.allowlist
to whitelist extensions. You should be aware that there are many internal extensions, and things may break if they are not available. If you run a build with the --log
flag the tapped extensions will be summarized at the bottom, but it's probably better to use bud.denylist
.
@roots/bud-preset-recommend
@roots/bud-esbuild
over @roots/bud-babel
when possibleThe @roots/bud-preset-recommend
extension will check to see if @roots/bud-esbuild
is available before registering @roots/bud-babel
.
This didn't cause errors prior to 6.1.0, but it did have a cost in terms of build time for users of @roots/bud-preset-recommend
who wanted to use @roots/bud-esbuild
iorf @roots/bud-typescript
instead of @roots/bud-babel
.
A few changes here:
domReady
now async compatibleThe domReady
named export of @roots/sage/client
can now take an async callback:
import {domReady} from '@roots/sage/client'
domReady(async () => {
// do async stuff
})
theme.json
features⚠️ If you were already using bud.js to generate theme.json
for WordPress, you will need to update your call.
All the methods are now housed under bud.wpjson
. You must also call bud.wpjson.enable
in order to actually emit the file.
bud.wpjson
.useTailwindColors()
.settings(theme => {
theme.set('prop')
})
.enable()
theme.json
In addition to the theme color palette, you can now generate font sizes and font families from tailwind.config.js
using bud.wpjson.useTailwindFontSize
and bud.wpjson.useTailwindFontFamily
.
app.wpjson
.useTailwindColors()
.useTailwindFontSize()
.useTailwindFontFamily()
.enable()
You can also modify fields which are not under the settings
key using the standard extension API's setOptions
method:
// callback
app.wpjson.setOptions(opts => ({
...options,
customTemplates: [],
}))
// literal
app.wpjson.setOptions({
// using without a callback
// will fully override theme.json
...app.wpjson.options,
})
Check the updated @roots/sage docs for additional usage guidance.
The fix for this issue is pretty in the weeds but you can read about it in #1492.
@roots/bud-eslint
incompatible with filesystem cachingPreviously users of @roots/bud-eslint
needed to use bud.persist('memory')
in order to guarantee linting worked as expected. This is no longer the case thanks to #1492.
For more information review the diff to see what's changed.
Published by kellymears over 2 years ago
This major release transitions bud.js to ESM. It also provides some cool new features (like importing from remote sources), but we'll mainly be talking about the new ESM syntax.
Read the official announcement on bud.js.org.
The transition to EcmaScript modules is causing a lot of division and drama in the JS world, at the moment.
Having just finished transitioning all of the nearly 50 packages that make up the bud.js monorepo to use
ESM I can say in all honesty that I totally get it. It was a very frustrating experience.
Which is to say, whatever problems come up with this release, let's work together as a community to help one another
get through it. There will be problems. I hope not a lot, but this is the type of transition that happens every twenty
years, maybe. And I can assure you, on the other side of throwing require
out the window, it feels good to be on the
future-facing side of a great schism like this one.
I hope the appeal for solidarity wasn't too spooky because the good news is that, for the vast majority of
bud.js users, not much is required here.
See "that sindresorhus README" for more context.
There are three upgrade paths available to JS users:
.cjs
extension.mjs
extensionThings are a litle different for users with configuration files authored in TypeScript, and we'll get to that.
.cjs
extensionThis is the simplest possible path forward. Update bud.config.js
to bud.config.cjs
.
Caveat: you cannot require
code from @roots/bud
or any first-party extension. Mostly bud.js is structured so
this isn't a normal use case, but if you are using a require statement you'll want to read up on
how to import esm from commonjs.
.mjs
.This is probably my recommended approach. Update bud.config.js
to bud.config.mjs
.
Update your config function to use the ESM export
syntax:
module.exports = async bud => bud.entry('app', 'index')
becomes:
export default async bud => bud.entry('app', 'index')
This is the most involved approach. There is no way I can cover it fully in this release post. But, I will try to sketch it out:
First, add a type
field to package.json
indicating your project is opting in to ESM:
{
"name": "project",
"type": "module"
}
Then update bud.config.js
to use export
syntax as described above.
You will also need to update all other files in your project accordingly. Some build tools allow for using export
syntax. Others do not.
For example, stylelint
does not support export
. So you will update stylelint.config.js
to stylelint.config.cjs
.
Jest, on the other hand, does support export
. You will either want to update your jest config file to use ESM export
syntax or rename it to jest.config.cjs
.
Check the documentation for each tool. Read up on ESM.
bud.config.mts
or bud.config.cts
TypeScript 4.7.2 offers two new TypeScript extensions to deal with CJS/ESM compatibility issues: .cts
and .mts
(they have their own declaration file extensions as well: .d.cts
and .d.mts
).
In general, I'd imagine most TS users already author their bud.config.ts
file with export
syntax. If that's the case, you will likely just want to update the file name to bud.config.mts
.
ts-bud
instead of bud
Due to the way ESM modules are loaded you'll need to use ts-bud
instead of bud
when running cli commands. Explanation follows:
A problem with TypeScript and ESM: it is not possible to hack import
at runtime the way we can hack require
at runtime.
bud.js uses ts-node to import TS configs when it is available, but with ESM we also need to register an import
loader so that the config file can be parsed. This can't be done at runtime.
ts-node offers a flag to set this up:
ts-node --esm --transpileOnly
And bud.js offers a bin
that wraps the standard bud
command accordingly: ts-bud
. Use it instead of bud
.
If this doesn't work for you, or you need to adjust other ts-node
flags, you may do this yourself:
ts-node --esm --transpileOnly ./node_modules/.bin/bud build
bud.typescript.typecheck.enable()
will die when using ts-bud
It is unclear what the problem is as of right now (see #1480). In order to enable typechecking you must author your config file in JS until this is resolved.
For the most part this shouldn't be an issue. It isn't typical to import or require bud.js code from a project config.
There are exceptions however. For example, if you are using the bud.js node api to generate a config for use with the webpack-cli
.
require
statements to import
If you are writing a config file with .mjs
or you have opted in with "type": "module"
, you will no longer
be able to require
modules or packages in your config file.
The great news is that it's totally possible import CommonJS from an ES Module, so you can convert require
statements to use import
without worrying about it too much:
const value = require('browsersync-webpack-plugin')
becomes:
import value from 'browsersync-webpack-plugin'
:::danger
You absolutely cannot require
bud.js core. No CommonJS exports are offered.
:::
Importing ESM from CommonJS is a little less straight forward than the other way around. This is one of the reasons we recommend converting your config to .mjs
.
The easiest way is to use a dynamic import
statement. The biggest difference is that a dynamic import is asynchronous, whereas require is sync.
export default async bud => {
await import('browsersync-webpack-plugin')
}
In these cases you may find that the code returned from a dynamic import
is set inside of a property called default
.
bud.module
helper utilityIf you wish you may use bud.module.import
instead of import
(which will automatically return the value of default
, if it is set):
export default async bud => {
await bud.module.import('browsersync-webpack-plugin')
}
The node:module
interface provides a function createRequire
that will let you directly require CommonJS
code like you may be used to. See the nodejs docs on createRequire
.
bud.js has an instance of the Require
function available at bud.module.require
(it's context is the directory containing the project package.json
):
export default async bud => {
bud.module.require('browser-sync-webpack-plugin')
// require.resolve works too
bud.module.require.resolve('browser-sync-webpack-plugin')
}
If you just want the path to a module and aren't sure if it is CommonJS or ESM, you may use bud.module.resolve
:
export default async bud => {
await bud.module.resolve('browser-sync-webpack-plugin')
}
This functionality is provided using the import-meta-resolve
package. In the future we'll use the import.meta.resolve
API directly but right now it is labeled as experimental
and requires a flag.
@roots/wordpress-hmr
. Greatly simplifies block editor development for WordPress friends. I'm not sure where this fits into the docs yet, but there is usage information available on this page for now.esm
. This feature is not yet documented and should be considered experimental. You can try it out with bud.esm.enable()
, but roots/sage users in particular should be aware that this will./extension
(eg: @roots/bud-react/extension
).stylelint
and eslint
presets are exported with the .cjs
extension. If your eslint or stylelint config is already using the preset without an extension (as documented) you don't have to do anything. If you are specifying .js
you will need to update it.lib
and types
directories for all packages have been merged.es2021
. Update to node 16 if you are running an outdated version of node.@roots/bud-support
is deprecated@roots/bud-library
is deprecated (the default caching configuration is now better than this extension)For more information review the diff to see what's changed.
Published by kellymears over 2 years ago
Some minor improvements to the @roots/bud-terser
extension and a fix for projects with development
and production
in the project path. Recommended for all users of 5.8.x.
This release also updates many dependencies. Compare v5.8.6 and v5.8.7 to see the full list of what got bumped.