Skip to content

Commit

Permalink
✨ improve(patch): improve facades (#2504)
Browse files Browse the repository at this point in the history
- feat: `--hash` flag now accepts string for setting hashing algorithm (eg: `--hash=contenthash:4`)
- feat: `--minimize` flag now accepts string for only applying a single minimizer (eg: `--minimize=js` and `--minimize=css`
- improve: `bud.hash`
- improve: `bud.runtime`
- improve: facade logging
- performance: lazy load `terser-webpack-plugin` and `css-minimizer-webpack-plugin` minimizers

## Type of change

**PATCH: backwards compatible change**
  • Loading branch information
kellymears authored Nov 29, 2023
1 parent c3b224f commit 6e4f6c9
Show file tree
Hide file tree
Showing 20 changed files with 206 additions and 66 deletions.
1 change: 1 addition & 0 deletions examples/babel/bud.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-check
/**
* @param {import('@roots/bud').Bud} bud
*/
Expand Down
7 changes: 6 additions & 1 deletion examples/config-yml/bud.config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@ runtime: true
assets:
- ['src/**/*.html']

# Inner properties of bud are fair game
# You can access inner properties
babel:
setPluginOptions:
- '@babel/plugin-transform-runtime'
- {helpers: true}

# You can use dot notation
babel.setPluginOptions:
- '@babel/plugin-transform-runtime'
- {helpers: true}

# prefix bud properties with _
# to reference the value
splitChunks: _bud.isProduction
Expand Down
32 changes: 32 additions & 0 deletions sources/@roots/bud-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,39 @@ declare module '@roots/bud-framework' {
/**
* ## bud.hash
*
* Hash output filenames
*
* {@link https://bud.js.org/docs/bud.hash 📕 Documentation}
*
* @example
* Enable:
* ```js
* bud.hash()
* ```
*
* @example
* Disable:
* ```js
* bud.hash(false)
* ```
*
* @example
* Enable with custom format:
* ```js
* bud.hash('contenthash:8')
* ```
*
* @example
* Enable with a bud.js callback:
* ```js
* bud.when(bud.isProduction, bud.hash)
* ```
*
* @example
* Transform the existing value:
* ```js
* bud.hash((value) => !value)
* ```
*/
hash(...params: Hash.Parameters): Bud

Expand Down
3 changes: 2 additions & 1 deletion sources/@roots/bud-api/src/methods/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import isFunction from '@roots/bud-support/lodash/isFunction'

export type Parameters = [
| ((config: Partial<Configuration>) => Partial<Configuration>)
| ((config: Partial<Configuration>) => Promise<Partial<Configuration>>)
| Partial<Configuration>,
]

Expand All @@ -27,7 +28,7 @@ export const config: config = function (this: Bud, input): Bud {
if (!app) return

app.build.config = isFunction(input)
? input(app.build.config)
? await input(app.build.config)
: {...app.build.config, ...input}
})

Expand Down
2 changes: 1 addition & 1 deletion sources/@roots/bud-api/src/methods/devtool/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const devtool: devtool = async function (
if (input instanceof Bud) {
this.hooks.on(`build.devtool`, FALLBACK_SOURCEMAP)

this.api.logger.success(`bud.devtool`, `devtool set to`, input)
this.api.logger.success(`bud.devtool:`, `devtool set to`, input)

return this
}
Expand Down
80 changes: 59 additions & 21 deletions sources/@roots/bud-api/src/methods/hash/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {Bud} from '@roots/bud-framework'
import type {Bud} from '@roots/bud-framework'

import {InputError} from '@roots/bud-support/errors'

export type Value =
| ((hash: boolean | undefined) => boolean)
| ((hash?: boolean) => boolean | string)
| boolean
| Bud
| string
Expand All @@ -12,34 +14,70 @@ export interface hash {
(value: Value): Bud
}

export const hash: hash = function (this: Bud, value) {
if (value instanceof Bud || value === undefined) {
this.context.hash = true
export const hash: hash = function (this: Bud, value = true) {
if (typeof value === `boolean`) {
return setHash(this, value)
}

if (value instanceof this.constructor) {
return setHash(this, true)
}

this.api.logger.success(`bud.hash: hash set to`, this.context.hash)
if (typeof value === `function`) {
value = value(this.context.hash)

return this
if (typeof value !== `boolean` && typeof value !== `string`)
throw new InputError(`bud.hash: invalid input`, {
details: `callbacks supplied to bud.hash should return a boolean or a string value`,
docs: new URL(`https://bud.js.org/reference/bud.hash`),
thrownBy: `@roots/bud-api/methods/hash`,
})

if (typeof value === `string`) {
setHash(this, true)
setFormat(this, value)
return this
}

return setHash(this, value)
}

if (typeof value === `string`) {
if (!value.startsWith(`[`)) value = `[${value}]`
setHash(this, true)
return setFormat(this, value)
}

this.context.hash = true
this.hooks.on(`value.hashFormat`, value)
throw new InputError(`bud.hash: invalid input`, {
details: `bud.hash accepts a boolean, string, or callback function as input.`,
docs: new URL(`https://bud.js.org/reference/bud.hash`),
thrownBy: `@roots/bud-api/methods/hash`,
})
}

this.api.logger
.success(`bud.hash: hash set to`, this.context.hash)
.success(
`bud.hash: hash format set to`,
this.hooks.filter(`value.hashFormat`),
)
const formatHashString = (value: string): string => {
if (!value.startsWith(`[`)) value = `[${value}`
if (!value.endsWith(`]`)) value = `${value}]`
return value
}

return this
}
const setFormat = (bud: Bud, value: string): Bud => {
value = formatHashString(value)

bud.hooks
.on(`value.hashFormat`, value)
.api.logger.success(`bud.hash: hash format set to`, value)

return bud
}

this.context.hash = this.maybeCall(value, this.context.hash)
const setHash = (bud: Bud, value: boolean): Bud => {
bud.context.hash = value

this.api.logger.success(`bud.hash: hash set to`, this.context.hash)
bud.api.logger.success(
`bud.hash:`,
`hash`,
value ? `enabled` : `disabled`,
)

return this
return bud
}
52 changes: 42 additions & 10 deletions sources/@roots/bud-api/src/methods/minimize/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,54 @@ export interface minimize {
}

export const minimize: minimize = function (this: Bud, value = true) {
/**
* Handle {@link Bud} instances (when used as a callback for something like bud.tap, bud.promise, etc)
*/
if (value instanceof Bud) {
this.minimizers.enable(true)
this.minimizers.js.enable(true)
this.minimizers.css.enable(true)
;[this.minimizers, this.minimizers.js, this.minimizers.css].map(
minimizer => minimizer.enable(true),
)
return this
}

/**
* Handle true, false
*/
if (typeof value == `boolean`) {
this.minimizers.enable(value)
this.minimizers.js.enable(value)
this.minimizers.css.enable(value)
;[this.minimizers, this.minimizers.js, this.minimizers.css].map(
minimizer => minimizer.enable(value),
)
return this
}

/**
* For everything else, enable minimization and reset any state by disabling all minimizers
*/
this.minimizers.enable(true)
this.minimizers.js.enable(false)
this.minimizers.css.enable(false)

/**
* Handle string (`css`, `js`)
*/
if (typeof value == `string`) {
this.minimizers.enable(true)
if (!(value in this.minimizers)) {
throwUndefinedMinimizer()
}

this.minimizers[value].enable(true)
return this
}

/**
* Handle array of strings ([`css`, `js`])
*/
if (Array.isArray(value)) {
this.minimizers.enable(true)
value.map(key => {
this.minimizers[key].enable(true)
if (value.some(prop => !(prop in this.minimizers))) {
throwUndefinedMinimizer()
}
value.map(prop => {
this.minimizers[prop].enable(true)
})
return this
}
Expand All @@ -47,3 +71,11 @@ export const minimize: minimize = function (this: Bud, value = true) {
thrownBy: `@roots/bud-api/methods/minimize`,
})
}

const throwUndefinedMinimizer = (): never => {
throw ConfigError.normalize(`Error in bud.minimize`, {
details: `Invalid argument passed to bud.minimize. Minimizer does not exist.`,
docs: new URL(`https://bud.js.org/reference/bud.minimize`),
thrownBy: `@roots/bud-api/methods/minimize`,
})
}
6 changes: 0 additions & 6 deletions sources/@roots/bud-api/src/methods/persist/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@ export interface persist {
}

export const persist: persist = function (this: Bud, type = `filesystem`) {
if (type instanceof Bud) {
this.cache.enabled = true
this.api.logger.success(`bud.cache:`, `set to`, type.cache.type)
return this
}

if (type === false) {
this.cache.enabled = false
this.api.logger.success(`bud.cache:`, `disabled`)
Expand Down
15 changes: 11 additions & 4 deletions sources/@roots/bud-api/src/methods/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type {Bud} from '@roots/bud-framework'
import type {Optimization} from '@roots/bud-framework/config'

import {Bud} from '@roots/bud-framework'

export type Parameters = [
| ((
runtime: Optimization.RuntimeChunk | undefined,
) => Optimization.RuntimeChunk)
| Bud
| Optimization.RuntimeChunk
| undefined,
]

export interface runtime {
Expand All @@ -17,8 +18,14 @@ export const runtime: runtime = async function (
this: Bud,
runtime = `single`,
) {
return this.hooks.on(
const value = runtime instanceof Bud || runtime === true ? `single` : runtime

this.hooks.on(
`build.optimization.runtimeChunk`,
runtime === true ? `single` : runtime,
value,
)

this.api.logger.success(`bud.runtime:`, `set to`, value)

return this
}
4 changes: 2 additions & 2 deletions sources/@roots/bud-api/test/minimize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe(`bud.minimize`, () => {
minimize(value)

expect(spies.pop()).toHaveBeenCalledWith(true)
expect(spies.pop()).not.toHaveBeenCalled()
expect(spies.pop()).toHaveBeenCalledWith(false)
expect(spies.pop()).toHaveBeenCalledWith(true)
})

Expand All @@ -64,7 +64,7 @@ describe(`bud.minimize`, () => {

expect(spies.pop()).toHaveBeenCalledWith(true)
expect(spies.pop()).toHaveBeenCalledWith(true)
expect(spies.pop()).not.toHaveBeenCalled()
expect(spies.pop()).toHaveBeenCalledWith(false)
})

it(`should return bud`, () => {
Expand Down
3 changes: 2 additions & 1 deletion sources/@roots/bud-framework/src/bud/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,9 @@ export class Bud {
* Await all promised tasks
*/
@bind
public promise(promise: (bud: Bud) => Promise<unknown>) {
public promise(promise: (bud: Bud) => Promise<unknown>): Bud {
this.promised.push(promise)
return this
}

@bind
Expand Down
2 changes: 0 additions & 2 deletions sources/@roots/bud-framework/src/configuration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ class Configuration {
})
})

this.bud.log(`config`, config)

if (!config) {
throw ConfigError.normalize(`No configuration found`, {
file: source,
Expand Down
23 changes: 14 additions & 9 deletions sources/@roots/bud-framework/src/methods/bindFacade.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type {Bud} from '@roots/bud-framework'

import {Bud} from '@roots/bud-framework'
import {BudError} from '@roots/bud-support/errors'
import isFunction from '@roots/bud-support/lodash/isFunction'
import logger from '@roots/bud-support/logger'
Expand All @@ -23,16 +22,15 @@ export const bindFacade: bindFacade = function (key, fn, binding?) {
if (`bind` in fn) fn = fn.bind(binding ?? this)

this.set(key, (...args: Array<any>) => {
logger
.scope(`bud.${key}`)
.log(
`called with args:`,
...args.map(arg => this.fs.json.stringify(arg)),
)
logger.enabled &&
logger
.scope(`bud.${key}`)
.log(`called with args:`, args.map(parseArgs(this)).join(`, `))

this.promise(async () => {
try {
await this.resolvePromises().then(async () => await fn(...args))
await this.resolvePromises()
await fn(...args)
} catch (error) {
throw error
}
Expand All @@ -43,3 +41,10 @@ export const bindFacade: bindFacade = function (key, fn, binding?) {

return this
}

const parseArgs = (bud: Bud) => (arg: any) =>
arg instanceof Bud
? `(bud)`
: typeof arg === `function`
? `(function)`
: bud.fs.json.stringify(arg)
Loading

0 comments on commit 6e4f6c9

Please sign in to comment.