Skip to content
/ bud Public

Commit 6e4f6c9

Browse files
authored
✨ improve(patch): improve facades (#2504)
- 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**
1 parent c3b224f commit 6e4f6c9

File tree

20 files changed

+206
-66
lines changed

20 files changed

+206
-66
lines changed

examples/babel/bud.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// @ts-check
12
/**
23
* @param {import('@roots/bud').Bud} bud
34
*/

examples/config-yml/bud.config.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@ runtime: true
1414
assets:
1515
- ['src/**/*.html']
1616

17-
# Inner properties of bud are fair game
17+
# You can access inner properties
1818
babel:
1919
setPluginOptions:
2020
- '@babel/plugin-transform-runtime'
2121
- {helpers: true}
2222

23+
# You can use dot notation
24+
babel.setPluginOptions:
25+
- '@babel/plugin-transform-runtime'
26+
- {helpers: true}
27+
2328
# prefix bud properties with _
2429
# to reference the value
2530
splitChunks: _bud.isProduction

sources/@roots/bud-api/src/index.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,39 @@ declare module '@roots/bud-framework' {
162162
/**
163163
* ## bud.hash
164164
*
165+
* Hash output filenames
166+
*
165167
* {@link https://bud.js.org/docs/bud.hash 📕 Documentation}
168+
*
169+
* @example
170+
* Enable:
171+
* ```js
172+
* bud.hash()
173+
* ```
174+
*
175+
* @example
176+
* Disable:
177+
* ```js
178+
* bud.hash(false)
179+
* ```
180+
*
181+
* @example
182+
* Enable with custom format:
183+
* ```js
184+
* bud.hash('contenthash:8')
185+
* ```
186+
*
187+
* @example
188+
* Enable with a bud.js callback:
189+
* ```js
190+
* bud.when(bud.isProduction, bud.hash)
191+
* ```
192+
*
193+
* @example
194+
* Transform the existing value:
195+
* ```js
196+
* bud.hash((value) => !value)
197+
* ```
166198
*/
167199
hash(...params: Hash.Parameters): Bud
168200

sources/@roots/bud-api/src/methods/config/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import isFunction from '@roots/bud-support/lodash/isFunction'
66

77
export type Parameters = [
88
| ((config: Partial<Configuration>) => Partial<Configuration>)
9+
| ((config: Partial<Configuration>) => Promise<Partial<Configuration>>)
910
| Partial<Configuration>,
1011
]
1112

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

2930
app.build.config = isFunction(input)
30-
? input(app.build.config)
31+
? await input(app.build.config)
3132
: {...app.build.config, ...input}
3233
})
3334

sources/@roots/bud-api/src/methods/devtool/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const devtool: devtool = async function (
2222
if (input instanceof Bud) {
2323
this.hooks.on(`build.devtool`, FALLBACK_SOURCEMAP)
2424

25-
this.api.logger.success(`bud.devtool`, `devtool set to`, input)
25+
this.api.logger.success(`bud.devtool:`, `devtool set to`, input)
2626

2727
return this
2828
}
Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import {Bud} from '@roots/bud-framework'
1+
import type {Bud} from '@roots/bud-framework'
2+
3+
import {InputError} from '@roots/bud-support/errors'
24

35
export type Value =
4-
| ((hash: boolean | undefined) => boolean)
6+
| ((hash?: boolean) => boolean | string)
57
| boolean
68
| Bud
79
| string
@@ -12,34 +14,70 @@ export interface hash {
1214
(value: Value): Bud
1315
}
1416

15-
export const hash: hash = function (this: Bud, value) {
16-
if (value instanceof Bud || value === undefined) {
17-
this.context.hash = true
17+
export const hash: hash = function (this: Bud, value = true) {
18+
if (typeof value === `boolean`) {
19+
return setHash(this, value)
20+
}
21+
22+
if (value instanceof this.constructor) {
23+
return setHash(this, true)
24+
}
1825

19-
this.api.logger.success(`bud.hash: hash set to`, this.context.hash)
26+
if (typeof value === `function`) {
27+
value = value(this.context.hash)
2028

21-
return this
29+
if (typeof value !== `boolean` && typeof value !== `string`)
30+
throw new InputError(`bud.hash: invalid input`, {
31+
details: `callbacks supplied to bud.hash should return a boolean or a string value`,
32+
docs: new URL(`https://bud.js.org/reference/bud.hash`),
33+
thrownBy: `@roots/bud-api/methods/hash`,
34+
})
35+
36+
if (typeof value === `string`) {
37+
setHash(this, true)
38+
setFormat(this, value)
39+
return this
40+
}
41+
42+
return setHash(this, value)
2243
}
2344

2445
if (typeof value === `string`) {
25-
if (!value.startsWith(`[`)) value = `[${value}]`
46+
setHash(this, true)
47+
return setFormat(this, value)
48+
}
2649

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

30-
this.api.logger
31-
.success(`bud.hash: hash set to`, this.context.hash)
32-
.success(
33-
`bud.hash: hash format set to`,
34-
this.hooks.filter(`value.hashFormat`),
35-
)
57+
const formatHashString = (value: string): string => {
58+
if (!value.startsWith(`[`)) value = `[${value}`
59+
if (!value.endsWith(`]`)) value = `${value}]`
60+
return value
61+
}
3662

37-
return this
38-
}
63+
const setFormat = (bud: Bud, value: string): Bud => {
64+
value = formatHashString(value)
65+
66+
bud.hooks
67+
.on(`value.hashFormat`, value)
68+
.api.logger.success(`bud.hash: hash format set to`, value)
69+
70+
return bud
71+
}
3972

40-
this.context.hash = this.maybeCall(value, this.context.hash)
73+
const setHash = (bud: Bud, value: boolean): Bud => {
74+
bud.context.hash = value
4175

42-
this.api.logger.success(`bud.hash: hash set to`, this.context.hash)
76+
bud.api.logger.success(
77+
`bud.hash:`,
78+
`hash`,
79+
value ? `enabled` : `disabled`,
80+
)
4381

44-
return this
82+
return bud
4583
}

sources/@roots/bud-api/src/methods/minimize/index.ts

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,54 @@ export interface minimize {
1313
}
1414

1515
export const minimize: minimize = function (this: Bud, value = true) {
16+
/**
17+
* Handle {@link Bud} instances (when used as a callback for something like bud.tap, bud.promise, etc)
18+
*/
1619
if (value instanceof Bud) {
17-
this.minimizers.enable(true)
18-
this.minimizers.js.enable(true)
19-
this.minimizers.css.enable(true)
20+
;[this.minimizers, this.minimizers.js, this.minimizers.css].map(
21+
minimizer => minimizer.enable(true),
22+
)
2023
return this
2124
}
2225

26+
/**
27+
* Handle true, false
28+
*/
2329
if (typeof value == `boolean`) {
24-
this.minimizers.enable(value)
25-
this.minimizers.js.enable(value)
26-
this.minimizers.css.enable(value)
30+
;[this.minimizers, this.minimizers.js, this.minimizers.css].map(
31+
minimizer => minimizer.enable(value),
32+
)
2733
return this
2834
}
2935

36+
/**
37+
* For everything else, enable minimization and reset any state by disabling all minimizers
38+
*/
39+
this.minimizers.enable(true)
40+
this.minimizers.js.enable(false)
41+
this.minimizers.css.enable(false)
42+
43+
/**
44+
* Handle string (`css`, `js`)
45+
*/
3046
if (typeof value == `string`) {
31-
this.minimizers.enable(true)
47+
if (!(value in this.minimizers)) {
48+
throwUndefinedMinimizer()
49+
}
50+
3251
this.minimizers[value].enable(true)
3352
return this
3453
}
3554

55+
/**
56+
* Handle array of strings ([`css`, `js`])
57+
*/
3658
if (Array.isArray(value)) {
37-
this.minimizers.enable(true)
38-
value.map(key => {
39-
this.minimizers[key].enable(true)
59+
if (value.some(prop => !(prop in this.minimizers))) {
60+
throwUndefinedMinimizer()
61+
}
62+
value.map(prop => {
63+
this.minimizers[prop].enable(true)
4064
})
4165
return this
4266
}
@@ -47,3 +71,11 @@ export const minimize: minimize = function (this: Bud, value = true) {
4771
thrownBy: `@roots/bud-api/methods/minimize`,
4872
})
4973
}
74+
75+
const throwUndefinedMinimizer = (): never => {
76+
throw ConfigError.normalize(`Error in bud.minimize`, {
77+
details: `Invalid argument passed to bud.minimize. Minimizer does not exist.`,
78+
docs: new URL(`https://bud.js.org/reference/bud.minimize`),
79+
thrownBy: `@roots/bud-api/methods/minimize`,
80+
})
81+
}

sources/@roots/bud-api/src/methods/persist/index.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ export interface persist {
88
}
99

1010
export const persist: persist = function (this: Bud, type = `filesystem`) {
11-
if (type instanceof Bud) {
12-
this.cache.enabled = true
13-
this.api.logger.success(`bud.cache:`, `set to`, type.cache.type)
14-
return this
15-
}
16-
1711
if (type === false) {
1812
this.cache.enabled = false
1913
this.api.logger.success(`bud.cache:`, `disabled`)
Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import type {Bud} from '@roots/bud-framework'
21
import type {Optimization} from '@roots/bud-framework/config'
32

3+
import {Bud} from '@roots/bud-framework'
4+
45
export type Parameters = [
56
| ((
67
runtime: Optimization.RuntimeChunk | undefined,
78
) => Optimization.RuntimeChunk)
9+
| Bud
810
| Optimization.RuntimeChunk
9-
| undefined,
1011
]
1112

1213
export interface runtime {
@@ -17,8 +18,14 @@ export const runtime: runtime = async function (
1718
this: Bud,
1819
runtime = `single`,
1920
) {
20-
return this.hooks.on(
21+
const value = runtime instanceof Bud || runtime === true ? `single` : runtime
22+
23+
this.hooks.on(
2124
`build.optimization.runtimeChunk`,
22-
runtime === true ? `single` : runtime,
25+
value,
2326
)
27+
28+
this.api.logger.success(`bud.runtime:`, `set to`, value)
29+
30+
return this
2431
}

sources/@roots/bud-api/test/minimize.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ describe(`bud.minimize`, () => {
4848
minimize(value)
4949

5050
expect(spies.pop()).toHaveBeenCalledWith(true)
51-
expect(spies.pop()).not.toHaveBeenCalled()
51+
expect(spies.pop()).toHaveBeenCalledWith(false)
5252
expect(spies.pop()).toHaveBeenCalledWith(true)
5353
})
5454

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

6565
expect(spies.pop()).toHaveBeenCalledWith(true)
6666
expect(spies.pop()).toHaveBeenCalledWith(true)
67-
expect(spies.pop()).not.toHaveBeenCalled()
67+
expect(spies.pop()).toHaveBeenCalledWith(false)
6868
})
6969

7070
it(`should return bud`, () => {

0 commit comments

Comments
 (0)