diff --git a/README.md b/README.md index 106f103..27a21ea 100644 --- a/README.md +++ b/README.md @@ -3,24 +3,143 @@ laravel-elixir-bower Elixir Wrapper Around Bower -``` +### Usage + +```javascript var elixir = require('laravel-elixir'); require('laravel-elixir-bower'); elixir(function(mix) { - mix.bower() - .routes() - .events(); + mix.bower(); +}); +``` + +This will : +- scan your bower files +- concat all css files in a `public/css/vendor.css` file +- concat all js files in a `public/js/vendor.js` file +- copy all webfonts in a `fonts/` folder. +- copy all images in a `imgs/` folder. + +### Settings + +The default settings are the following : + +```javascript +{ + debugging: false, // Enable/Disable verbose output + flatten: true, // Enable/Disable flat asset structure + css: { + file: 'vendor.css', // Merged CSS file + output: config.cssOutput // Elixir default css output folder (public/css) + }, + js: { + file: 'vendor.js', // Merged JS file + output: config.jsOutput // Elixir default js output folder (public/js) + }, + font: { + output: 'public/fonts' // Web fonts output folder + }, + img: { + output: 'public/imgs', + extInline: ['gif','png'], // Extensions to inline + maxInlineSize: 32 * 1024 // [kB] Inline as data uri images below specified size + // (use 0 to disable, max 32k on ie8) + } +} +``` + +Each setting can be overwritten by passing them as an object to the `bower()` function. + +Any setting can also be set to `false` to prevent generation and output of those files. + +### Examples + +```javascript +elixir(function(mix) { + mix.bower({ + debugging: true, + css: { + file: 'plugins.css' + }, + js: { + output: 'public/scripts' + } + }); }); ``` -This will scan your bower files and concat all css files, by default, in a `css/vendor.css` file. And all js files in a `js/vendor.js` file. +```javascript + +var options = {}; +options.debugging = true; +options.css = {file: 'plugins.css'}; +options.js = {output: 'public/scripts'}; + +elixir(function(mix) { + mix.bower(options); +}); +``` -These settings can be overwriten by passing them to the `bower()` function. +Those examples do the same : +- scan your bower files +- concat all css files in a `public/css/plugins.css` file +- concat all js files in a `public/scripts/vendor.js` file +- copy all webfonts in a `fonts/` folder. +```javascript +elixir(function(mix) { + mix.bower({ + debugging: true, + css: false, + js: false, + font: { + output: 'public/fonts' + }, + img: { + output: 'public/css', + extInline: ['gif', 'png'], // Extensions to inline + maxInlineSize: 32 * 1024 // [kB] Inline as data uri images below specified size + // (use 0 to disable, max 32k on ie8) + } + }); +}); ``` +This example does the following: +- scan your bower files +- skips css and js files +- copy all webfonts in a `public/fonts/` folder. +- copy all gif or png images into `public/css` folder. +- inline any of those images which are smaller than 32k. + +```javascript elixir(function(mix) { - mix.bower('styles.css', 'public/assets/css', 'scripts.js', 'public/assets/js'); + mix.bower({ + debugging: true, + flatten: false, + css: { + output: 'public/css' + }, + js: false, + font: { + output: 'public/fonts' + }, + img: { + output: 'public/imgs', + extInline: ['gif', 'png'], // Extensions to inline + maxInlineSize: 32 * 1024 // [kB] Inline as data uri images below specified size + // (use 0 to disable, max 32k on ie8) + } + }); }); -``` \ No newline at end of file +``` +This example does the following: +- scan your bower files +- deactivate flat asset mode +- concat all css files in a `public/css/plugins.css` file +- skips js files +- copy all webfonts in a `public/fonts/{bower_package}/xxx` folder (according to bower package structure) +- copy all gif or png images into `public/imgs/{bower_package}/xxx` folder (according to bower package structure) +- inline any of those images which are smaller than 32k. + diff --git a/index.js b/index.js index be6ca5d..036a1f7 100644 --- a/index.js +++ b/index.js @@ -1,75 +1,206 @@ var gulp = require('gulp'); -var mainBowerFiles = require('main-bower-files'); +var bowerfiles = require('main-bower-files'); var elixir = require('laravel-elixir'); var filter = require('gulp-filter'); var notify = require('gulp-notify'); var minify = require('gulp-minify-css'); var uglify = require('gulp-uglify'); var concat = require('gulp-concat'); +var changed = require('gulp-changed'); +var base64 = require('gulp-base64'); +var test = require('gulp-if'); +var ignore = require('gulp-ignore'); +var rewrite = require('gulp-rewrite-css'); +var filesize = require('filesize'); +var path = require('path'); +var validator = require('validator'); +var isAbsolute = require('is-absolute-url'); -elixir.extend('bower', function(cssFile, cssOutput, jsFile, jsOutput) { +var task = elixir.Task; +var config = elixir.config; +var notification = elixir.Notification; - var config = this; - var cssFile = cssFile || 'vendor.css'; - var jsFile = jsFile || 'vendor.js'; +var _ = require('lodash'); - gulp.task('bower', ['bower-css', 'bower-js']); +elixir.extend('bower', function (options) { + + var options = _.merge({ + debugging: false, + flatten: true, + css: { + minify: true, + file: 'vendor.css', + extInline: ['gif', 'png'], + maxInlineSize: 32 * 1024, //max 32k on ie8 + output: config.css.outputFolder ? config.publicPath + '/' + config.css.outputFolder : config.publicPath + '/css' + }, + js: { + uglify: true, + file: 'vendor.js', + output: config.js.outputFolder ? config.publicPath + '/' + config.js.outputFolder : config.publicPath + '/js' + }, + font: { + output: (config.font && config.font.outputFolder) ? config.publicPath + '/' + config.font.outputFolder : config.publicPath + '/fonts', + filter: /\.(eot|svg|ttf|woff|woff2|otf)$/i + }, + img: { + output: (config.img && config.img.outputFolder) ? config.publicPath + '/' + config.img.outputFolder : config.publicPath + '/imgs', + filter: /\.(png|bmp|gif|jpg|jpeg)$/i + + } + }, options); + + var files = []; + + if (options.css !== false) + files.push('bower-css'); + if (options.js !== false) + files.push('bower-js'); + if (options.font !== false) + files.push('bower-fonts'); + if (options.img !== false) + files.push('bower-imgs'); + + new task('bower', function () { + return gulp.start(files); + }); + + var isInline = function (file) { + + var fsize = file.stat ? filesize(file.stat.size) : filesize(Buffer.byteLength(String(file.contents))); + var fext = file.path.split('.').pop(); + + if (options.debugging) + console.log("Size of file:" + file.path + " (" + 1024 * parseFloat(fsize) + " / max=" + options.css.maxInlineSize + ")"); + + return options.css.extInline.indexOf(fext) > -1 && 1024 * parseFloat(fsize) < options.css.maxInlineSize; + } gulp.task('bower-css', function () { - var onError = function (err) { - notify.onError({ - title: "Laravel Elixir", - subtitle: "Bower Files CSS Compilation Failed!", - message: "Error: <%= error.message %>", - icon: __dirname + '/../icons/fail.png' - })(err); + var onError = function (err) { + new notification().error(err, "Bower Files CSS Compilation Failed! Error: <%= error.message %>"); this.emit('end'); }; - return gulp.src(mainBowerFiles()) - .on('error', onError) - .pipe(filter('**/*.css')) - .pipe(concat(cssFile)) - .pipe(minify()) - .pipe(gulp.dest(cssOutput || config.cssOutput)) - .pipe(notify({ - title: 'Laravel Elixir', - subtitle: 'CSS Bower Files Imported!', - icon: __dirname + '/../icons/laravel.png', - message: ' ' - })); + var rebase = function (context) { + + if (isAbsolute(context.targetFile) || validator.isURL(context.targetFile) || context.targetFile.indexOf('data:image') === 0) { + return context.targetFile; + } + + var targetPath = context.targetFile.split(/\?|#/).shift() + + if (options.flatten) + { + targetPath = targetPath.split('/').pop(); + } else + { + targetPath = path.relative(opts.base, context.sourceDir + '/' + targetPath); + } + + var absolutePath = path.relative(context.destinationDir, targetPath) + + if (absolutePath.match(options.font.filter)) + targetPath = path.relative(context.destinationDir, process.cwd() + '/' + options.font.output + '/' + targetPath); + + if (absolutePath.match(options.img.filter)) + targetPath = path.relative(context.destinationDir, process.cwd() + '/' + options.img.output + '/' + targetPath); + + if (process.platform === 'win32') + targetPath = targetPath.replace(/\\/g, '/'); + + if (opts.debugging) + { + console.log(context.targetFile + " -> " + targetPath); + } + + return targetPath; + + }; + + var opts = { + debugging: options.debugging + }; + + + return gulp.src(bowerfiles(opts), options.flatten ? null : {base: opts.base}) + .on('error', onError) + .pipe(filter('**/*.css')) + .pipe(test(options.css.maxInlineSize > 0, base64({ + extensions: options.css.extInline, + maxImageSize: options.css.maxInlineSize, // bytes + debug: options.debugging, + }))) + .pipe(rewrite({destination: options.css.output, debug: options.debugging, adaptPath: rebase})) + .pipe(concat(options.css.file)) + .pipe(test(options.css.minify, minify())) + .pipe(gulp.dest(options.css.output)) + .pipe(new notification('CSS Bower Files Imported!')); + }); gulp.task('bower-js', function () { + var onError = function (err) { + new notification().error(err, "Bower Files JS Compilation Failed! Error: <%= error.message %>"); + this.emit('end'); + }; + + var opts = { + debugging: options.debugging + }; + + return gulp.src(bowerfiles(opts)) + .on('error', onError) + .pipe(filter('**/*.js')) + .pipe(concat(options.js.file)) + .pipe(test(options.js.uglify, uglify())) + .pipe(gulp.dest(options.js.output)) + .pipe(new notification('Javascript Bower Files Imported!')); + + }); - notify.onError({ - title: "Laravel Elixir", - subtitle: "Bower Files JS Compilation Failed!", - message: "Error: <%= error.message %>", - icon: __dirname + '/../icons/fail.png' - })(err); + gulp.task('bower-fonts', function () { + var onError = function (err) { + new notification().error(err, "Bower Files Font Copy Failed! Error: <%= error.message %>"); this.emit('end'); }; - return gulp.src(mainBowerFiles()) - .on('error', onError) - .pipe(filter('**/*.js')) - .pipe(concat(jsFile)) - .pipe(uglify()) - .pipe(gulp.dest(jsOutput || config.jsOutput)) - .pipe(notify({ - title: 'Laravel Elixir', - subtitle: 'Javascript Bower Files Imported!', - icon: __dirname + '/../icons/laravel.png', - message: ' ' - })); + var opts = { + debugging: options.debugging, + filter: options.font.filter + }; + return gulp.src(bowerfiles(opts), options.flatten ? null : {base: opts.base}) + .on('error', onError) + .pipe(ignore.exclude(isInline)) // Exclude inlined images + .pipe(changed(options.font.output)) + .pipe(gulp.dest(options.font.output)) + .pipe(new notification('Font Bower Files Imported!')); }); - return this.queueTask('bower'); + gulp.task('bower-imgs', function () { + + var onError = function (err) { + new notification().error(err, "Bower Files Images Copy Failed! Error: <%= error.message %>"); + this.emit('end'); + }; + + var opts = { + debugging: options.debugging, + filter: options.img.filter + }; + + return gulp.src(bowerfiles(opts), options.flatten ? null : {base: opts.base}) + .on('error', onError) + .pipe(ignore.exclude(isInline)) // Exclude inlined images + .pipe(changed(options.img.output)) + .pipe(gulp.dest(options.img.output)) + .pipe(new notification('Images Bower Files Imported!')); + + }); -}); \ No newline at end of file +}); diff --git a/package.json b/package.json index 34f9fa3..51550e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "laravel-elixir-bower", - "version": "0.1.0", + "version": "1.0.0", "description": "Laravel Elixir Bower Extension", "main": "index.js", "scripts": { @@ -23,12 +23,25 @@ "url": "https://github.com/Crinsane/laravel-elixir-bower/issues" }, "dependencies": { - "gulp-concat": "^2.4.1", - "gulp-filter": "^1.0.2", - "gulp-load-plugins": "^0.7.0", - "gulp-minify-css": "^0.3.11", - "gulp-notify": "^2.0.0", - "gulp-uglify": "^1.0.1", - "main-bower-files": "^2.1.0" + "gulp-changed": "^1.1", + "gulp-concat": "^2.4", + "gulp-filter": "^1.0", + "gulp-load-plugins": "^0.7", + "gulp-minify-css": "^0.3", + "gulp-notify": "^2.0", + "gulp-uglify": "^1.0", + "lodash": "^3.0", + "main-bower-files": "^2.1", + "gulp-base64" :"^0.1", + "gulp-if" :"^1.2", + "gulp-ignore" :"^1.2", + "gulp-rewrite-css":"^0.0", + "filesize":"^2.0", + "validator": "^4.2", + "is-absolute-url":"^2.0" + + }, + "peerDependencies":{ + "laravel-elixir":"^3.0" } }