Im new to Gulp.. I have been able to successfully install and concatenate and minify my .js and .css files, however, there is one .css file which i want to exclude - print.css
Ive followed the instructions here: https://www.npmjs.org/package/gulp-ignore install gulp-ignore in my local directory, and modified my gulpfile.js to:
// Include gulp
var gulp = require('gulp');
// Include Our Plugins
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var minifyCSS = require('gulp-minify-css');
var imagemin = require('gulp-imagemin');
var exclude = require('gulp-ignore').exclude;
var paths = {
scriptsNonAuth: ['Non-Auth/javascript/*.js'],
scriptsAuth: ['Auth/javascript/*.js'],
stylesNonAuth: ['Non-Auth/css/*.css'],
stylesAuth: ['Auth/css/*.css'],
};
// CSS Task - Non Authenticated
gulp.task('minify-css-non-auth', function() {
gulp.src(paths.stylesNonAuth)
.pipe(minifyCSS(opts))
.pipe(concat('all.min.css'))
.pipe(gulp.dest('Non-Auth/css'))
});
// CSS Task - Authenticated
gulp.task('minify-css-auth', function() {
gulp.src(paths.stylesAuth)
.pipe(minifyCSS(opts))
**.pipe(exclude('Auth/css/print.css'))**
.pipe(concat('all.min.css'))
.pipe(gulp.dest('Auth/css'))
});
Within my CSS Task - Secure, i have included .pipe(exclude('Secure/css/print.css'))
When i run gulp minify-css-secure, the task completes but upon inspecting the new all.min.css, i cant see the contents of print.css within there too.
It's unclear what you are trying to achieve. If I get it right, you want to:
minify all css files (including print.css)
concat all files except print.css into all.min.css
put minified all.min.css and print.css into destination folder
To achieve that, you can use StreamQueue. (source)
var streamqueue = require('streamqueue');
var paths = {
scriptsNonAuth: ['Non-Auth/javascript/*.js'],
scriptsAuth: ['Auth/javascript/*.js'],
stylesNonAuth: ['Non-Auth/css/*.css'],
stylesAuth: ['Auth/css/*.css', '!Auth/css/print.css'],
};
gulp.task('minify-css-auth', function() {
return streamqueue({ objectMode: true },
gulp.src(paths.stylesAuth)
.pipe(minifyCSS(opts))
.pipe(concat('all.min.css')),
gulp.src('Auth/css/print.css'))
.pipe(minifyCSS(opts))
)
.pipe(gulp.dest('Auth/css'))
});
If you want to just exclude some files, you don't need gulp-ignore. Gulp supports ignore globs.
Just prefix the path to exclude with bang.
Like this:
stylesAuth: ['Auth/css/*.css', '!Auth/css/print.css']
Related
I'm building an MVC application, which is making use of Areas. So I've got a folder structure as follows:
Areas/
AreaOne/
Views/
About/
ScriptOne.js
ScriptTwo.js
Index.cshtml
Home/
ScriptThree.js
ScriptFour.js
Index.cshtml
AreaTwo
Views/...
I'd like to bundle the JavaScript files within the individual page's folder within the View folder.
E.g. ScriptOne.js, ScriptTwo.js should be bundled into About.js and output into a seperate folder like:
js/
Areas/
AreaOne/
About.js
Home.js
I'm able to grab the files, however it will grab all .js files under Areas.
gulp.src('./Areas/**/*.js')
Areas\AreaOne\Views\About\ScriptOne.js
Areas\AreaOne\Views\About\ScriptTwo.js
Areas\AreaOne\Views\Home\ScriptThree.js
Areas\AreaOne\Views\Home\ScriptFour.js
If I concat this I'll end up with a single .js file. However I'd like About.js and Home.js
If I can achieve the above in theory I can use the following (but i'm unsure how to get the appropriate area name:
pipe(gulp.dest('./js/Areas/...AREA NAME GOES HERE.../'))
I'm trying to avoid manual concatenation of files.. like so..
gulp.src(['./Areas/AreaOne/Views/About/ScriptOne.js', './Areas/AreaOne/Views/About/ScriptTwo.js'])
Not sure it's the most succinct way but it works and it's fairly simple.
I use Glob to get the file names within the Areas.
I then add the view paths to a JavaScript object (this works like a set, it prevents duplicates), I also add the name of the view folder as this will be the output file name.
I use gulp.src with the distinct view folder names to collect all of the Javascript files within the individual view folder and then concat them, and finally if it's a release build the files get ugilfied.
var gulp = require('gulp'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
glob = require('glob'),
path = require('path');
gulp.task('process-areas-js', function () {
glob('./Areas/**/*.js*', null, function (er, files) {
var distinctAreaPaths = {};
for (var i = 0; i < files.length; i++) {
var filePath = path.dirname(files[i]).replace(/\./g, "");
var viewFolderName = path.basename(filePath);
distinctAreaPaths[filePath] = viewFolderName;
}
for (distinctPath in distinctAreaPaths) {
var concatName = distinctAreaPaths[distinctPath] + ".js";
var destination = './js' + path.dirname(distinctPath);
var sourceGlob = "." + distinctPath + "/*.js";
var pipeline = gulp.src(sourceGlob)
.pipe(concat(concatName))
uglifyOnRelease(pipeline)
.pipe(gulp.dest(destination));
}
});
});
gulp.task('default', ['process-areas-js']);
function uglifyOnRelease(pipeline) {
return process.env.NODE_ENV === 'Release' || process.env.NODE_ENV == null ? pipeline.pipe(uglify()) : pipeline;
}
I'm trying to add livereload to broccoli
Unfortunately the live-reload plugin documentation is a bit short and I cannot get it to work. In the docs it is stated to do the following:
var injectLivereload = require('broccoli-inject-livereload');
var public = injectLivereload('public');
I figured that this should be placed inside the Brocfile.js (right?). But whatever I do nothing gets reloaded (I have to hit reload to refresh) I've also changed the 'public' part, which I think is representing a directory. Any help would be appreciated.
I'm using BrowserSync instead of "only" LiveReload. It also supports LiveReload (and LiveInject for CSS), but it has tons of other features as well (like ghosting).
Let's create a file called server.js and a folder called app next to it, where you put our index.html, .css and .js. This server.js contains:
var broccoli = require("broccoli");
var brocware = require("broccoli/lib/middleware");
var mergeTrees = require("broccoli-merge-trees");
var Watcher = require("broccoli-sane-watcher");
var browserSync = require("browser-sync");
var tree = mergeTrees(["app"]); // your public directory
var builder = new broccoli.Builder(tree);
var watcher = new Watcher(builder);
watcher.on("change", function(results) {
if (!results.filePath) return;
// Enable CSS live inject
if (results.filePath.indexOf("css") > -1) {
return browserSync.reload("*.css");
}
browserSync.reload();
});
browserSync({
server: {
baseDir: "./",
middleware: brocware(watcher)
}
});
Now fire the server (which will open the browser automatically):
node server.js
I know this isn't as straightforward as Gulp or Grunt at first sight, but it offers fine grained control over everything and it's really blazing fast, even if your app grows and grows.
Instead of Livereload I opted to use Browsersync via the Broccoli Browser Sync plugin
My final Brocfile.js was very similar to (pulled from plugins npm page):
var fastBrowserify = require('broccoli-fast-browserify');
var babelify = require('babelify');
var mergeTrees = require('broccoli-merge-trees');
var compileSass = require('broccoli-sass-source-maps');
var funnel = require('broccoli-funnel');
var BrowserSync = require('broccoli-browser-sync');
var optionalTransforms = [
'regenerator'
// 'minification.deadCodeElimination',
// 'minification.inlineExpressions'
];
var babelOptions = {stage: 0, optional: optionalTransforms, compact: true};
// var browserifyOpts = {deps: true, entries: files, noParse: noParse, ignoreMissing: true};
var transformedBabelify = fastBrowserify('app', {
browserify: {
extensions: [".js"]
},
bundles: {
'js/app.js': {
entryPoints: ['app.js'],
transform: {
tr: babelify,
options: {
stage: 0
}
}
}
}
});
var appCss = compileSass(['piggy/frontend/app'], 'main.scss', 'css/app.css');
var staticFiles = funnel('frontend', {
srcDir: 'static'
});
var browserSync = new BrowserSync([staticFiles, transformedBabelify, appCss]);
module.exports = mergeTrees([staticFiles, transformedBabelify, appCss, browserSync]);
With this solution I was able to continue using broccoli to serve my assets via broccoli serve and all my assets would be rebuilt then reloaded in the browser including my css.
I have a sass file with long loop (generate about 800 lines of CSS) that compiles about 25 seconds. It's too long.
How can I minimize compile time?
Thanks!
This is how I compile Sass using gulp-sass and it takes about 800ms or less. Are you sure you use the node version, not the Ruby gulp-ruby-sass? Ruby is much slower than Node.js.
The loop may be the problem, be sure you are using Each or For, never While. But I also generated big grid system with a more less 200 selectors and it also was fast. Try my task config below:
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var autoprefixer = require('gulp-autoprefixer');
var gulpif = require('gulp-if');
var minify = require('gulp-minify-css');
var argv = require('yargs').argv;
var cache = require('gulp-cached');
// Values from console flags.
var is = {
dev: argv.develop,
prod: argv.production
};
// Gulpfile config.
var config = {
sass: {
src: './src/**/*.scss',
dest: 'src/',
maps: '/'
}
};
gulp.task('sass', function () {
return gulp.src(config.sass.src)
.pipe(cache('sass'))
.pipe(gulpif(is.dev, sourcemaps.init()))
.pipe(autoprefixer())
.pipe(gulpif(is.prod, minify()))
.pipe(gulpif(is.dev, sourcemaps.write(config.sass.maps)))
.pipe(gulp.dest(config.sass.dest));
});
I have a project with a few relatively disjoint pages, each including their own entry point script. These scripts require a number of others using commonjs syntax, and need to be transformed by 6to5 and bundled by browserify.
I would like to set up a gulp task that captures all the files matching a pattern and passes them on to the bundler, but I'm not sure how to pass files from gulp.src to browserify(filename).
My gulpfile looks like:
var gulp = require("gulp");
var browserify = require("browserify");
var to5browserify = require("6to5-browserify");
var source = require("vinyl-source-stream");
var BUNDLES = [
"build.js",
"export.js",
"main.js"
];
gulp.task("bundle", function () {
/* Old version, using glob:
return gulp.src("src/** /*.js")
.pipe(sixto5())
.pipe(gulp.dest("dist"));
*/
// New version, using array:
return BUNDLES.map(function (bundle) {
return browserify("./src/" + bundle, {debug: true})
.transform(to5browserify)
.bundle()
.pipe(source(bundle))
.pipe(gulp.dest("./dist"));
});
});
gulp.task("scripts", ["bundle"]);
gulp.task("html", function () {
return gulp.src("src/**/*.html")
.pipe(gulp.dest("dist"));
});
gulp.task("styles", function () {
return gulp.src("src/**/*.css")
.pipe(gulp.dest("dist"));
});
gulp.task("default", ["scripts", "html", "styles"]);
This seems to work, but isn't maintainable: I'll be adding more scripts relatively soon, and don't want to add them to the array every time.
I've tried using gulp.src(glob).pipe within the browserify call and piping after calling (shown here), and gulp.src(glob).map (method doesn't exist).
How can you chain gulp.src with a name-based transformer like browserify?
Use through2 to make a one-off custom plugin stream that does all of the dirty work.
Unfortanately vinyl-transform and vinyl-source-stream and the solutions that go along with those have flaws so we have to go for something custom.
var gulp = require('gulp');
var through = require('through2');
var browserify = require('browserify');
gulp.task('bundle', function() {
var browserified = function() {
return through.obj(function(chunk, enc, callback) {
if(chunk.isBuffer()) {
var b = browserify(chunk.path);
// Any custom browserify stuff should go here
//.transform(to5browserify);
chunk.contents = b.bundle();
this.push(chunk);
}
callback();
});
};
return gulp.src(['./src/**/*.js'])
.pipe(browserified())
.pipe(gulp.dest('dest'));
});
You can specify globs in your BUNDLES array as well as exclude any files:
var BUNDLES = [
"app/**/*.js",
"export.js",
"app/modules/**/*.js",
"!app/modules/excluded/*.js"
];
I'm new to gulp, but I'm wondering if its possible to iterate through directories in a gulp task.
Here's what I mean, I know a lot of the tutorials / demos show processing a bunch of JavaScript files using something like "**/*.js" and then they compile it into a single JavaScript file. But I want to iterate over a set of directories, and compile each directory into it's own JS file.
For instance, I have a file structure like:
/js/feature1/something.js
/js/feature1/else.js
/js/feature1/foo/bar.js
/js/feature1/foo/bar2.js
/js/feature2/another-thing.js
/js/feature2/yet-again.js
...And I want two files: /js/feature1/feature1.min.js and /js/feature2/feature2.min.js where the first contains the first 4 files and the second contains the last 2 files.
Is this possible, or am I going to have to manually add those directories to a manifest? It would be really nice to pragmatically iterate over all the directories within /js/.
Thanks for any help you can give me.
-Nate
Edit: It should be noted that I don't only have 2 directories, but I have many (maybe 10-20) so I don't really want to write a task for each directory. I want to handle each directory the same way: get all of the JS inside of it (and any sub-directories) and compile it down to a feature-based minified JS file.
There's an official recipe for this: Generating a file per folder
var fs = require('fs');
var path = require('path');
var merge = require('merge-stream');
var gulp = require('gulp');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var scriptsPath = 'src/scripts';
function getFolders(dir) {
return fs.readdirSync(dir)
.filter(function(file) {
return fs.statSync(path.join(dir, file)).isDirectory();
});
}
gulp.task('scripts', function() {
var folders = getFolders(scriptsPath);
var tasks = folders.map(function(folder) {
return gulp.src(path.join(scriptsPath, folder, '/**/*.js'))
// concat into foldername.js
.pipe(concat(folder + '.js'))
// write to output
.pipe(gulp.dest(scriptsPath))
// minify
.pipe(uglify())
// rename to folder.min.js
.pipe(rename(folder + '.min.js'))
// write to output again
.pipe(gulp.dest(scriptsPath));
});
// process all remaining files in scriptsPath root into main.js and main.min.js files
var root = gulp.src(path.join(scriptsPath, '/*.js'))
.pipe(concat('main.js'))
.pipe(gulp.dest(scriptsPath))
.pipe(uglify())
.pipe(rename('main.min.js'))
.pipe(gulp.dest(scriptsPath));
return merge(tasks, root);
});
You could use glob to get a list of directories and iterate over them, using gulp.src to create a separate pipeline for each feature. You can then return a promise which is resolved when all of your streams have ended.
var fs = require('fs');
var Q = require('q');
var gulp = require('gulp');
var glob = require('glob');
gulp.task('minify-features', function() {
var promises = [];
glob.sync('/js/features/*').forEach(function(filePath) {
if (fs.statSync(filePath).isDirectory()) {
var defer = Q.defer();
var pipeline = gulp.src(filePath + '/**/*.js')
.pipe(uglify())
.pipe(concat(path.basename(filePath) + '.min.js'))
.pipe(gulp.dest(filePath));
pipeline.on('end', function() {
defer.resolve();
});
promises.push(defer.promise);
}
});
return Q.all(promises);
});
I am trying myself to get how streams work in node.
I made a simple example for you, on how to make a stream to filter folders and start a new given stream for them.
'use strict';
var gulp = require('gulp'),
es = require('event-stream'),
log = require('consologger');
// make a simple 'stream' that prints the path of whatever file it gets into
var printFileNames = function(){
return es.map(function(data, cb){
log.data(data.path);
cb(null, data);
});
};
// make a stream that identifies if the given 'file' is a directory, and if so
// it pipelines it with the stream given
var forEachFolder = function(stream){
return es.map(function(data, cb){
if(data.isDirectory()){
var pathToPass = data.path+'/*.*'; // change it to *.js if you want only js files for example
log.info('Piping files found in '+pathToPass);
if(stream !== undefined){
gulp.src([pathToPass])
.pipe(stream());
}
}
cb(null, data);
});
};
// let's make a dummy task to test our streams
gulp.task('dummy', function(){
// load some folder with some subfolders inside
gulp.src('js/*')
.pipe(forEachFolder(printFileNames));
// we should see all the file paths printed in the terminal
});
So in your case, you can make a stream with whatever you want to make with the files in a folder ( like minify them and concatenate them ) and then pass an instance of this stream to the forEachFolder stream I made. Like I do with the printFileNames custom stream.
Give it a try and let me know if it works for you.
First, install gulp-concat & gulp-uglify.
$ npm install gulp-concat
$ npm install gulp-uglify
Next, do something like:
//task for building feature1
gulp.task('minify-feature1', function() {
return gulp.src('/js/feature1/*')
.pipe(uglify()) //minify feature1 stuff
.pipe(concat('feature1.min.js')) //concat into single file
.pipe(gulp.dest('/js/feature1')); //output to dir
});
//task for building feature2
gulp.task('minify-feature2', function() { //do the same for feature2
return gulp.src('/js/feature2/*')
.pipe(uglify())
.pipe(concat('feature2.min.js'))
.pipe(gulp.dest('/js/feature2'));
});
//generic task for minifying features
gulp.task('minify-features', ['minify-feature1', 'minify-feature2']);
Now, all you have to do to minify everything from the CLI is:
$ gulp minify-features
I had trouble with the gulp recipe, perhaps because I'm using gulp 4 and/or because I did not want to merge all my folders' output anyway.
I adapted the recipe to generate (but not run) an anonymous function per folder and return the array of functions to enable them to be processed by gulp.parallel - in a way where the number of functions I would generate would be variable. The keys to this approach are:
Each generated function needs to be a function or composition (not a stream). In my case, each generated function was a series composition because I do lots of things when building each module folder.
The array of functions needs to passed into my build task using javascript apply() since every member of the array needs to be turned into an argument to gulp.parallel in my case.
Excerpts from my function that generates the array of functions:
function getModuleFunctions() {
//Get list of folders as per recipe above - in my case an array named modules
//For each module return a function or composition (gulp.series in this case).
return modules.map(function (m) {
var moduleDest = env.folder + 'modules/' + m;
return gulp.series(
//Illustrative functions... all must return a stream or call callback but you can have as many functions or compositions (gulp.series or gulp.parallel) as desired
function () {
return gulp.src('modules/' + m + '/img/*', { buffer: false })
.pipe(gulp.dest(moduleDest + '/img'));
},
function (done) {
console.log('In my function');
done();
}
);
});
}
//Illustrative build task, running two named tasks then processing all modules generated above in parallel as dynamic arguments to gulp.parallel, the gulp 4 way
gulp.task('build', gulp.series('clean', 'test', gulp.parallel.apply(gulp.parallel, getModuleFunctions())));
`