Task dependencies in Gulp - gulp

There is the following gulpfile.js
const { watch, src, dest, parallel, series } = require('gulp')
const uglify = require('gulp-uglify')
const browserSync = require('browser-sync').create()
const htmlMin = require('gulp-htmlmin')
const cleanCSS = require('gulp-clean-css')
const imagemin = require('gulp-imagemin')
const hash = require('gulp-hash') // !!!
const references = require('gulp-hash-references') // !!!
const del = require('del')
const path = require('path')
const manifestFile = 'asset-manifest.json'
const buildDir = './build'
function serve() {
browserSync.init({
server: {
baseDir: "./"
}
})
watch("./*.html").on('change', browserSync.reload)
watch("./css/**/*.css").on('change', browserSync.reload)
watch("./**/*.js").on('change', browserSync.reload)
}
function buildHTML(cb) {
src('index.html')
.pipe(references(manifestFile)) // replace file paths in index.html according to the manifest
.pipe(htmlMin({
collapseWhitespace: true
}))
.pipe(dest(buildDir))
cb()
}
function buildCSS(cb) {
src('./css/**/*.css')
.pipe(cleanCSS())
.pipe(hash())
.pipe(dest(path.join(buildDir, 'css')))
.pipe(hash.manifest(manifestFile)) // generate a manifest file
.pipe(dest('.'))
cb()
}
function buildJS(cb) {
src(['./**/*.js', '!./node_modules/**', '!./gulpfile.js'])
.pipe(uglify())
.pipe(hash())
.pipe(dest('build/'))
.pipe(hash.manifest(manifestFile)) // generate a manifest file
.pipe(dest('.'))
cb()
}
function buildImages(cb) {
src('./img/**/*.png')
.pipe(imagemin([
imagemin.optipng({ optimizationLevel: 7 })
]))
.pipe(dest(path.join(buildDir, 'img')))
cb()
}
exports.build = series(buildJS, buildCSS, buildHTML) // !!!
exports.default = serve
I'm trying to hash *.css and *.js file names and replace their old names with hashed ones in the build/index.html file. But the problem is that the function "buildHTML" starts working earlier than the "asset-manifest.json" file created. What am I doing wrong?

You have to return the streams created by your functions to ensure that they run in the expected order and to catch any possible errors. No need to use a callback:
function buildHTML() {
return src('index.html')
.pipe(references(manifestFile)) // replace file paths in index.html according to the manifest
.pipe(htmlMin({
collapseWhitespace: true
}))
.pipe(dest(buildDir));
}
function buildCSS() {
return src('./css/**/*.css')
.pipe(cleanCSS())
.pipe(hash())
.pipe(dest(path.join(buildDir, 'css')))
.pipe(hash.manifest(manifestFile)) // generate a manifest file
.pipe(dest('.'));
}
function buildJS() {
return src(['./**/*.js', '!./node_modules/**', '!./gulpfile.js'])
.pipe(uglify())
.pipe(hash())
.pipe(dest('build/'))
.pipe(hash.manifest(manifestFile)) // generate a manifest file
.pipe(dest('.'));
}
function buildImages() {
return src('./img/**/*.png')
.pipe(imagemin([
imagemin.optipng({ optimizationLevel: 7 })
]))
.pipe(dest(path.join(buildDir, 'img')));
}

Related

Gulp 4 array as source

I'm attempting to upgrade to Gulp 4 in an existing project. I have created a task called vendor with the intent of concatenating and minifying global javascript packages. Unfortunately I'm receiving an error when compiling with the following code:
function vendor() {
const source = [
'./node_modules/#popperjs/core/dist/umd/popper.js',
'./node_modules/bootstrap/dist/js/bootstrap.js',
'./node_modules/slick-carousel/slick/slick.js'
];
return src(source)
.pipe(changed(source))
.pipe(concat('vendor.js'))
.pipe(uglify())
.pipe(rename({
extname: '.min.js'
}))
.pipe(dest('./dist/js/'))
}
exports.build = series(parallel(vendor, js));
The error that I'm receiving is TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type object.
This on my side functional (with path that I had on my project). Can you try this task and see if it works well ?
const {src, dest, task} = require("gulp");
const stripDebug = require('gulp-strip-debug');
const logger = require('node-color-log');
const uglify = require('gulp-uglify');
const source = [
'./node_modules/#popperjs/core/dist/umd/popper.js',
'./node_modules/bootstrap/dist/js/bootstrap.js',
'./node_modules/slick-carousel/slick/slick.js'
];
const jsDest = "./dist/js/";
function compressJs(callback) {
logger.color('yellow').log(`Removing console.log() and uglifying js from ${source} to: ${jsDest}`);
src(source)
.pipe(stripDebug())
.pipe(uglify())
.pipe(dest(`${jsDest}`))
.on('end', function () {
callback();
});
}
const Js = task('compress:js', compressJs);
exports.Js = Js;

Gulp 4 tasks do not run in parallel

I have migrated from gulp 3 to 4. Everything was fine for a week, and then my build pipeline broke. I have a hugo website that should be rebuilt on gulp build.
The build task calls three other tasks in parallel: gulp.parallel("css", "js", "hugo");
When running gulp build, gulp claims it succeeded in 2.19 ms, which is too fast. These three task are supposed to output files to my dist folder, but it does not run my tasks at all.
Running the css, js, and hugo tasks manually in the terminal works as expected.
I am fairly new to gulp 4, so I suspect I am missing some detail. Here is my gulpfile:
import gulp from "gulp";
import cp from "child_process";
import gutil from "gulp-util";
import postcss from "gulp-postcss";
import cssImport from "postcss-import";
import cssnext from "postcss-cssnext";
import BrowserSync from "browser-sync";
import webpack from "webpack";
import webpackConfig from "./webpack.conf";
import cssnano from "cssnano";
import imagemin from "gulp-imagemin";
import imageminMozjpeg from "imagemin-mozjpeg";
import webp from "imagemin-webp";
import gm from "gulp-gm";
const browserSync = BrowserSync.create();
const hugoBin = `./bin/hugo.${process.platform === "win32" ? "exe" : process.platform}`;
const defaultArgs = ["-d", "../dist", "-s", "site"];
if (process.env.DEBUG) {
defaultArgs.unshift("--debug");
}
const hugo = (cb) => {
buildSite(cb);
};
const hugoPreview = (cb) => {
buildSite(cb, gulp.parallel("--buildDrafts", "--buildFuture"));
cb();
};
const build = (cb) => {
gulp.parallel("css", "js", "hugo");
cb();
};
const buildPreview = (cb) => {
gulp.parallel("css", "js", "hugoPreview");
cb();
};
const css = (cb) => {
gulp.src("./src/css/*.css")
.pipe(postcss([
cssImport({
from: "./src/css/main.css"
}),
cssnext(),
cssnano(),
]))
.pipe(gulp.dest("./dist/css"))
.pipe(browserSync.stream());
cb();
};
const js = (cb) => {
const myConfig = Object.assign({}, webpackConfig);
webpack(myConfig, (err, stats) => {
if (err) throw new gutil.PluginError("webpack", err);
gutil.log("[webpack]", stats.toString({
colors: true,
progress: true
}));
browserSync.reload();
cb();
});
};
const webpConvert = (cb) => {
gulp.src("./dist/img/**/*")
.pipe(gm((gmfile) => {
return gmfile.colorspace("rgb");
}))
.pipe(imagemin([
webp({
quality: 75
})
]))
.pipe(gulp.dest("./dist/webp"));
cb();
};
const imgSquash = (cb) => {
return gulp.src("./site/static/img/**/*")
.pipe(imagemin([
imagemin.gifsicle({
interlaced: true,
optimizationLevel: 3
}),
imagemin.jpegtran({
progressive: true
}),
imageminMozjpeg({
quality: 80
}),
imagemin.optipng({
optimizationLevel: 5
}),
imagemin.svgo({
plugins: [{
removeViewBox: true
},
{
cleanupIDs: false
}
]
})
]))
.pipe(gulp.dest("./dist/img"));
};
const server = (cb) => {
browserSync.init({
server: {
baseDir: "./dist"
}
});
gulp.watch("./src/js/**/*.js", js);
gulp.watch("./src/css/**/*.css", css);
gulp.watch("./site/**/*", hugo);
cb();
};
const buildSite = (cb, options) => {
const args = options ? defaultArgs.concat(options) : defaultArgs;
return cp.spawn(hugoBin, args, {
stdio: "inherit"
}).on("close", (code) => {
if (code === 0) {
browserSync.reload("notify:false");
cb();
} else {
browserSync.notify("Hugo build failed :(");
cb("Hugo build failed");
}
});
};
export {
hugo,
hugoPreview,
build,
buildPreview,
css,
js,
webpConvert,
imgSquash,
server
};
When you execute callback in your tasks, gulp thinks that task is finished. Instead of calling callback you should return stream, so that gulp knows when task is finished.
You should change your tasks in something similar like this:
const css = (cb) => {
return gulp.src("./src/css/*.css")
.pipe(postcss([
cssImport({
from: "./src/css/main.css"
}),
cssnext(),
cssnano(),
]))
.pipe(gulp.dest("./dist/css"))
.pipe(browserSync.stream());
// cb(); --comment this line
};
Add 'return' and comment line with cb();

Gulp task not finishing

Being new to gulp. I have the follwing task. I need to spawn a webserver and then another script has to run some stuff against this webserver. I am currently struggling with finishing the script because the browser-sync task does not finish and prevents the script from exit.
'use strict';
const browserSync = require('browser-sync').create();
const cp = require('child_process');
const minimalcss = require('minimalcss');
const gulp = require('gulp');
const clean = require('gulp-clean');
const sourceDir = "_site/";
const deployDir = "public/";
// build the mkdocs Site
gulp.task('build', function() {
return cp.exec('pipenv run mkdocs build --site-dir ' + sourceDir);
});
// Delete _deploy directory first
gulp.task('prepare', function() {
return gulp.src(deployDir, {read: false, allowEmpty: true})
.pipe(clean());
});
// Delete _deploy directory again // just for testing
gulp.task('cleanup', function() {
return gulp.src(deployDir, {read: false, allowEmpty: true})
.pipe(clean());
});
// does not lead to anything, just for testing
gulp.task('inlinecriticalCSS', function(done) {
minimalcss
.minimize({ urls: ['http://localhost:9999/' + 'index.html'] })
.then(result => {
console.log('OUTPUT', result.finalCss.length, result.finalCss);
})
.catch(error => {
console.error(`Failed the minimize CSS: ${error}`);
});
done();
});
// webserver
gulp.task('serve', (done) => {
browserSync.init({
port: 9999,
server: {
baseDir: sourceDir
}
});
done();
});
// default sequence
gulp.task('default', gulp.series(
'prepare',
'build',
'serve',
'inlinecriticalCSS',
'cleanup')
);

Gulp Watch tasks finishing early

I have a gulp file that runs Sass and injects my CSS, app and Bower js files in separate tasks. I would like, at the end of the task, to watch my SCSS files and run Sass on change, and application code and inject new files (with a view to livereload when I can get this working).
Unfortunately, I've run into a problem where my watch tasks end early, therefore no changes are being watched for.
I've read in another question that the watch tasks have to be returned, however, this did not help...
Here is my gulpfile (with prod tasks removed)
const gulp = require('gulp')
// plugins
const concat = require('gulp-concat')
const uglify = require('gulp-uglify')
const rename = require('gulp-rename')
const closure = require('gulp-jsclosure')
const rev = require('gulp-rev')
const sass = require('gulp-sass')
const cssmin = require('gulp-cssmin')
const bower = require('main-bower-files')
const strip = require('gulp-strip-comments')
const inject = require('gulp-inject')
const ngannotate = require('gulp-ng-annotate')
const mainBowerFiles = require('main-bower-files')
const templateCache = require('gulp-angular-templatecache')
const minifyHtml = require('gulp-minify-html')
const path = require('path')
const babel = require('gulp-babel')
const es = require('event-stream')
// configuration variables
const config = {
dir: {
root: 'client/',
app: './Dist/',
vendor: './Dist/',
css: 'client/',
cssMin: './Dist/',
bower: 'client/wwwroot/lib',
index: './Views/Shared/_Layout.cshtml',
indexDir: './Views/Shared',
modules: 'client/app/modules'
},
filters: {
app: 'client/app.js',
appModules: 'client/app/modules/**/*.module.js',
appModuleFiles: 'client/app/modules/**/*.js',
vendors: 'client/vendors/**/*.js',
templates: 'client/app/modules/**/*.html',
client: 'client/app/css/**/*.scss'
}
}
//----------CSS---------
gulp.task('sass', () => {
return gulp.src(['client/app/css/bootstrap.scss', 'client/app/css/app.scss', 'client/app/css/themes/theme-f.scss'])
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('build/css'));
})
gulp.task('inject-css', ['sass'], () => {
var sources = gulp.src(['build/css/bootstrap.css', 'build/css/app.css', 'build/css/theme-f.css'], { read: false }, { name: 'css' });
return gulp.src(config.dir.index)
.pipe(inject(sources))
.pipe(gulp.dest(config.dir.indexDir));
})
//--------End CSS-------
//----------App---------
gulp.task('inject-js', ['inject-bower'], () => {
var sources = gulp.src([config.filters.app, config.filters.appModules, config.filters.appModuleFiles], { read: false });
return gulp.src(config.dir.index)
.pipe(inject(sources))
.pipe(gulp.dest(config.dir.indexDir));
})
//--------End App-------
//---------Vendor-------
gulp.task('inject-bower', ['inject-css'], () => {
let bower = gulp.src(mainBowerFiles(), { read: false }, { relative: true })
return gulp.src(config.dir.index)
// .pipe(inject(es.merge(bower, vendors), { name: 'vendor' }))
.pipe(inject(bower, { name: 'vendor' }))
.pipe(gulp.dest(config.dir.indexDir));
})
//-------End Vendor-----
//----------Prod--------
//---------Watches-------
gulp.task('scripts:watch', () => {
return gulp.watch([config.filters.app, config.filters.appModuleFiles], ['inject-js']);
})
gulp.task('sass:watch', () => {
return gulp.watch(config.filters.scss, ['sass']);
})
gulp.task('watch', ['scripts:watch', 'sass:watch'], () => {
console.log(" ");
console.log("Watching for changes...");
console.log(" ");
})
//-------End Watches-----
//----------Tasks--------
gulp.task('default', ['inject-js', 'inject-bower', 'inject-css',' watch'], () => {
// gulp.watch([config.filters.app, config.filters.appModuleFiles], ['inject-js'])
// gulp.watch(config.filters.scss, ['sass'])
})
As you can probably see from the commented out code, I have also tried running these watched directly inside of the default task.
This is the console output from running gulp
[12:48:12] Using gulpfile C:\source\Icon.Admin\src\UI\Icon.Admin\gulpfile.js
[12:48:12] Starting 'scripts:watch'...
[12:48:12] Finished 'scripts:watch' after 145 ms
[12:48:12] Starting 'sass:watch'...
[12:48:12] Finished 'sass:watch' after 180 μs
[12:48:12] Starting 'watch'...
Watching for changes...
[12:48:12] Finished 'watch' after 159 μs
Any help with this is greatly appreciated!
Fixed this by running my watch tasks inside of the main watch task:
gulp.task('watch', [], () => {
console.log(" ");
console.log("Watching for changes...");
console.log(" ");
gulp.watch([config.filters.app, config.filters.appModuleFiles], ['inject-js']);
gulp.watch(config.filters.client, ['sass']);
})
Well, Inside your sass:watch it refers to config.filters.scss but that is no where to be found in the config object. Probably why your scss isn't compiling.
...
gulp.task('scripts:watch', () => {
return gulp.watch([config.filters.app, config.filters.appModuleFiles], ['inject-js']);
})
gulp.task('sass:watch', () => {
return gulp.watch(config.filters.client, ['inject-sass']);
})
gulp.task('default', ['inject-js', 'inject-bower', 'inject-css', 'scripts:watch', 'sass:watch']);
This should be all you need.

Can't load ES6 module with require

I'm using gulp + browserify to compile an es6 to es5 and then trying to require that in another module (neither of these work):
Main = require('mylibrary/dist/main').Main
Main2 = require('mylibrary/dist/main')
Also tried to to export default class Main and tried class Main then export default new Main
I'm sure this is something simple that I'm missing?
es6 class:
export class Main {
constructor(){
console.log('Main!');
}
test(){
console.log('test');
}
}
output (abbreviated):
var Main = exports.Main = function () {
function Main() {
_classCallCheck(this, Main);
console.log('Main!');
}
_createClass(Main, [{
key: 'test',
value: function test() {
console.log('test');
}
}]);
return Main;
}();
gulpfile.js
var gulp = require('gulp');
var browserify = require('browserify');
var source = require("vinyl-source-stream");
var babelify = require("babelify");
gulp.task('browserify', function() {
return browserify({
entries: ['src/main.js'],
debug: true
})
.transform(babelify, {presets: ["es2015", "react"]})
.bundle()
.on("error", function (err) { console.log("Error : " + err.message); })
.pipe(source('main.js'))
.pipe(gulp.dest('./dist'));
});
gulp.task('watch', function() {
gulp.watch('src/*.js', ['browserify']);
gulp.watch('src/*.jsx', ['browserify']);
});
gulp.task('default', ['watch','browserify']);
By default Browserify builds a file meant to be run in a browser, not one that is meant to work with require. You want to use Browserify's standalone option via
return browserify({
entries: ['src/main.js'],
debug: true,
standalone: 'someName',
})