Awesome
bower-files
Looking for another maintainer. I have been cleaning up my packages and no
longer have the energy to maintain this package. If you are interested in
taking over, please reach out. Otherwise, eventually I will have this package
removed. There are much better alternatives that have much better community
adoption/support. The best alternative I could find was
wiredep. Honestly, I don't use bower
anymore, and it's been a long time since I have. I've opted to use webpack with
standard npm
installs. If you haven't tried that yet, you should definitely
give it a try.
Help you dynamically include your bower components into your build process.
The Problem
Bower is a great tool to bring in your front-end dependencies (and their dependencies) to your project. But if you want them to be included in your build process, you need to manually enter them in to your build process. If you add or remove dependencies, you need to modify your build process configuration files.
The Solution
bower-files
aims to simplify your build process setup by dynamically getting
the library files for you to include in whatever build process you use. It
splits up the files by extension, and puts them in the order they need to be in,
in order to work correctly in the browser.
4.x
Just updated dependencies and support for only node >= 4.x. Also added deprecation notice. Otherwise, api is exactly the same and should work the same as it did before.
3.x
There are breaking changes in 3.x. A few features were requested, but with the way that the code was organized, it was going to be pretty difficult and it would make the codebase even more complicated. In the end, I refactored most every piece to follow a more modular approach. I am much happier with the code base than I was, but it's not perfect. I'm going to be slowly refactoring litte pieces here and there, but the api should not change much from here.
For those of you who want the old 2.x api, just use it the same way, but adding
a .old
before the function call.
var lib = require('bower-files').old(options);
With that you get the benefit of using the new modular code, and it still passes all of the old tests (which had 100% api and code coverage). 2.x Docs
Installation
npm install bower-files --save-dev
Usage
gulp example...
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var lib = require('bower-files')();
gulp.task('default', function () {
gulp.src(lib.ext('js').files)
.pipe(concat('lib.min.js'))
.pipe(uglify())
.pipe(gulp.dest('public/js'));
});
or a grunt example...
var lib = require('bower-files')();
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
dist: {
files: {
'build/lib.min.js': lib.ext('js').files
}
}
},
cssmin: {
dist: {
files: {
'build/lib.min.css': lib.ext('css').files
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.registerTask('default', ['uglify', 'cssmin']);
};
or via the CLI (node-modules/.bin
needs to be in your PATH
):
$ bower-files js css
Other Solutions
There are other modules that do this same thing, but in different ways:
Options
The following gives you an instance of your bower files.
var lib = require('bower-files')(/* options */);
Those options are as follows:
options.cwd
{String}
Default: process.cwd()
Your current working directory where your bower.json
lives. This is also where
it will start looking at .bowerrc
. MUST be an absolute path.
options.json
{String}
Default: 'bower.json'
The relative path to your bower.json
. This is relative to your options.cwd
.
options.componentJson
{String}
Default: '.bower.json'
When you run bower install jquery
it installs the jquery
component into a
folder bower_components/jquery/
. In that directory, there is a .bower.json
file put there by bower, which essentially is a copy of the other bower.json
,
but it's what is officially used by bower. If for some reason you are using a
different package manager that uses a different file, then you can change it
with this option. Otherwise, leave it as is.
options.overrides
{Object}
Default: {}
An overrides object to override specific package main files. Occasionally,
you'll find a bower component that has no defined main
property. So here, you
pass in an object that looks like this:
var lib = require('bower-files')({
overrides: {
jQuery: {
main: './dist/jquery.min.js',
dependencies: {}
}
}
});
Note that you can also add this POJO into bower.json
in JSON
form, but if
you specify an overrides directly when calling bower-files
, it will override
the bower.json
version.
options.dir
{String}
Default: 'bower_components'
The directory that your bower_components directory is set. Note that this module
will automatically read your .bowerrc
file, so if you already have it being
set there, you don't need to set this option. It also follows the same
.bowerrc
rules that bower
follows
options.camelCase
{Boolean}
Default: true
When you get a dependency hash using the .deps
, by default, it will return
the components in camelCase. So if you have angular-route
as a dependency,
it will be returned in the dependency hash as angularRoute
. To prevent this
from happening, pass false to this option. Example:
var lib = require('bower-files')({camelCase: false}).deps;
lib['angular-route']; // instead of lib.angularRoute
API
Getting the files and filtering through them can be a pain without this module. This API is designed to be easy to understand. If you don't like it, PRs are welcome.
First, you need your BowerFiles instance:
var lib = require('bower-files')();
At this point, bower-files
has gotten a list of all the components and their
dependencies. Now it's up to you to use the API to filter those files.
Chainable Methods
The following methods are chainable. At the end, you will need to get the
files
property to get the array of files.
lib.files; // returns all of the files
You may also get the deps
property, which will be an object hash with all of
the bower components as keys. Note that this is not guaranteed to be in the
correct order. If you need the correct order, use the next option.
lib.deps;
/*
{
jquery: [...],
bootstrap: [...]
}
*/
You can also get an array of all of the dependencies with their names and files.
lib.depsArray
/*
[
{
name: 'jquery',
files: [...]
},
{
name: 'bootstrap',
files: [...]
}
]
*/
lib.self()
By default the array of files you get only contain your dependencies defined in
the dependencies
property in your bower.json
. This allows you to also get
the files defined in the main
property in your bower.json
.
lib.self().files;
lib.self().deps;
lib.relative('/')
Default: process.cwd()
Converts the file paths to be relative to the provided path, defaults to process.cwd()
lib.relative(__dirname).files;
lib.main(false)
Default: true
This gives you the ability to remove main dependencies from the file list.
lib.dev().main(false).files;
lib.dev().main(false).deps;
lib.fileListProps(props, useOne)
Default: ['main'], true
This lets you select which bower properties are used when generating a file list
for a component. For example, it seems that the bower standard for lists of
files used by tools like this one is to use the files
property. You could use
lib.fileListProps('files')
to utilize that property instead of the other one.
You could also select both: lib.fileListProps(['files', 'main'])
and it would
remove the duplicate files that match both the main property definition and the
files property definition (it expands globs and uniquifies the lists)
The second option allows you to specify whether or not you want it to stop
trying to read additional file list properties when it finds one. For example,
you may specify ['files', 'main']
, and then true
as the second option, and
all components with a files
property would ignore the 'main' property.
If it's set to false, it would include all of the files in the 'main' property.
lib.fileListProps('files').files;
lib.fileListProps(['files', 'main']).files;
lib.ignoreListProps(props)
Default []
This lets you select which bower properties are used when ignore globs of files. This is to support the bower spec which allows you to use globs in the "files" property, and "ignore" which would ignore groups of files that match the "files" patterns.
lib
.fileListProps('files')
.ignoreListProps('ignore')
.files;
lib.dev()
This throws in your devDependencies
. By default, they come before the normal
dependencies, but you can put them after by calling lib.dev('after')
lib.dev().files;
lib.dev().deps;
lib.ext('js')
Gives you the files with the given extension(s). Accepts a string, array of
strings, or a boolean. The strings are extensions that you would like to filter
by (without the '.'). If you pass true
, it will return an object whose
properties are all of the extensions.
lib.ext('js').files; // Gets all .js files
lib.ext(['css', 'less']).files; // Gets all .css and .less files
lib.ext('css').ext('less').files; // Same as above
lib.ext(true).files; // Get an object like:
/*
{
js: ['what.js', 'who.js'],
css: ['when.css'],
less: ['why.less']
}
*/
lib.ext('js').deps;
/*
{
jquery: ['/path/to/jquery.js'],
bootstrap: ['/path/to/bootstrap.js']
}
*/
lib.ext(true).deps;
/*
{
jquery: { js: ['/path/to/jquery.js'] },
bootstrap: {
js: ['/path/to/bootstrap.js'],
css: ['/path/to/bootstrap.css'],
less: ['/path/to/bootstrap.less'],
you get the picture...
}
}
*/
lib.match('!**/*.min.js')
Allows you to glob match the files. Accepts a string, or array of strings. The files have to match all of the given glob strings to make it through.
The matches are done relative to process.cwd(). So if you wanted to get all of
the bootstrap files by matching, you would use '*/bootstrap/**'
as a pattern.
// Gets all .js files that aren't .min.js files
lib.match('**/*.js').match('!**/*.min.js').files;
lib.join({font: ['eot', 'woff', 'ttf', 'svg']})
Allows you to join files of a certain extension into another extension. Accepts
an object as formed above and in the example below. It's only really useful if
you plan on using .ext(true)
to split by extension, otherwise you can just use
lib.ext(['eot', 'woff', 'ttf', 'svg']).files
to get the files you need.
// Gets all the font files, from bootstrap for example
lib.join({font: ['eot', 'woff', 'ttf', 'svg']}).files
Non-Chainable
There's really only one method, and it could be made chainable really easy, but this method is really a catch all of all of the above methods.
lib.filter({/* options */})
The object given have all of the above options given through the chainable methods. Below is a full example.
lib.filter({
self: true,
dev: true,
ext: 'js',
match: ['!**/*.min.js'],
join: {
js: ['js', 'jsx']
}
});
// chainable alternative
lib.self()
.dev()
.ext('js')
.match('!**/*.min.js')
.join({js: ['js', 'jsx']})
.files;
The above returns all of the .js
files, including the ones in your
bower.json
, and the devDependencies
, and they aren't min.js
files, and it
joins all of the 'js' and 'jsx' files into the 'js' extension. That join could
be used in the extensions instead, but it's just there to show you how you
would do it.
Questions
I know it's trying to solve for a lot of different use cases, so if you have any questions about how to implement this in your specific setup, feel free to open an issue. I usually get back to you pretty quickly, but usually no later than 24 hours, as long as I have access to email.
Development
PRs welcome! Make sure you have an updated npm
or the npm scripts won't work.
Tests that run fail if not all the tests pass, if you don't have 100% coverage,
or if the code doesn't pass jshint. I'd like to keep everything the same style,
so feel free to call me out on stuff. If you don't like the coding style, I'm
open for a discussion on it.
To run tests, run npm test
.