diff --git a/.gitignore b/.gitignore index 1fe1b00..41ccd3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .idea/ node_modules/ +/nbproject/private/ +/nbproject/ 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..19beb49 100644 --- a/index.js +++ b/index.js @@ -1,75 +1,202 @@ var gulp = require('gulp'); -var mainBowerFiles = 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 bowerfiles = require('main-bower-files'); +var Elixir = require('laravel-elixir'); -elixir.extend('bower', function(cssFile, cssOutput, jsFile, jsOutput) { +var filesize = require('filesize'); +var path = require('path'); +var validator = require('validator'); +var isAbsolute = require('is-absolute-url'); - var config = this; - var cssFile = cssFile || 'vendor.css'; - var jsFile = jsFile || 'vendor.js'; +var task = Elixir.Task; +var config = Elixir.config; +var notification = Elixir.Notification; - gulp.task('bower', ['bower-css', 'bower-js']); +var $ = require('gulp-load-plugins')(); +var _ = require('lodash'); + + +Elixir.extend('bower', function (options) { + + var options = _.merge({ + debugging: !config.production, + flatten: true, + css: { + minify: config.production, + outputFile: 'vendor.css', + extInline: ['gif', 'png'], + maxInlineSize: 32 * 1024, //max 32k on ie8 + outputFolder: config.get("public.css.outputFolder") + }, + js: { + uglify: config.production, + outputFile: 'vendor.js', + outputFolder: config.get("public.js.outputFolder") + }, + fonts: { + outputFolder: config.get("public.fonts.outputFolder"), + filter: /\.(eot|svg|ttf|woff|woff2|otf)$/i + }, + images: { + outputFolder: config.get("public.images.outputFolder"), + 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.fonts !== false) + files.push('bower-fonts'); + if (options.images !== 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(/\?|#/)[0]; + var targetQuery = context.targetFile.split(/\?/)[1]; + + 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.fonts.filter)) + targetPath = path.relative(context.destinationDir, process.cwd() + '/' + options.fonts.outputFolder + '/' + targetPath); + + if (absolutePath.match(options.images.filter)) + targetPath = path.relative(context.destinationDir, process.cwd() + '/' + options.images.outputFolder + '/' + targetPath); + + if (process.platform === 'win32') + targetPath = targetPath.replace(/\\/g, '/'); + + if (opts.debugging) + { + console.log(context.targetFile + " -> " + targetPath); + } + + return targetPath + (targetQuery !== undefined ? '?' + targetQuery : ''); + + }; + + var opts = { + debugging: options.debugging, + filter: '**/*.css' + }; + + + return gulp.src(bowerfiles(opts), options.flatten ? null : {base: opts.base}) + .on('error', onError) + //.pipe($.filter('**/*.css')) + .pipe($.if(options.css.maxInlineSize > 0, $.base64({ + extensions: options.css.extInline, + maxImageSize: options.css.maxInlineSize, // bytes + debug: options.debugging + }))) + .pipe($.rewriteCss({destination: options.css.outputFolder, debug: options.debugging, adaptPath: rebase})) + .pipe($.concat(options.css.outputFile)) + .pipe($.if(options.css.minify, $.cssnano())) + .pipe(gulp.dest(options.css.outputFolder)) + .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, + filter: '**/*.js' + }; + + return gulp.src(bowerfiles(opts)) + .on('error', onError) + //.pipe($.filter('**/*.js')) + .pipe($.concat(options.js.outputFile)) + .pipe($.if(options.js.uglify, $.uglify(), $.beautify())) + .pipe(gulp.dest(options.js.outputFolder)) + .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.fonts.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.fonts.outputFolder)) + .pipe(gulp.dest(options.fonts.outputFolder)) + .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.images.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.images.outputFolder)) + .pipe(gulp.dest(options.images.outputFolder)) + .pipe(new notification('Images Bower Files Imported!')); + + }); -}); \ No newline at end of file +}); diff --git a/package.json b/package.json index 34f9fa3..24c4390 100644 --- a/package.json +++ b/package.json @@ -1,34 +1,48 @@ { - "name": "laravel-elixir-bower", - "version": "0.1.0", - "description": "Laravel Elixir Bower Extension", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "name": "laravel-elixir-bower", + "version": "1.2.3", + "description": "Laravel Elixir Bower Extension", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "laravel", + "elixir", + "bower", + "gulp" + ], + "repository": { + "type": "git", + "url": "https://github.com/Crinsane/laravel-elixir-bower" + }, + "author": "Rob Gloudemans", + "license": "MIT", + "homepage": "https://github.com/Crinsane/laravel-elixir-bower", + "bugs": { + "url": "https://github.com/Crinsane/laravel-elixir-bower/issues" + }, + "dependencies": { + "filesize": "~3.3.0", + "gulp-base64": "~0.1", + "gulp-beautify": "~2.0", + "gulp-changed": "~1.1", + "gulp-concat": "~2.4", + "gulp-cssnano": "~2.1.0", + "gulp-filter": "~1.0", + "gulp-if": "~1.2", + "gulp-ignore": "~1.2", + "gulp-load-plugins": "~1.2.2", + "gulp-minify-css": "~0.3", + "gulp-notify": "~2.0", + "gulp-rewrite-css": "~0.0", + "gulp-uglify": "~1.0", + "is-absolute-url": "~2.0", + "lodash": "~3.0", + "main-bower-files": "~2.11", + "validator": "~4.2" }, - "keywords": [ - "laravel", - "elixir", - "bower", - "gulp" - ], - "repository": { - "type": "git", - "url": "https://github.com/Crinsane/laravel-elixir-bower" - }, - "author": "Rob Gloudemans", - "license": "MIT", - "homepage": "https://github.com/Crinsane/laravel-elixir-bower", - "bugs": { - "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" + "peerDependencies":{ + "laravel-elixir": ">3.0" } }