@bluecadet/bldr
v1.1.0
Published
<h1 style="text-align: center;">Bldr 💪</h1> <p style="text-align: center">TL;DR: Bldr is a (very opinionated) configuration based task runner for css, js, sass, and image.</p>
Downloads
384
Keywords
Readme
Installation
We recommend installing Bldr as a project dependency:
npm i @bluecadet/bldr
You can then add scripts to package.json to run commands:
scripts: {
'dev': 'bldr dev',
'build': 'bldr build',
'devOnce': 'bldr dev --once'
}
but you can also install it globally:
npm i -g @bluecadet/bldr
Then run npm run dev
, which will run bldr dev
, etc.
If you need to pass parameters to a script, add --
between the command and the parameter:
npm run dev -- env=SampleEnv
Documentation
- Command Documentation
- Command Option Documentation
- Configuration Overview
- Basic Configuration
- Config documentation
- Processing documentation
- Complete Config Example
Commands
init
$ bldr init
Running init
will run a simple interactive config setup.
dev
$ bldr dev
Running dev
will run postcss and esbuild without minification. Additionally:
- files in
watch
andwatchReload
arrays will be observed and appropriate processes will be ran when files are added/removed/updated based on file type - a browsersync instance will be created. Edit
bldrConfigLocal.js
to add browsersync options as needed.- Set
browsersync.disable
is set to true in the config (see )
- Set
bldr watch
is an alias forbldr dev
build
$ bldr build
Running build
will run postcss and rollup with minification. Rollup will also run babel.
Command Options
--env=some_key
(or -e some_key
)
If the env
object is setup in config, you can run a command with --env=env_key_name
to run that config setup. See env config below.
--once
(or -o
)
For the dev
command only.
Running bldr dev -o
will run a single build of all assets using the dev
settings.
--start
(or -s
)
For the dev
command only.
Running bldr dev -s
will run a single build of all assets before starting up browsersync and watch tasks. By default, bldr dev
does not do this.
Configuration Overview
Bldr relies on a bldrConfig.js
file to point to where files should be sourced, distributed to, and watched.
Bldr was created to allow multiple configurations within bldrConfig.js
based on the need of a project. Config can be setup to either export a single object (see Basic Configuration below), or an object with seperate dev
and build
objects (see Advanced Configuration below).
Bldr can handle processing css, js, sass, and image files. Each of these processes is configured in a key, and can be added or removed as required by the project. Each process configuration requires an object (or array of objects) that point to file sources, destinations, and 'watch' sources.
Basic Configuration
Bldr configuration determines the processes that are ran. At minimum, bldrConfig.js
should export an object:
module.exports = {
// file configuration
}
The following processes can be added:
module.exports = {
css: {
// processes .css files with postcss
},
sass: {
// processes .sass files with node-sass and then postcss
},
js: {
// processes .js files with esbuild (bldr dev) or rollup (bldr build)
},
// Images are no longer optimized but will still be copied
// images: {
// processes image files with imagemin (via imagemin-mozjpeg, imagemin-pngquant, and imagemin-svgo)
// }
}
Each process can also accept and array of config object if multiple file locations should be processed:
module.exports = {
css: [
{
// process config
},
{
// process config
},
]
}
If an array of config objects is present, each config object will be ran as its own process. In other words, if css
is an array, two seperate postcss processes will be ran, one for each configuration object.
Process Configuration Objects
For each process, the following config is required:
{
src: './path/to/src/files/**/*.[ext]',
dest: './path/to/destination/directory/',
watch: [
'./path/to/files/to/watch/**/*.[ext]',
]
}
src
, dest
, watch
configuration
src
config expects a path (string). This path is the 'incoming' path for processing, and should include a file extension as needed for the process. Glob patterns can be used.dest
config expects a path (string). This path is the 'destination' for processing. This is the directory where builds will be created.watch
config is only used in thedev
process, and expects an array of paths (array of strings). These paths will be 'watched' by chokidar.
Example js config:
module.exports = {
js: {
src: './path/to/src/js/**/*.js',
dest: './path/to/destination/js/',
watch: [
'../path/to/other/js/moldules/**/*.js',
]
},
}
Example js config with multiple build locations:
module.exports = {
js: [
{
src: './path/to/theme/src/js/**/*.js',
dest: './path/to/theme/dest/js/',
watch: [
'../path/to/theme/js/moldules/**/*.js',
]
},
{
src: './path/to/child-theme/src/js/*.js',
dest: './path/to/child-theme/dest/js/',
watch: [
'../path/to/child-theme/src/js/moldules/**/*.js',
]
},
],
}
watchReload
config
When running bldr dev
you may want additional files or file types to trigger an automatic reload. To do this, add a watchReload
key with a value of an array to config:
Example basic config:
module.exports = {
css: {
...
},
js: {
...
},
watchReload: [
'./**/*.twig',
'./**/*.html',
'./**/*.php'
]
}
env
config
Projects can have many parts. Some may have just one source for assets, some may have multiple. For example, you may be working on a theme for a CMS, but also need bldr to process assets for a plugin. With env
configuration, you can setup 'environments' with their own process configurations:
module.exports = {
css: [
{
src: './path/to/theme/css/**/*.css',
dest: './path/to/public/css/',
watch: [
'./path/to/theme/css/**/*.css',
'./path/to/other/css/**/*.css'
]
},
{
src: './path/to/plugin/src/css/**/*.css',
dest: './path/to/plugin/build/css/',
watch: [
'./path/to/plugin/src/css/**/*.css',
'./path/to/plugin/style-guide/css/**/*.css'
]
},
],
js: {
...
},
env: {
'themeOnly': {
css: {
src: './path/to/theme/css/**/*.css',
dest: './path/to/public/css/',
watch: [
'./path/to/theme/css/**/*.css',
'./path/to/other/css/**/*.css'
]
},
js: {
...
},
},
'pluginOnly': {
css: {
src: './path/to/plugin/src/css/**/*.css',
dest: './path/to/plugin/build/css/',
watch: [
'./path/to/plugin/src/css/**/*.css',
'./path/to/plugin/style-guide/css/**/*.css'
]
},
js: {
...
},
}
}
}
IMPORTANT NOTE ABOUT ENVIRONMENTS
Each environment key is treated as its own set of configuration. Configuration for each environment is not inherited, or other wise read, from the basic configuration. In other words, each environment needs its own processes defined as needed. This allows you to, for example, run just css in an environment if desired.
If similar config is required in both basic and environment, its best to setup config in variables before the module.exports = {}
in the config file:
const themeCSS = {
src: './path/to/theme/css/**/*.css',
dest: './path/to/public/css/',
watch: [
'./path/to/theme/css/**/*.css',
'./path/to/other/css/**/*.css'
]
};
module.exports = {
css: [
themeCSS,
{
src: './path/to/plugin/src/css/**/*.css',
dest: './path/to/plugin/build/css/',
watch: [
'./path/to/plugin/src/css/**/*.css',
'./path/to/plugin/style-guide/css/**/*.css'
]
},
],
js: {
...
},
env: {
'themeCssOnly': {
css: themeCSS,
}
}
}
CLI commands and env
To use configuration from an env
key, add the env=
(or -e=
) param with a value equal to the key of the env
object you want to run.
Example
// bldrConfig.js
const themeCSS = {
src: './path/to/theme/css/**/*.css',
dest: './path/to/public/css/',
watch: [
'./path/to/theme/css/**/*.css',
'./path/to/other/css/**/*.css'
]
};
module.exports = {
css: [
themeCSS,
{
// some other config
},
],
env: {
'themeCssOnly': {
css: themeCSS,
},
'whateverNameYouWant': {
js: {
// some other config
},
}
}
}
In command line, to use the themeCssOnly
env config, you would run:
$ bldr dev env=themeCssOnly # or bldr dev -e=themeCssOnly
In command line, to use the whateverNameYouWant
env config, you would run:
$ bldr dev env=whateverNameYouWant
Advanced Configuration
Bldr supports dev
and build
configuration keys at the root of the config object. Think of them as bldr command environments.
This allows bldr dev
and bldr build:dev
to have a seperate set of process configurations (via the dev
key) from the process configurations used in bldr build
(via the build
key):
module.exports = {
dev: {
css: {
src: './path/to/src/css/**/*.css',
dest: './path/to/public/css/',
watch: [
'./path/to/src/css/**/*.css',
'./path/to/other/css/**/*.css'
]
}
},
build: {
css: [
{
src: './path/to/src/css/**/*.css',
dest: './path/to/public/css/',
watch: [
'./path/to/src/css/**/*.css',
'./path/to/other/css/**/*.css'
]
},
{
src: './path/to/some-plugin/src/css/**/*.css',
dest: './path/to/some-plugin/build/css/',
watch: [
'./path/to/some-plugin/src/css/**/*.css',
'./path/to/some-plugin/style-guide/css/**/*.css'
]
},
]
}
}
The dev
key can take all settings in the Basic Configuration section. The build
key can as well, but the watchReload
and env
keys aren't needed, as they will not be relevant in the bldr build
processing.
PostCSS config
Configure postcss by adding a postcss.config.js
file to the root of your project. bldr uses postcss-load-config under the hood. As such, make sure to add plugins using the object syntax in the postcss-load-config
documentation here.
In addition to the default context variables of (ctx.env
(process.env.NODE_ENV
) and ctx.cwd
(process.cwd()
)), there is an additional bldrEnv
, which will have the value of the current build command (dev
, build
). Other options based on commands are available in the ctx
object under settings
(such as watch
and once
if applicable)
Again, refer to the postcss-load-config
documentation here for further details.
Process Settings Configuration
In addition to processes, you can also add config to override or add to the default esBuild and Rollup process.
The following configuration options are available:
module.exports = {
processSettings: {
esBuild: {
plugins: [
// Array of esbuild plugins to add (install in your root package.json)
// if `esBuild.overridePlugins` is set to true, this array will replace the default bldr array.
// if not, then these will be added after bldrs default plugin set. See Processing documentation below
],
overridePlugins: false, // set to true to override default bldr plugins
esBuild: require('esbuild'), // overrides bldr version of esbuild. Default: null
},
rollup: {
useBabel: false, // set to true if babel should not be ran
useTerser: true, // set to false if terser should not be ran
babelPluginOptions: {
// see @rollup/plugin-babel options at https://github.com/rollup/plugins/tree/master/packages/babel#babelhelpers)
// default: { babelHelpers: 'bundled' }
},
inputOptions: {
// see rollups inputOptions object at https://rollupjs.org/guide/en/#inputoptions-object
// `file` will automatically be added, so no need to add here
// default additions: { external: [/@babel\/runtime/] }
},
inputPlugins: [
// array of rollup input plugins.
// if `rollup.overrideInputPlugins` is set to true, this array will replace the default bldr array.
// if not, then these will be added after bldrs default input plugin set. See Processing documentation below
],
overrideInputPlugins: false, // set to true to override default bldr plugins
outputOptions: {
// see rollups outputOptions object at https://rollupjs.org/guide/en/#outputoptions-object
// `file` will automatically be added, so no need to add here
},
outputPlugins: [
// array of rollup output plugins.
// if `rollup.overrideOutputPlugins` is set to true, this array will replace the default bldr array.
// if not, then these will be added after bldrs default plugin set. See Processing documentation below
],
overrideOutputPlugins: false, // set to true to override default bldr plugins
rollup: require('rollup') // if you wish to use a specific version of rollup, you can require it here. Default: null
}
}
}
EsBuild
module.exports = {
processSettings: {
esBuild: {
plugins: [
// Array of esbuild plugins to add (install in your root package.json)
// if `esBuild.overridePlugins` is set to true, this array will replace the default bldr array.
// if not, then these will be added after bldrs default plugin set. See Processing documentation below
],
overridePlugins: false, // set to true to override default bldr plugins
}
}
}
Rollup
module.exports = {
processSettings: {
rollup: {
useBabel: true, // set to false if babel should not be ran. Default: true
useTerser: true, // set to false if terser should not be ran. Default: true
babelPluginOptions: {
// see @rollup/plugin-babel options at https://github.com/rollup/plugins/tree/master/packages/babel#babelhelpers)
// default: { babelHelpers: 'bundled' }
},
inputOptions: {
// see rollups inputOptions object at https://rollupjs.org/guide/en/#inputoptions-object
// `file` will automatically be added, so no need to add here
// default: { external: [/@babel\/runtime/] }
},
inputPlugins: [
// array of rollup input plugins.
// if `rollup.overrideInputPlugins` is set to true, this array will replace the default bldr array.
// if not, then these will be added after bldrs default input plugin set. See Processing documentation below
],
overrideInputPlugins: false, // set to true to override default bldr plugins
outputOptions: {
// see rollups outputOptions object at https://rollupjs.org/guide/en/#outputoptions-object
// `file` will automatically be added, so no need to add here
},
outputPlugins: [
// array of rollup output plugins.
// if `rollup.overrideOutputPlugins` is set to true, this array will replace the default bldr array.
// if not, then these will be added after bldrs default plugin set. See Processing documentation below
],
overrideOutputPlugins: false, // set to true to override default bldr plugins
rollup: require('rollup') // if you wish to use a specific version of rollup, you can require it here. Default: null
}
}
}
Browsersync
module.exports = {
processSettings: {
browsersync: {
disable: false, // set to true to prevent browsersync from instatiating in watch env. Default: true
},
}
}
Sass
🚨 Sass is now limited to sass
- node-sass
is no longer supported. 🚨
As a result, sass options are removed from processSettings
module.exports = {
processSettings: {
// sass: {
// sassProcessor: null, // defaults to node sass. You can require dart-sass here if preferred
// importers: null, // defaults to node-sass-magic-importer
// importerOpts: {}, // options for the importer, defaults to empty object
// },
}
}
Babel (via @rollup/plugin-babel)
If a valid babel config file exists in the same root as where bldr was ran, bldr will include @rollup/plugin-babel
with the default options of {babelHelpers: 'bundled'}
, and Babel will be ran using your local config file. To override, see the documentation for rollup.babelPluginOptions
above.
If you do not want Babel to be ran, simply do not include a
Note: Babel will only conditionally be ran when using the bldr build
command.
Babel Config
While you can setup babel config however you like, here is a working example to get it working.
- Install the following packages to your projects package.json:
npm i --save-dev @babel/preset-env core-js
- Create a
babel.config.json
file containing:
{
"compact" : false,
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
Browsersync Config
If you would like to run watch mode without browsersync, you can disable broswersync by adding processSettings: {browsersync: {disable: true}}
to your bldrConfig.js file.
Local Config
Create a local config file by running bldr init
or creating a file in root named bldrConfigLocal.js
.
Local config is primarily used to store browsersync settings. As such, it is not a file that needs to be tracked.
Example dev/build config:
module.exports = {
browserSync: {
proxy: 'http://site.local'
// other browsersync options as per https://browsersync.io/docs/options
}
}
Processing
Default Rollup input plugins:
- @rollup/plugin-commonjs
- @rollup/plugin-babel
- @rollup/plugin-node-resolve
- rollup-plugin-inject-process-env
Default Rollup output plugins:
- none
Complete Config Example:
module.exports = {
// ----------------------- BASIC CONFIG ----------------------- //
css: {
src: 'path/to/css/files/**/*.css',
dist: 'path/to/css/destination',
watch: ['paths/to/watch/css/files/**/*.css'],
},
// !-- OR IF MULTIPLE SOURCES
// css: [
// {
// src: 'path/to/css/files/**/*.css',
// dist: 'path/to/css/destination',
// watch: ['paths/to/watch/css/files/**/*.css'],
// },
// {
// src: 'path/to/css/files/2/**/*.css',
// dist: 'path/to/css/destination/2',
// watch: ['paths/to/watch/css/files/2/**/*.css'],
// }
// ],
// --!
sass: {
src: 'path/to/sass/files/**/*.scss',
dist: 'path/to/sass/destination',
watch: ['paths/to/watch/sass/files/**/*.scss'],
},
// !-- OR IF MULTIPLE SOURCES
// sass: [
// {
// src: 'path/to/sass/files/**/*.scss',
// dist: 'path/to/sass/destination',
// watch: ['paths/to/watch/sass/files/**/*.scss'],
// },
// {
// src: 'path/to/sass/files/2/**/*.scss',
// dist: 'path/to/sass/destination/2',
// watch: ['paths/to/watch/sass/files/2/**/*.scss'],
// }
// ],
// --!
js: {
src: 'path/to/js/files/**/*.js',
dist: 'path/to/js/destination',
watch: ['paths/to/watch/js/files/**/*.js'],
},
// !-- OR IF MULTIPLE SOURCES
// js: [
// {
// src: 'path/to/js/files/**/*.js',
// dist: 'path/to/js/destination',
// watch: ['paths/to/watch/js/files/**/*.js'],
// },
// {
// src: 'path/to/js/files/2',
// dist: 'path/to/js/destination/2',
// watch: ['paths/to/watch/js/files/2/**/*.js'],
// }
// ],
// --!
images: {
src: 'path/to/image/files/*.{jpg,JPG,jpeg,JPEG,gif,png,svg}',
dist: 'path/to/image/files/destination',
watch: ['paths/to/watch/image/files/**/*'],
},
// !-- OR IF MULTIPLE SOURCES
// images: [
// {
// src: 'path/to/image/files/*.{jpg,JPG,jpeg,JPEG,gif,png,svg}',
// dist: 'path/to/image/files/destination',
// watch: ['paths/to/watch/image/files/**/*'],
// },
// {
// src: 'path/to/image/files/2/*.{jpg,JPG,jpeg,JPEG,gif,png,svg}',
// dist: 'path/to/image/files/destination/2',
// watch: ['paths/to/watch/image/files/2/**/*'],
// },
// ],
// --!
watchReload: [
'some/path/to/watch/**/*.php',
'some/path/to/watch/**/*.cjs',
'some/path/to/watch/**/*.twig',
'some/path/to/watch/**/*.html',
],
env: { // Optional - add custom enviornments (run with `-e=SampleEnv` or `env=SampleEnv)
SampleEnv: { // name of env in cli `env=` parameter
css: { ... }, // Can also be array. Same as basic css config above.
js: { ... }, // Can also be array. Same as basic js config above.
images: { ... }, // Can also be array. Same as basic image config above.
watchReload: [] // Same as basic watchReload config above.
}
},
// --------------------- END BASIC CONFIG --------------------- //
// ---------- SEPERATE DEV/BUILD ENVIRORNMENT CONFIG ---------- //
// ---- IF USING DEV/BUILD CONFIG, DO NOT USE BASIC CONFIG ---- //
dev: {
// see basic config above
},
build: {
// see basic config above
},
// -------- END SEPERATE DEV/BUILD ENVIRORNMENT CONFIG -------- //
// -------------------- PROCESS CONFIG -------------------- //
processSettings: {
// -------------------- BROWSERSYNC CONFIG -------------------- //
browsersync: {
disable: false, // set to true to prevent browsersync from instatiating in watch env. Default: true
},
// ---------------------- ESBUILD CONFIG --------------------- //
esBuild: {
plugins: [
// Array of esbuild plugins to add (install in your root package.json)
// if `esBuild.overridePlugins` is set to true, this array will replace the default bldr array.
// if not, then these will be added after bldrs default plugin set. See Processing documentation below
],
overridePlugins: false, // set to true to override default bldr plugins
esBuild: require('esbuild'), // overrides bldr version of esbuild. Default: null
},
// ---------------------- ROLLUP CONFIG --------------------- //
rollup: {
useBabel: true, // set to false if babel should not be ran. Default: true
useTerser: true, // set to false if terser should not be ran. Default: true
babelPluginOptions: {
// see @rollup/plugin-babel options at https://github.com/rollup/plugins/tree/master/packages/babel#babelhelpers)
// default: { babelHelpers: 'bundled' }
},
inputOptions: {
// see rollups inputOptions object at https://rollupjs.org/guide/en/#inputoptions-object
// `file` will automatically be added, so no need to add here
// default: { external: [/@babel\/runtime/] }
},
inputPlugins: [
// array of rollup input plugins.
// if `rollup.overrideInputPlugins` is set to true, this array will replace the default bldr array.
// if not, then these will be added after bldrs default input plugin set. See Processing documentation below
],
overrideInputPlugins: false, // set to true to override default bldr plugins
outputOptions: {
// see rollups outputOptions object at https://rollupjs.org/guide/en/#outputoptions-object
// `file` will automatically be added, so no need to add here
},
outputPlugins: [
// array of rollup output plugins.
// if `rollup.overrideOutputPlugins` is set to true, this array will replace the default bldr array.
// if not, then these will be added after bldrs default plugin set. See Processing documentation below
],
overrideOutputPlugins: false, // set to true to override default bldr plugins
rollup: require('rollup') // if you wish to use a specific version of rollup, you can require it here. Default: null
},
// ---------------------- ESLint CONFIG --------------------- //
eslint: {
omit: null, // set to true to skip eslint
forceBuildIfError: null, // set to true to force builds to run if linting errors are found
},
// ---------------------- SASS CONFIG --------------------- //
sass: {
sassProcessor: null, // defaults to node sass. You can require [dart-sass](https://www.npmjs.com/package/sass) here if preferred
importer: null, // defaults to [node-sass-magic-importer](https://www.npmjs.com/package/node-sass-magic-importer)
importerOpts: {}, // options for the importer, defaults to empty object
},
}
}