Concatenate js files in correct order using Gulp - javascript

I am trying to concatenate a bunch of js files with gulp, but in a specific order. I want a file called ‘custom.js’ to be last (could be any other filename, though.
This is my gulp task:
gulp.task('scripts', function() {
return gulp.src(['src/scripts/**/!(custom)*.js','src/scripts/custom.js'])
.pipe(jshint('.jshintrc'))
.pipe(jshint.reporter('default'))
//.pipe(gulp.src('src/scripts/**/*.js')) not needed(?)
.pipe(order([
'!(custom)*.js', // all files that end in .js EXCEPT custom*.js
'custom.js'
]))
.pipe(concat('main.js'))
.pipe(gulp.dest('static/js'))
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(gulp.dest('static/js'))
.pipe(notify({ message: 'Scripts task complete' }));
});
However, this just concatenates files in alphabetical order. What can I do to solve this, except renaming the custom.js file to something like zzz-custom.js?

You need something along the lines of ....
gulp.task('scripts', function() {
return gulp.src(['src/scripts/**/*.js','!src/scripts/custom.js', 'src/scripts/custom.js'])
.pipe(concat('main.js'))
.pipe(uglify())
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest('static/js'));
});
gulp.src
Globs all js files in src/scripts
Excludes src/scripts/custom.js
Loads src/scripts/custom.js
Concat the stream into main.js
Uglify the stream
Add '.min' suffix
Save to static/js
Key part is to first exclude custom.js from the glob and then adding it.
** EDIT **
Well, I suppose you could break down the steps. Not the most elegant but should do the job:
var sequence = require(‘run-sequnce’);
var rimraf = require(‘rimraf’);
// This gets called and runs each subtask in turn
gulp.task('scripts', function(done) {
sequence('scripts:temp', 'scripts:main', 'scripts:ugly', 'scripts:clean', done);
});
// Concat all other js files but without custom.js into temp file - 'main_temp.js'
gulp.task('scripts:temp', function() {
return gulp.src(['src/scripts/**/*.js','!src/scripts/custom.js'])
.pipe(jshint('.jshintrc'))
.pipe(jshint.reporter('default'))
.pipe(concat('main_temp.js'))
.pipe(gulp.dest('static/js/temp'));
});
// Concat temp file with custom.js - 'main.js'
gulp.task('scripts:main', function() {
return gulp.src(['static/js/temp/main_temp.js','src/scripts/custom.js'])
.pipe(concat('main.js'))
.pipe(gulp.dest('static/js'));
});
// Uglify and rename - 'main.min.js'
gulp.task('scripts:ugly', function() {
return gulp.src('static/js/main.js')
.pipe(uglify())
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest('static/js'));
});
// Delete temp file and folder
gulp.task('scripts:clean', function(done) {
rimraf('static/js/temp', done);
});
You could perhaps combine them back bit by bit if it works in this way and you want a "cleaner" file

Related

Gulp errors trying to get uglify and default gulp to work

hi I'm having trouble setting up gulp it seems to have all changed since I last used it
I'm getting errors and can't figure out why. I'll post some pics along with my code. the first problem is that uglify doesn't complete and the second problem is that gulp default won't run the command prompt should explain my problems better than I can if you have any further questions please ask and be civil.
var gulp = require('gulp');
var sass = require('gulp-sass');
var uglifycss = require('gulp-uglifycss');
sass.compiler = require('node-sass');
gulp.task('sass', function () {
return gulp.src('./Edit/sass/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('./Edit/css'));
});
gulp.task('css', function () {
gulp.src('./Edit/css/*.css')
.pipe(uglifycss({
"maxLineLen": 80,
"uglyComments": true
}))
.pipe(gulp.dest('./upload/css'));
});
gulp.task('run',['sass','css']);
gulp.task('watch', function(){
gulp.watch('./Edit/sass/*.scss',['sass']);
gulp.watch('./Edit/css/*.css',['css']);
});
gulp.task('default',['watch', 'run']);
here is my output
So you've got two kinds of errors going on:
1. Task function must be specified
The way gulp runs dependent tasks has changed in v4.0.0. Instead of specifying those tasks in an array, like this:
gulp.task('run',['sass','css']);
They've introduced the gulp.series and gulp.parallel functions. A task function, and not an array, because Task function must be specified. In your case, that gives:
gulp.task('run', gulp.series('sass','css'));
2. Did you forget to signal async completion
This one you could have found, given that this question has been asked many times now. You need to add a return statement to your css task for gulp to know when it's completed and can thus move on. Your task becomes:
gulp.task('css', function () {
return gulp.src('./Edit/css/*.css')
.pipe(uglifycss({
"maxLineLen": 80,
"uglyComments": true
}))
.pipe(gulp.dest('./upload/css'));
});
Result:
Putting it all together, you get this gulpfile:
var gulp = require('gulp');
var sass = require('gulp-sass');
var uglifycss = require('gulp-uglifycss');
sass.compiler = require('node-sass');
gulp.task('sass', function () {
return gulp.src('./Edit/sass/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('./Edit/css'));
});
gulp.task('css', function () {
return gulp.src('./Edit/css/*.css')
.pipe(uglifycss({
"maxLineLen": 80,
"uglyComments": true
}))
.pipe(gulp.dest('./upload/css'));
});
gulp.task('run', gulp.series('sass','css'));
gulp.task('watch', function(){
gulp.watch('./Edit/sass/*.scss',gulp.series('sass'));
gulp.watch('./Edit/css/*.css', gulp.series('css'));
});
gulp.task('default', gulp.series('watch', 'run'));
Note that you can combine your sass and css task if you'd like:
gulp.task('styles', function(){
return gulp.src('./Edit/sass/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(uglifycss({
"maxLineLen": 80,
"uglyComments": true
}))
.pipe(gulp.dest('./upload/css'));
});

Gulp error: watch task has to be a function

Here is my gulpfile:
// Modules & Plugins
var gulp = require('gulp');
var concat = require('gulp-concat');
var myth = require('gulp-myth');
var uglify = require('gulp-uglify');
var jshint = require('gulp-jshint');
var imagemin = require('gulp-imagemin');
// Styles Task
gulp.task('styles', function() {
return gulp.src('app/css/*.css')
.pipe(concat('all.css'))
.pipe(myth())
.pipe(gulp.dest('dist'));
});
// Scripts Task
gulp.task('scripts', function() {
return gulp.src('app/js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(gulp.dest('dist'));
});
// Images Task
gulp.task('images', function() {
return gulp.src('app/img/*')
.pipe(imagemin())
.pipe(gulp.dest('dist/img'));
});
// Watch Task
gulp.task('watch', function() {
gulp.watch('app/css/*.css', 'styles');
gulp.watch('app/js/*.js', 'scripts');
gulp.watch('app/img/*', 'images');
});
// Default Task
gulp.task('default', gulp.parallel('styles', 'scripts', 'images', 'watch'));
If I run the images, scripts or css task alone it works. I had to add the return in the tasks - this wasn't in the book but googling showed me this was required.
The problem I have is that the default task errors:
[18:41:59] Error: watching app/css/*.css: watch task has to be a function (optionally generated by using gulp.parallel or gulp.series)
at Gulp.watch (/media/sf_VM_Shared_Dev/webdevadvlocal/gulp/public_html/gulp-book/node_modules/gulp/index.js:28:11)
at /media/sf_VM_Shared_Dev/webdevadvlocal/gulp/public_html/gulp-book/gulpfile.js:36:10
at taskWrapper (/media/sf_VM_Shared_Dev/webdevadvlocal/gulp/public_html/gulp-book/node_modules/undertaker/lib/set-task.js:13:15)
at bound (domain.js:287:14)
at runBound (domain.js:300:12)
at asyncRunner (/media/sf_VM_Shared_Dev/webdevadvlocal/gulp/public_html/gulp-book/node_modules/async-done/index.js:36:18)
at nextTickCallbackWith0Args (node.js:419:9)
at process._tickCallback (node.js:348:13)
at Function.Module.runMain (module.js:444:11)
at startup (node.js:136:18)
I think it is because there is also no return in the watch task. Also the error message isn't clear - at least to me. I tried adding a return after the last gulp.watch() but that didn't work either.
In gulp 3.x you could just pass the name of a task to gulp.watch() like this:
gulp.task('watch', function() {
gulp.watch('app/css/*.css', ['styles']);
gulp.watch('app/js/*.js', ['scripts']);
gulp.watch('app/img/*', ['images']);
});
In gulp 4.x this is no longer the case. You have to pass a function. The customary way of doing this in gulp 4.x is to pass a gulp.series() invocation with only one task name. This returns a function that only executes the specified task:
gulp.task('watch', function() {
gulp.watch('app/css/*.css', gulp.series('styles'));
gulp.watch('app/js/*.js', gulp.series('scripts'));
gulp.watch('app/img/*', gulp.series('images'));
});
GULP-V4.0
It is a bit late to answer this right now but still. I was stuck in this problem as well and this is how I got it working.
In detail analysis what I was doing wrong
I forgot to call the reload function when the watch noticed some changes in my html files.
Since fireUp and KeepWatching are blocking. They need to be started in parallel rather than serially. So I used the parallel function in the variable run.
thanks for all
gulp.task('watch', function(){
gulp.watch('app/sass/**/*.sass', gulp.series('sass'));
});
for version gulp 4.xx
It worked for me in Gulp 4.0
gulp.task('watch', function() {
gulp.watch('src/images/*.png', gulp.series('images'));
gulp.watch('src/js/*.js', gulp.series('js'));
gulp.watch('src/scss/*.scss', gulp.series('css'));
gulp.watch('src/html/*.html', gulp.series('html'));
});
//Check what worked for me
gulp.task('watch', function(){
gulp.watch('css/shop.css', gulp.series(['shop']));
});
In my case, work for me this:
(in gulpfile.js)
(install: gulp, gulp sass)
var gulp = require('gulp');
var sass = require('gulp-sass')(require('sass'));
var cssDest = 'style';
var cssInputFile = 'source/style.scss';
var watchedFiles = 'source/**/*.scss';
gulp.task('buildcss', function(){
return gulp.src(cssInputFile)
.pipe(sass({
outputStyle: 'compressed'
}))
.pipe(gulp.dest(cssDest));
});
gulp.task('watch', function(){
gulp.watch(watchedFiles, gulp.series(['buildcss']));
});
Commend: gulp watch
(v 4.0)
On my side, I also had to add "{usePolling: true}" this to get it working:
gulp.watch(paths.js_src + '/*.js', {usePolling: true}, gulp.series(projectScripts, ondemandProjectScripts))
I think it's because my code runs into a docker container.

Import / read variable from separate gulp file

I'm looking to split my gulpfile.js assets or src variables into separate files so that I can manage them better. For example:
....
var scripts = ['awful.js', 'lot.js', 'of.js', 'js.js', 'files.js']
....(somewhere down the line)
gulp.task('vendorjs', function() {
return gulp.src(scripts)
.pipe(concat('vendor.js'))
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(gulp.dest(paths.root + 'dist'))
.pipe(notify({ message: 'vendorjs task completed' }));
});
So what I'm basically interested if theres a way to actually move to a separate file the scripts variable and be able to access it from gulpfile.js.
I've been looking into something like:
require("fs").readFile('gulp/test.js', function(e, data) {
//(test.js would be the file that holds the scripts var)
});
Howerver while it does read the contents of the file, I still can't access it from the gulpfile.js. Any tips or ideas are much appreciated.
Node.js allows you to import other files using require(). It supports three types of files:
JSON files. See DavidDomain's answer for that.
Binary Node.js addons. Not useful for your use case.
JavaScript files. That's what you want.
For JavaScript files the value returned from require() is the one that is assigned to module.exports in the imported file.
So for your use case:
gulp/test.js
var arrayOfFiles = ["awful.js", "lots.js"];
arrayOfFiles.push("of.js");
arrayOfFiles.push("js.js");
arrayOfFiles.push("files.js");
for (var i = 0; i < 10; i++) {
arrayOfFiles.push("some_other_file" + i + ".js");
}
module.exports = {
scripts: arrayOfFiles
};
gulpfile.js
var test = require('gulp/test.js');
gulp.task('vendorjs', function() {
return gulp.src(test.scripts)
.pipe(concat('vendor.js'))
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(gulp.dest(paths.root + 'dist'))
.pipe(notify({ message: 'vendorjs task completed' }));
});
You could use a json file to store your assets or source file location in and load that into your gulp file.
For example:
// config.json
{
"scripts": ["awful.js", "lot.js", "of.js", "js.js", "files.js"]
}
And in your gulp file you would do
// gulpfile.js
var config = require('./config');
var scripts = config.scripts;
console.log(scripts);

minify css/js into their individual files

I have this default gulp file from a Visual Studio template:
/// <binding BeforeBuild='clean, minPreBuild' />
"use strict";
var gulp = require("gulp"),
rimraf = require("rimraf"),
concat = require("gulp-concat"),
cssmin = require("gulp-cssmin"),
uglify = require("gulp-uglify");
var webroot = "./wwwroot/";
var paths = {
js: webroot + "js/**/*.js",
minJs: webroot + "js/**/*.min.js",
css: webroot + "css/**/*.css",
minCss: webroot + "css/**/*.min.css",
concatJsDest: webroot + "js/_site.min.js",
concatCssDest: webroot + "css/_site.min.css"
};
gulp.task("clean:js", function (cb) {
rimraf(paths.concatJsDest, cb);
});
gulp.task("clean:css", function (cb) {
rimraf(paths.concatCssDest, cb);
});
gulp.task("clean", ["clean:js", "clean:css"]);
gulp.task("min:js", function () {
return gulp.src([paths.js, "!" + paths.minJs], { base: "." })
.pipe(concat(paths.concatJsDest))
.pipe(uglify())
.pipe(gulp.dest("."));
});
gulp.task("min:css", function () {
return gulp.src([paths.css, "!" + paths.minCss])
.pipe(concat(paths.concatCssDest))
.pipe(cssmin())
.pipe(gulp.dest("."));
});
gulp.task("min", ["min:js", "min:css"]);
gulp.task("minPreBuild", ["min:js", "min:css"]);
The problem I'm having is one of my js files in the directory has a dependency on knockout, but I'm only using knockout on one of the pages on the site. I don't want to include knockout on my shared view, and the default bundling all files into a single file causes a JS error "ko is undefined" as one of the JS files is dependent on KO.
Is there a way that I can minify files individually, without concatting it into the main "site.min.css"?
First you need to exclude the Knockout file from your min:js task. Prepending a path with ! tells gulp to ignore that file:
gulp.task("min:js", function () {
return gulp.src([
paths.js,
"!" + paths.minJs,
"!js/path/to/knockout.js" // don't include knockout in _site.min.js
], { base: "." })
.pipe(concat(paths.concatJsDest))
.pipe(uglify())
.pipe(gulp.dest("."));
});
Then you need to create a new task min:knockout that does nothing but minify your Knockout file. You'll probably want the minified file to end with a .min.js extension so you'll have to install the gulp-rename plugin as well.
var rename = require('gulp-rename');
gulp.task("min:knockout", function () {
return gulp.src("js/path/to/knockout.js", { base: "." })
.pipe(rename("js/_knockout.min.js"))
.pipe(uglify())
.pipe(gulp.dest("."));
});
Finally you need to make sure your new min:knockout task is executed when running the min and minPreBuild tasks:
gulp.task("min", ["min:js", "min:knockout", "min:css"]);
gulp.task("minPreBuild", ["min:js", "min:knockout", "min:css"]);

Modify file in place (same dest) using Gulp.js and a globbing pattern

I have a gulp task that is attempting to convert .scss files into .css files (using gulp-ruby-sass) and then place the resulting .css file into the same place it found the original file. The problem is, since I'm using a globbing pattern, I don't necessarily know where the original file is stored.
In the code below I'm trying to use gulp-tap to tap into the stream and figure out the file path of the current file the stream was read from:
gulp.task('convertSass', function() {
var fileLocation = "";
gulp.src("sass/**/*.scss")
.pipe(sass())
.pipe(tap(function(file,t){
fileLocation = path.dirname(file.path);
console.log(fileLocation);
}))
.pipe(gulp.dest(fileLocation));
});
Based on the output of the console.log(fileLocation), this code seems like it should work fine. However, the resulting CSS files seem to be placed one directory higher than I'm expecting. Where it should be project/sass/partials, the resulting file path is just project/partials.
If there's a much simplier way of doing this, I would definitely appreciate that solution even more. Thanks!
As you suspected, you are making this too complicated. The destination doesn't need to be dynamic as the globbed path is used for the dest as well. Simply pipe to the same base directory you're globbing the src from, in this case "sass":
gulp.src("sass/**/*.scss")
.pipe(sass())
.pipe(gulp.dest("sass"));
If your files do not have a common base and you need to pass an array of paths, this is no longer sufficient. In this case, you'd want to specify the base option.
var paths = [
"sass/**/*.scss",
"vendor/sass/**/*.scss"
];
gulp.src(paths, {base: "./"})
.pipe(sass())
.pipe(gulp.dest("./"));
This is simpler than numbers1311407 has led on. You don't need to specify the destination folder at all, simply use .. Also, be sure to set the base directory.
gulp.src("sass/**/*.scss", { base: "./" })
.pipe(sass())
.pipe(gulp.dest("."));
gulp.src("sass/**/*.scss")
.pipe(sass())
.pipe(gulp.dest(function(file) {
return file.base;
}));
Originally answer given here: https://stackoverflow.com/a/29817916/3834540.
I know this thread is old but it still shows up as the first result on google so I thought I might as well post the link here.
This was very helpful!
gulp.task("default", function(){
//sass
gulp.watch([srcPath + '.scss', '!'+ srcPath +'min.scss']).on("change", function(file) {
console.log("Compiling SASS File: " + file.path)
return gulp.src(file.path, { base: "./" })
.pipe(sass({style: 'compressed'}))
.pipe(rename({suffix: '.min'}))
.pipe(sourcemaps.init())
.pipe(autoprefixer({
browsers: ['last 2 versions'],
cascade: false
}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest("."));
});
//scripts
gulp.watch([srcPath + '.js','!'+ srcPath + 'min.js']).on("change", function(file) {
console.log("Compiling JS File: " + file.path)
gulp.src(file.path, { base: "./" })
.pipe(uglify())
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest("."));
});
})
if you want to save all files in their own path in the dist folder
const media = () => {
return gulp.src('./src/assets/media/**/*')
.pipe(gulp.dest(file => file.base.replace('src', 'dist'))
)
}
const watch = () => {
gulp.watch(
"./src/**/*",
media
);
};

Categories