Skip to content

Releases: roots/bud

6.13.1

14 Jun 06:06
Compare
Choose a tag to compare

A feature rich (and mostly backwards compatible) set of improvements and fixes for bud.js.

⚠️ Potentially breaking changes

  • single runtimeChunk now enabled by default.
  • @roots/bud-eslint: warnings are not treated as errors by default.
  • @roots/bud-eslint: errors will cause files to not emit in production.
  • @roots/bud-stylelint: warnings are not treated as errors by default.
  • @roots/bud-stylelint: errors will not emit in production.
  • @roots/wordpress-theme-json-webpack-plugin: exported type Theme renamed to Schema.
  • @roots/bud-terser: is replaced by @roots/bud-minify.
    • you do not need to include this in your project; it is a transitive dependency of @roots/bud.
    • bud.terser deprecated in favor of bud.minify.js
    • bud.minimizeCss deprecated in favor of bud.minify.css

Core features

Enhanced support for tsconfig.json

You can now configure @src, @dist, compilation paths and aliases directly in tsconfig.json. Also works with jsconfig.json. This is nice for compatibility with the typescript compiler.

This feature is opt-in for now but will likely become a default in bud v7. To opt in set bud.useCompilerOptions to true in the config.

tsconfig key value
compilerOptions.baseUrl Set @src directory
compilerOptions.outDir Set @dist directory
compilerOptions.paths Set bud path handles and aliases
include Directories containing modules which should be treated as source. Same as calling bud.compilePaths

Example annotated tsconfig.json

{
  "extends": ["@roots/bud/config/tsconfig.json"],
  "compilerOptions": {
    /**
     * Source directory
     *
     * @remarks
     * This is the same as calling `bud.setPath(`@src`, `sources`)
     */
    "baseUrl": “sources",

    /**
     * Output directory
     *
     * @remarks
     * This is the same as calling `bud.setPath(`@dist`, `build`)
     */
    "outDir": “build",

    /**
     * Path aliases
     *
     * @remarks
     * This is the same as calling `bud.setPath()` and `bud.alias()`
     * Only the first path in each value will be used.
     */
    "paths": {
      "@fonts": ["fonts"],
      "@images": ["images"],
      "@scripts": ["scripts"],
      "@styles": ["styles"]
    },

    /**
     * Include type definitions
     */
    "types": [
      "@roots/bud",
      "@roots/bud-react",
      "@roots/bud-postcss",
      "webpack/module" // defines import.meta.webpackHot
    ]
  },

  /**
   * Configuration files
   */
  "files": ["bud.config.ts"],

  /**
   * Compiler paths
   *
   * @remarks
   * This is the same as calling bud.compilePaths()
   */
  "include": ["resources"],

  /**
   * Allow bud to reference tsconfig/jsconfig values
   */
  "bud": {
    "useCompilerOptions": true
  }
}

TSC compatible module imports

With the TypeScript Compiler you can ensure your outputted code is compliant with esmodules by mapping extensions in your import statements. For example, if you want to import a module from ./some-module.ts, you would likely want to import it like this:

import someModule from './some-module.js'

bud.js works the same way now, in practice. Now, if you want to write your import statements in a way that is compliant with TSC, you can.

bud.setPath now automatically sets aliased paths

If you set a path handle with bud.setPath it now sets up a path alias as well.

JSON schema available

JSON schema available at https://bud.js.org/bud.package.json. You can optionally add it to package.json for validation of package.json fields (including bud specific ones):

{
  "$schema": "https://bud.js.org/bud.package.json"
}

Improved extension options API

Every registered extension option now has a dedicated getter and setter. The getter prefixes the option key with get and the setter prefixes it with set.

Option Getter Setter
bud.extension.optionName bud.extension.getOptionName() bud.extension.setOptionName(value)

Lastly, know that the setOptionName always accepts a callback:

bud.extension.setOptionName(value => value)

Example

Let's say @roots/bud-eslint has a new option defined (since it does):

lintDirtyModulesOnly: EslintPluginOptions['lintDirtyModulesOnly']

Previously you could get this value like so:

bud.eslint.get(`lintDirtyModulesOnly`)

That still works, but now you have some additional options:

/** Get the value via a property */
bud.eslint.lintDirtyModulesOnly
/** Get the value via a function */
bud.eslint.getLintDirtyModulesOnly()

Similarly, in addition to bud.eslint.set:

bud.eslint.set(`lintDirtyModulesOnly`, true)

You can now set it with a dedicated setter method:

bud.eslint.setLintDirtyModulesOnly(true)

All such setter methods accept a callback:

bud.eslint.setLintDirtyModulesOnly(value => !value)

@roots/bud-postcss

  • The postcss configuration API has gotten a rework.

Refer to the updated documentation for more information.

@roots/bud-eslint

  • New options and methods exposed by bud.eslint
  • Configure eslint in your bud config

Refer to the updated documentation for more information.

@roots/bud-sass

  • New options and methods exposed by bud.sass

Refer to the updated documentation for more information.

@roots/bud-stylelint

  • New options and methods exposed by bud.stylelint
  • Configure stylelint in your bud config

Refer to the updated documentation for more information.

@roots/bud-swc

  • New options and methods exposed by bud.swc
  • Override base configuration for js and ts separately

Refer to the updated documentation for more information.

@roots/bud-tailwindcss

  • New options and methods exposed by bud.tailwind
  • Supports configuring tailwindcss directly in bud config

Refer to the updated documentation for more information.

@roots/bud-wordpress-theme-json

  • New options and methods exposed by bud.wpjson

Other changes

  • experiments.backCompat now set to false. bud doesn't need backwards compatibility with webpack 4 and the compatibility fixes come with performance penalties related to Array objects.
  • snapshot.buildDependencies uses a hash if bud.env.get('CI') is true; uses a timestamp otherwise.
  • snapshot.module uses a hash if bud.env.get('CI') is true; uses a timestamp otherwise.
  • snapshot.resolve uses a hash if bud.env.get('CI') is true; uses a timestamp otherwise.
  • snapshot.resolveBuildDependencies uses a hash if bud.env.get('CI') is true; uses a timestamp otherwise.
  • resolveLoader.alias defined for all registered loaders.
  • resolve.unsafeCache set to undefined (was false). default behavior is for unsafeCache to be used in development, and not used in production.
  • profile now set to true if --debug flag is true.
  • performance now set to false (was {hints: false}).
  • externalsType set to undefined (was var).
  • bud.context.logger is removed.
  • APP_TITLE fallback set for projects which use bud.html.
  • NO_SCRIPT fallback set for projects which use bud.html.
  • Typings for WordPress theme.json updated using current schema.
  • Build script now in place to help with future updates to WordPress theme.json.
  • Default css minimizer is now lightningcss (css parser used by parcel).
  • If using @roots/bud-swc css minification is handled by swc.
  • If using @roots/bud-esbuild css minification is handled by esbuild.
  • New documentation for bud.minify.

6.12.3

11 May 00:48
Compare
Choose a tag to compare

Bugfixes and bumped dependencies

Improvements

#2243 improves compatibility with pnpm

This change finishes work started in 6.12.2 make it less necessary to use the bud.js .pnpmfile.cjs compatibility shim.

You should also now be able to limit hoisting to @roots packages, if desired:

pnpm install --public-hoist-pattern="@roots/*"

When only hoisting @roots/* packages you will need to make sure your app dependencies are explicitly defined. Rule of thumb: if you import it in your app you will need to have it installed in your project.

The alternative is to hoist everything (same behavior as npm and yarn):

pnpm install --public-hoist-pattern="*"

Fixes

  • Fixes module resolution cache validation when swapping package managers.
  • Fixes issue with eslint not outputting to stdout/stderr in some configurations.

6.12.2

30 Apr 23:19
Compare
Choose a tag to compare

Adds cached module count to dashboard output for greater transparency into what is being recompiled in development.

6.12.1

26 Apr 00:37
Compare
Choose a tag to compare

Minor release with improvements and fixes for package resolution and caching

Fixes

Failure installing custom TypeScript version with yarn

Fixes an error encountered when trying to install a custom version of TypeScript while using @roots/bud-typescript with yarn classic. See #2216.

This issue is actually an upstream bug in yarn. But, our response sidesteps it and also improves compatibility with pnpm.

The short version: we don't need to declare typescript as a peer dependency because of changes to bud.module made in bud v6. It will always try to resolve from the project context before using the built-in as a fallback.

So, even without peer dependencies defined by the extension, the following call (when made from the @roots/bud-typescript context) will always try and resolve the module first from node_modules/typescript, and then node_modules/@roots/bud-typescript/node_modules.

bud.module.resolve(`typescript`, import.meta.url)

The change that fixes #2216 has also been applied to @roots/bud-eslint and @roots/bud-babel. We'll apply it to other packages which use peerDependencies in future releases.

Improvements

Include eslint and tailwind configs in build dependencies

#2233 Include tailwind & eslint configs in cached build dependencies adds discovered tailwind and eslint configs to the map of files the compiler uses to validate the cache. Hopefully changes made to your tailwind config will now be more reliably reflected in your next build without having to use the --force flag. Additionally, only modules related to the changed config will be invalidated, which will be much faster than wiping everything.

Prevent invoking multiple esbuild and/or esbuild-wasm modules

When transforming configuration modules authored in TypeScript bud.js will now prefer esbuild or esbuild-wasm as defined by package.json, if they are included. The built-in esbuild-wasm included in @roots/bud-support is used as a fallback. This should be a minor improvement for users who are using esbuild in some other way as part of their build.

Vendor bind decorator from helpful-decorators.

helpful-decorators is an awesome package but we are only using bind from it and it is used in a lot of places. This change eliminates the (modest) overhead associated with all the unused modules.

v6.12.0

03 Apr 08:24
Compare
Choose a tag to compare

Framework improvements, eslint fixes, better config directory support, and more.

📦 tailwindcss 3.3.0 supported

bud.js now supports the new configuration options from tailwindcss 3.3.0. tailwind configs can now be authored with typescript or esm.

🧹 default storage location: .budfiles -> os cache dir

Less junk in your project is always good, right? The new default @storage directory is now [os-cache dir]/bud-nodejs/[hash of project path].

Breaking change: If you are explicitly setting the @storage directory you need to do it using the --storage CLI flag or the APP_STORAGE_PATH .env variable. By the time config files have been processed most reads and writes to @storage will have already occurred, so bud.setPath won't be effective. There will be a warning logged to the console if you are doing this; the main adverse effect will be slower builds when bud.js can't find caches during bootstrapping.

Potentially breaking change: If you are using remote modules (which lets you import modules from cdns like skypack without installing locally) the bud.lock lockfile will now be written to the root of your project (unless you have configured it to be written somewhere else).

✨ Config files can be written in TypeScript (without extensions)

bud.js configuration files can now be authored in typescript without installing any additional extensions. if you were previously using the ts-bud binary you still can (it executes the bud.js runtime with ts-node), but you can now just use the standard bud command (it is faster). ts-bud remains available in case you were doing some deeper integration with ts-node.

The parsing of TypeScript configs is handled with esbuild-wasm. I have not been able to measure a meaningful difference in timings using this package instead of esbuild and the wasm binary doesn't need to be built so installs are a lot faster. However, if you want to use esbuild instead of esbuild-wasm you can install esbuild as a project dependency and it will be used instead. Again, I don't think it's worth the extra installation time. Especially since the results of config transforms are cached.

This also applies to eslint, tailwindcss, postcss and babel configs.

✨ Config files can be stored in ./config directory

bud.js configuration files can now be stored in the config directory. This also applies to eslint, tailwindcss, postcss and babel configs.

✨ @roots/bud-eslint: upgrade eslint-webpack-plugin to v4

eslint-webpack-plugin@4 removes need for eslint cache fix

If you were disabling the fix with bud.eslint.cacheFix.enable(false) before you will be prompted to remove that call, as it is now deprecated.

See #2191

🏎️ performance: module resolution caching

Module paths resolved by bud.module are cached to [cachedir]/resolutions.yml. This gives a nice performance boost since we can skip a lot of lookups:

The resolve and import methods used by bud.module treat built-in dependencies as fallbacks. So, if you aren't overriding any built-in dependencies and the cache is valid the net result is more than half as many calls to importMetaResolve and import statements.

  • sha1 hashes are calculated for files in root and config/* and an artifact is output to [cachedir]/checksum.yml.
  • Hash mismatches in config files or package.json will invalidate the bud.module resolver cache and the compiler cache.

🏎️ performance: reuse context & bud instances

bud.context is now re-used between bootstrap scripts and the cli application.

✨ improve: unified error handling

Now extending modern-errors for unified error handling.

🩹 fix: no postinstall scripts in CI

There are some reliability issues with postinstall scripts (for @roots/bud-framework and @roots/browserslists-config) running in CI.

This update disables postinstall scripts when process.env.CI is set (default for gh actions).

See #2169

✨ improve(@roots/eslint-config): remove react-in-jsx-scope

This rule is not really appropriate as a default for modern React.

See #2154

👩‍🔬 experimental: pnpm support

Installs with pnpm should work now. They may break again in the future, but we're closer to being able to claim full compatibility. You must install with public hoisting:

pnpm install --public-hoist-pattern=*

pnpm installs peers by default as of pnpm v8 🎉, so we suspect that compatibility will be a lot better once people upgrade.

📦 upgrade ink to v4

A ton of workarounds were required to make ink work prior to this upgrade. It's now compatible with react 18 and fully esm 🎉.

📕 Documentation improvements

  • Thanks to @chrillep for improving the @roots/bud-eslint documentation example config
  • Adds documentation for bud.config
  • Improves documentation for bud.define
  • Adds pnpm installation instructions to getting started guide

v6.11.0

09 Mar 22:17
Compare
Choose a tag to compare

A bunch of cool features, fixes and improvements.

If you have any trouble installing try the --force flag.

Breaking changes

  • There have been some fixes made to bud.assets which make the function behave much more predictably. Still, I'm concerned there might be workarounds people are using which will no longer be working around. Check out the documentation and consider replacing complex bud.assets calls with the new bud.copyFile and bud.copyDir functions.

  • If you are configuring bud.js with JSON or YML you will need to update any functions which accept a single argument which is an array. bud.config.json and bud.config.yml arguments are now expressed as an array, so there is no good way for the config parser to determine that you actually wanted to pass an array and not multiple params.

    assets: 
    -  - 'image.jpeg'
    +  - ['image.jpeg']
  • If you have been using the new blade view directives in your Sage project you will need to update them. There is now a single directive to replace all previous directives: @module. So, @js import '@scripts/confetti.js' @endjs becomes @module('js') import '@scripts/confetti.js' @endmodule. This should support all module types now, generically. Built-in support for this feature is still in process for roots/acorn. An example ModuleDirective and EndModuleDirective class have been updated and included in @roots/blade-loader/vendor.

    -@js
    +@module('js')
    console.log('hello')
    -@endjs
    +@endmodule

Deprecations

A bunch of extension functions are going to be removed at some point in the future (bud.js 7). Most of these are simple wrappers for the built-in extensions API.

If you are using a deprecated function you can expect IDE notifications (if you use an IDE that supports the @deprecated doctype), but you will also see warnings in the terminal with specific instructions for how to update the call.

We'll go slow when removing these functions; don't fret about it. This github issue (#2079) is dedicated to tracking related function deprecations.

Improved WordPress editor support

Easily add blocks, plugins, filters, styles, variations and formats in production and development with next to no boilerplate along with full hot module reloading (HMR) support.

See the updated documentation for specifics on implementing it in your WordPress project. There is also a new example in the examples directory to get a feel for how it comes together.

This feature is new so I suspect early adopters may bump into issues. But, we've been using the underlying library that powers this for many months now and it seems to work quite well in-house.

Improved yml and json config support

See the updated documentation. Short version: anything you can do in a js file you can now do in a yml file.

New functions for copying files

These two functions are a lot more predictable for you and will be a lot easier to maintain for me. I'd recommend replacing bud.assets with them (although I've tried to do what I can to improve it in this release).

bud.copyDir

See documentation for details.

bud.copyFile

See documentation for details.

Improved errors

There is better error handling in a few critical areas. Hopefully you'll never notice.

Early errors

Ever make a syntax error in your bud.config.js file? Me neither. But if I did the error would happen before bud.js (and it's logger) had even been instantiated.

Not anymore!

Error reading config file:
bud.config.mjs appears to be a bud config file, but it could not be imported.

Original error follows:
SyntaxError: Unexpected token '}'
    at file:///bud/sources/@roots/bud/lib/context/config.js:62:31
    at async Promise.all (index 4)

bud.when errors

If you pass a non-function argument to bud.when it will throw an error now. I've seen a few people do this and it's an understandable mistake. I'm sorry for the error but it wasn't doing what you wanted before.

This is the specific mistake I saw most recently.

/* This will now throw */
bud.when(
  bud.isProduction, 
  bud.minimize(), // oops!
)

The problem is that the function is being called right there! It's whatever value the function returns by the time bud.when receives it. It doesn't cause a type error but it's obvious something is wrong.

The corrected version would just wrap the bud.minimize() call in an arrow function:

bud.when(
  bud.isProduction, 
  () => bud.minimize() // corrected
)

Anyway, there will be instructions in the console if you are bit by this.

Unsupported platform errors

If you run bud.js on Windows outside of a WSL environment, it won't try and stop you, but it also won't work. This is mentioned in both the project README.md and our Getting Started guide, and yet many people still post support requests related to errors experienced while using Windows.

Now, errors are accompanied by a reminder that the platform is not supported, which should hopefully reduce support request volume.

If you use Windows and want to see native support for Windows in bud.js please submit an issue and accompanying PR!

Improve bud doctor

bud doctor now displays additional information about the project and has a couple new checks.

Fix: sass/vue/sage (in combination)

Fixes an issue that could create blank stylesheets (with no error thrown from vue-loader). Adds reproduction to prevent regressions.

Fix: @roots/bud-prettier format command

Thanks to @nlemoine for fixing the bud format command.

Docs contributions

Big thanks to @dsturm for their continued work improving bud.js' documentation 🙏🏼.

v6.9.1

08 Feb 05:54
Compare
Choose a tag to compare

Bugfix release for 6.9.

🩹 fix(@roots/bud-swc): tree shaking #2089

Fixes problem described in #2088. Adds reproduction and unit test to help guard against regressions.

🔧 fix: normalize paths #2086

Replaces several bespoke functions with node:path equivalents.

v6.9.0

06 Feb 02:04
Compare
Choose a tag to compare

An easy helper for dealing with uncompiled modules, dot notation getters and setters for extension options, and a bugfix for the typescript+vue support introduced in 6.8.0

🩹 fix: vue/typescript #2082

Moves css, scss,ts rules out of oneOf and into the top-level module.rules array.

Fixes:

✨ feature(@roots/bud): bud.compilePaths #2083

bud.compilePaths is used to specify directories which should be treated as source directories. This serves as a simple replacement for the instructions found in the compiler sources guide.

If you have errors which say something along the lines of You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file., this is probably the function you want to use to fix that.

Example adding support for the swiper lib:

export default async bud => {
  bud.compilePaths([
    bud.path(`@src`),
    bud.path(`@modules/swiper`),
  ])
}

✨ improve(@roots/bud): options api #2078

A small change but a good one. Backwards compatible but it will let us remove a lot of extension methods in bud@7.0.

export default async bud => {
    bud.wpjson
      .set(`settings.color.customDuotone`, false)
      .set(`settings.color.customGradient`, false)
      .set(`settings.color.defaultDuotone`, false)
      .set(`settings.color.defaultGradients`, false)
      .set(`settings.color.defaultPalette`, false)
      .set(`settings.color.duotone`, [])
      .enable()

    bud.tailwind.set(`generateImports`, true)

    bud.typescript
      .set(`appendTsSuffixTo`, [/\.vue$/])
      .typecheck.enable()

    bud.terser
      .set(`extractComments`, false)
      .set(`terserOptions.mangle.safari10`, false)

    bud.vue.set(`runtimeOnly`, false)

    bud.imagemin.sharp
      .set(`encodeOptions.png.quality`, 60)
      .set(`encodeOptions.webp.quality`, 60)
}

Can also retrieve options with get:

bud.vue.get(`runtimeOnly`)

Right now these dot props are not type safe and you may get feedback in your IDE that the option name doesn't exist. More work is roadmapped to address this, but it's very complicated to do dot notation type transformations on generics with recursive or very deeply nested properties.

If this is a problem for you you can do the prop drilling yourself with extension.getOptions() and extension.setOptions().

v6.8.0

02 Feb 07:34
Compare
Choose a tag to compare

Bugfixes, host/container URL mappings and an improved cli experience.

🩹 fix(@roots/bud): remote sources #2057

Fixes issue with modules loaded from registered remote schemas.

🩹 fix(@roots/bud): resolve extensions #2058

Adds missing extensions to set of resolvable extensions.

🩹 fix(@roots/sage): blade loader caching #2065

Improves regular expression used to extract @asset URLs and fixes caching for blade partials. Fixes issues referenced in this discourse topic.

✨ feature(@roots/bud): distinct settings for mapped URLs #2074

This is primarily targeted at docker users (including lando), or really anyone who has need for internal/external URLs for the proxy server, dev server, or both.

Adds the following methods:

  • bud.setProxyUrl
  • bud.setPublicProxyUrl
  • bud.setUrl
  • bud.setPublicUrl

Like bud.serve and bud.proxy they are pretty flexible and support strings, URL instances or numbers (if you only need to specify the port). If you only specify a port the default interface is used (0.0.0.0).

So, a lando user mapping 0.0.0.0 to example.lndo can set it up like so:

export default async bud => {
  bud
    .setUrl(3000)
    .setPublicUrl(`http://example.test:3000`)
    .setProxyUrl(8000)
    .setPublicProxyUrl(`http://example.test`)
}

This is especially useful for replacing URLs in proxy responses since the public URLs will be used for find/replace operations. The hope is that you won't have to handle these manually any longer.

This change should be backwards compatible with the existing bud.proxy and bud.serve functions. They can be used together and there is no plan on deprecating them:

export default async bud => {
  bud
    .proxy('http://0.0.0.0')
    .setPublicProxyUrl('http://example.lndo')

    .serve('http://0.0.0.0:3000')
    .setPublicUrl('http://example.lndo:3000') 
}

✨ feature(@roots/bud-vue): support typescript #2075

Adds automatic support for typescript in vue single file components. You only need to install @roots/bud-typescript and you should be good to go. Adds an example to the examples directory and integration tests to ensure this keeps working as the framework develops.

✨ feature(@roots/bud): improve bud cli #2004

Running bud (no subcommand) presents user with menu of common tasks to select from. bud doctor now displays additional information about the project.

v6.7.3

26 Jan 04:18
Compare
Choose a tag to compare

Fixes bud.fs.read not respecting the 2nd parameter when reading json files #2053