Customizing loaders
The bud.build service allows you to customize the loaders used to process modules.
Adding a rule
The majority of this guide is focused on adding support for additional filetypes to bud.js in a way that is compatible with the rest of the framework and composable with rules added by other extensions.
However, if you just want to add a rule in the context of the bud config file, you might find it easiest to use the build.module.rules.oneOf
hook:
export default async bud => {
bud.hooks.on(`build.module.rules.oneOf`, (rules = []) => {
rules.push({
test: /\.example$/,
use: [
{
loader: `babel-loader`,
options: {
presets: [`@babel/preset-env`],
},
},
],
})
return rules
})
}
If you are authoring an extension, you should use the API described below.
Overview
bud.build divides its handling of loaders into three related objects:
- Loaders — A resolved path to a script which processes source modules
- Items — A loader accompanied by its options
- Rules — One or more items and the rules which dictate what modules they apply to
Loaders
A loader
is the path to a module which handles a code transformation.
All registered loaders are stored in bud.build.loaders
. They are all instances of the bud.js Loader
class.
Modifying loaders
loader[`setSrc`]
Modify the source path of a given loader using Loader[`setSrc`]
bud.build.loaders.babel.setSrc('example')
Examples
With automatic resolution:
export default async bud => {
bud.build.setLoader('babel-loader')
}
With explicit resolution:
export default async bud => {
bud.build.setLoader(
'babel-loader',
await bud.module.resolve('babel-loader'),
)
}
Using the callback API:
export default async bud => {
bud.build.setLoader(
'babel-loader',
loader => loader.setSrc('babel-loader')
)
}
Items
An item
is a loader and associated options. There may be multiple items using a common loader.
All registered items are stored in bud.build.items
. They are all instances of the bud.js Item
class.
Modifying items
item[`setOptions`]
Modify the options of a given item using Item[`setOptions`]
bud.build.items.example.setOptions({})
Item[`setLoader`]
The value given references the handle of a registered loader.
bud.build.items.example.setLoader(`example`)
Examples
Declaratively:
export default async bud => {
bud.build.setItem(`babel`, {
loader: `babel-loader`,
options: {
presets: [`@babel/preset-env`],
},
})
}
Using the callback API:
export default async bud => {
bud.build.setItem(`babel`, item =>
item.setLoader(`babel-loader`).setOptions({
presets: [`@babel/preset-env`],
}),
)
}
Rules
A rule
describes:
- a set of conditions that must be met for the rule to be applied
test
- a regular expression that matches the module's filenameinclude
- a regular expression that must match the module's pathexclude
- a regular expression that must not match the module's path
- a set items which should process the module if it meets the conditions
All registered rules are stored in bud.build.rules
. They are all instances of the bud.js Rule
class. There may be multiple
rules using a common item.
Modifying rules
rule[`setTest`]
Modify the test of a given rule using Rule[`setTest`]
bud.build.rules.example.setTest(/\.example$/)
rule[`setInclude`]
Modify the include of a given rule using Rule[`setInclude`]
bud.build.rules.example.setInclude(/example/)
rule[`setExclude`]
Modify the exclude of a given rule using Rule[`setExclude`]
bud.build.rules.example.setExclude(/node_modules/)
rule[`setUse`]
Modify the items used by a given rule using Rule[`setUse`].
The value given references the handle of a registered item.
bud.build.rules.js.setUse(items => [...items, 'babel'])
Examples
Declaratively:
export default async bud => {
bud.build.setRule(`js`, {
test: /\.js$/,
use: [`babel`],
})
}
Using the callback API:
export default async bud =>
bud.build.setRule(`js`, rule => rule.setTest(/\.js$/).setUse([`babel`]))
In practice
@roots/bud-typescript
@roots/bud-typescript is an excellent example because it:
bud.build
.setLoader(`ts`, await bud.module.resolve(`ts-loader`))
.setItem(`ts`, {
loader: `ts`,
options: {},
})
.setRule(`ts`, {
test: /\.tsx?$/,
include: [bud.path(`@src`)],
use: [`babel`, `ts`],
})
bud.build.rules.js.setUse([`babel`, `ts`])
@roots/bud-vue
In @roots/bud-vue, the vue-loader
is registered, and the js
rule is modified to use it. Unlike the ts-loader
example, the vue-loader
is registered using the chainable API.
bud.build.setLoader(`vue-style-loader`).setItem(`vue-style-loader`)
bud.build.rules.css.setUse(items => [`vue-style-loader`, ...items])
bud.build.rules.sass?.setUse(items => [`vue-style-loader`, ...items])
bud.build.items.precss.setOptions({esModule: false})
bud.build
.makeRule()
.setTest(({hooks}) => hooks.filter(`pattern.vue`))
.setInclude([bud => bud.path(`@src`)])
.setUse(items => [`vue`, ...items])