I want to implement very simple chain of tasks in my project by Gulp:
Copy all files;
Replace some placeholders with values;
Minify some
files;
And for these purposes I have created gulpfile with such main task:
gulp.task(tasks.build, [
tasks.simplyCopy,
tasks.minifyXml,
tasks.minifyJs,
tasks.subst]);
It's a pretty simple and self describable.
Below I wrote full gulpfile.js:
var gulp = require('gulp');
var prettyData = require('gulp-pretty-data');
var uglify = require('gulp-uglify');
var renvy = require('gulp-renvy');
var tasks = {
simplyCopy: "simply-copy",
minifyXml: "minify-xml",
minifyJs: "minify-js",
subst: "renvy-subst",
build: "build"
};
// Collection of tasks
gulp.task(tasks.build, [tasks.simplyCopy, tasks.minifyXml, tasks.minifyJs,
tasks.subst]);
// By this task sources simply copy to the destination
var destination = 'dist/';
gulp.task(tasks.simplyCopy, function () {
gulp.src(['Source/**/*.*', '!Source/www/res/strings/*.*'], {base:
'Source/www'})
.pipe(gulp.dest(destination));
});
var stringsDestPath = 'dist/res/strings/';
var stringSrcPath = 'Source/www/res/strings/';
// By this task some xml files minify
gulp.task(tasks.minifyXml, [tasks.simplyCopy], function() {
gulp.src(stringSrcPath + '*.xml')
.pipe(prettyData({
type: 'minify',
preserveComments: true,
extensions: {
'xlf': 'xml',
'svg': 'xml'
}
}))
.pipe(gulp.dest(stringsDestPath))
});
var placeholder = {
'%version%': {'prod':'010.00', 'dev':'010.00'}
};
// By this task in some files placeholders replaces with value
gulp.task(tasks.subst, [tasks.minifyXml, tasks.minifyJs], function(){
return gulp.src(stringsDestPath + '*.*')
.pipe(renvy(placeholder, 'dev'))
.pipe(gulp.dest(stringsDestPath));
});
// By this task some js files minify
gulp.task(tasks.minifyJs, [tasks.simplyCopy], function () {
gulp.src(stringSrcPath + '*.js')
.pipe(uglify())
.pipe(gulp.dest(stringsDestPath))
});
But I have such unexpected behavior:
replacing of placeholders is not happening, but it's executes.
[16:29:51] Using gulpfile C:\PDDirectory\Workspace\src\some_workbench\User_Part\gulpfile.js
[16:29:51] Starting 'simply-copy'...
[16:29:51] Finished 'simply-copy' after 17 ms
[16:29:51] Starting 'minify-xml'...
[16:29:51] Finished 'minify-xml' after 7.49 ms
[16:29:51] Starting 'minify-js'...
[16:29:51] Finished 'minify-js' after 5.84 ms
[16:29:51] Starting 'renvy-subst'...
[16:29:51] Finished 'renvy-subst' after 28 ms
[16:29:51] Starting 'build'...
[16:29:51] Finished 'build' after 5.66 ?s
Task tasks.subst executed sepparetly works fine, but in a chain with other tasks, I see results of executing copy and minify only.
Why so?
Place tasks.subst has the sole dependency for tasks.build
gulp.task(tasks.build, [tasks.subst]);
Since tasks.subst requires all the others, the ordering should be correct and adding all the other tasks may lead to ordering problems.
From the gulp.task documentation:
Note: Are your tasks running before the dependencies are complete?
Make sure your dependency tasks are correctly using the async run
hints: take in a callback or return a promise or event stream.
To ensure that a task dependencies are fulfilled before executing it, Gulp needs each task to return a stream or a promise, or call the task function callback parameter.
In your case, the following task should just return the stream:
tasks.minifyXml
tasks.minifyJs
tasks.simplyCopy
For example:
gulp.task(tasks.minifyXml, [tasks.simplyCopy], function(done) {
// just return the task stream here
return gulp.src(stringSrcPath + '*.xml')
.pipe(prettyData({
// ...
}))
.pipe(gulp.dest(stringsDestPath));
});
or using the callback when it's not possible to return a stream:
gulp.task('somename', function(done) {
// async function which does not return a stream like other gulp functions
getFilesAsync(function(err, res) {
// pass any errors to the callback
if (err) return done(err);
var stream = gulp.src(res)
.pipe(minify())
.pipe(gulp.dest('build'))
.on('end', done); // use the callback when it's done
});
});
Related
I'm in the process of migrating from gulp#3.9.1 to gulp#4.0.2 and upgrading my gulp dependencies in the process. I have the following task in my gulpfile, where you can assume directories is just an array of directories I want to perform this operation on:
var gulp = require('gulp');
var ngAnnotate = require('gulp-ng-annotate'); //annotates dependencies in Angular components
var rev = require('gulp-rev'); //appends a hash to the end of file names to eliminate stale cached files
var revReplace = require('gulp-rev-replace');
var uglify = require('gulp-uglify'); // minimizes javascript files
var compressCss = require('gulp-minify-css');
var useref = require('gulp-useref'); // replaces style and script blocks in HTML files
var filter = require('gulp-filter');
var merge = require('merge-stream');
var sourcemaps = require('gulp-sourcemaps');
function minify() {
var tasks = directories.map(function (directory) {
var cssFilter = filter("**/all.min.css", {restore:true});
var jsAppFilter = filter("**/app.min.js", {restore:true});
var jsFilter = filter("**/*.js", {restore:true});
return gulp.src(dstBasePath + directory + "index.html", {allowEmpty: true})
.pipe(useref())
.pipe(cssFilter)
.pipe(compressCss({keepSpecialComments:false}))
.pipe(rev())
.pipe(cssFilter.restore)
.pipe(jsAppFilter)
.pipe(sourcemaps.init())
.pipe(ngAnnotate({add:true, single_quotes:true}))
.pipe(jsAppFilter.restore)
.pipe(jsFilter)
.pipe(uglify())
.pipe(rev())
.pipe(jsFilter.restore)
.pipe(revReplace())
.pipe(sourcemaps.write('.')) // sourcemaps need to be written to same folder for Datadog upload to work
.pipe(gulp.dest(dstBasePath + directory))
});
return merge(tasks);
}
Why would this result in the error "Did you forget to signal async completion?" from Gulp when running the task? Note that I'm using Gulp 4. I've tried passing a callback done to this task, and adding .addListener('end', done) to the final pipe, but this causes my merged stream to end prematurely (presumably when the first one ends). So perhaps one of these plugins is not signaling when it's completed, but how would you even get this to work otherwise? Thanks for any insight you can provide.
return merge(folders.map(function (folder) { // this has worked for me in the past
as has this form without merge
gulp.task('init', function (done) {
var zips = getZips(zipsPath);
var tasks = zips.map(function (zip) {
return gulp.src(zipsPath + "/" + zip)
.pipe(unzip({ keepEmpty: true }))
.pipe(gulp.dest(path.join("src", path.basename(zip, ".zip"))))
.on('end', function() { // this bit is necessary
done();
});
});
return tasks;
});
Gulp 4 requires that you signal async completion. There's some good information about it in this answer to a similar question:
Gulp error: The following tasks did not complete: Did you forget to signal async completion?
I had a similar case where I was returning a merged set of tasks, and I was able to resolve the error by making the function async and awaiting the merge. My case looked something like this:
gulp.task("build", async function () {
...
return await merge(tasks);
});
so I think you should be able to do something like
async function minify(){
...
return await merge(tasks);
}
Rather new to both gulp and javascript. The script I wrote is returning an error (appended at the end of the post.)
This is the minimal example file:
const {src, dest, series, parallel }= require('gulp');
const sourceList = ['about', 'contact', 'projects'];
// Next 2 functions take each html file and move them to respective dist folder.
function eachHtml(){
sourceList.forEach(function(htmlFile){
cphtmlTask(`source/${htmlFile}/${htmlFile}.html`, `dist/${htmlFile}/`)
});
//cphtmlTask('source/index.html', 'dist/');
}
function cphtmlTask(i,o){
return src(i)
.pipe(dest(o));
}
exports.default = series(eachHtml);
Output
[17:55:19] Starting 'default'...
[17:55:19] Starting 'eachHtml'...
[17:55:19] The following tasks did not complete: default, eachHtml
[17:55:19] Did you forget to signal async completion?
Any help please?
I think all you need is:
function eachHtml(cb){
sourceList.forEach(function(htmlFile){
cphtmlTask(`source/${htmlFile}/${htmlFile}.html`, `dist/${htmlFile}/`)
});
cb();
//cphtmlTask('source/index.html', 'dist/');
}
That cb is a callback function which will signal to gulp that the eachHtml task has completed.
If I have a watcher like this:
gulp.watch('js/**/*.js').on('change', path => {
gulp.series(build, reload)();
});
...and task build would look like this:
const build = done => {
return gulp
.src(path) // Use "path" here
.pipe(
rename({
dirname: ''
})
)
.pipe(uglify())
.pipe(gulp.dest('build'));
};
How can I pass path argument to the build task?
As an exercise I believe I got this working as you wanted. But first let me say that the traditional way of limiting the source pipeline would be with something like gulp-newer. You should see if that accomplishes what you want.
But here is something that may work for you [not well tested!]:
function build (path) {
return new Promise(resolve => {
// using setTimeout() to prove async/await is working as expected
setTimeout(() => {
resolve('resolved');
}, 2000);
// put your gulp.src pipeline here using 'path'
console.log("2 path = " + path);
});
};
function anotherTask (path) {
return new Promise(resolve => {
// put your gulp.src pipeline here
console.log("4 path = " + path); });
};
function testWatch () {
console.log("in testWatch");
// debounceDelay because gulp likes to call the watcher 2 or 3times otherwise
// see [gulp watch task running multiple times when a file is saved][2]
var watcher = gulp.watch('js/**/*.js', { debounceDelay: 2000 });
// I added the async/await because I wasn't sure those functions would be run in series
// as you wanted.
// With the event listener route I couldn't get gulp.series to work,
// so went with async/await.
watcher.on('change', async function(path, stats) {
console.log('1 File ' + path + ' was changed');
await build(path);
console.log("3 after build");
// I would assume that the **last** task in the chain doesn't need 'await'
// or to return a promise as in anotherTask
await anotherTask(path);
console.log("5 after anotherTask");
});
};
gulp.task('default', gulp.series(testWatch));
gulp watch running multiple times mentioned above in code.
Output (my js watch src is different than yours) :
in testWatch
1 File src\js\main.js was changed
2 path = src\js\main.js
3 after build
4 path = src\js\main.js
5 after anotherTask
1 File src\js\taxonomy.js was changed
2 path = src\js\taxonomy.js
3 after build
4 path = src\js\taxonomy.js
5 after anotherTask
As I mentioned in the title there is a problem running gulp.watch. It runs watch only after first change in the file, when I changing second, third and etc it doesn't run task.
Below is my gulpfile.js:
var gulp = require('gulp');
var babel = require('gulp-babel');
var rename = require("gulp-rename");
var del = require('del');
var less = require('gulp-less');
gulp.task('es6', function () {
return gulp.src('./test.js')
.pipe(rename(function (path) {
path.basename += "-es6";
return path;
}))
.pipe(babel())
.pipe(gulp.dest('./'))
});
gulp.task('clean', function () {
return del('./test-es6.js');
});
gulp.task('watch', function () {
gulp.watch( './test.js', gulp.series('es6') );
console.log('Running watch...');
});
gulp.task('default', gulp.series('clean', 'es6', gulp.parallel('watch') ));
And some logs :
$: gulp
[14:22:40] Using gulpfile /var/www/html/es2015/gulpfile.js
[14:22:40] Starting 'default'...
[14:22:40] Starting 'clean'...
[14:22:40] Finished 'clean' after 11 ms
[14:22:40] Starting 'es6'...
[14:22:43] Finished 'es6' after 2.11 s
[14:22:43] Starting '<parallel>'...
[14:22:43] Starting 'watch'...
Running watch...
[14:22:55] Starting '<series>'...
[14:22:55] Starting 'es6'...
[14:22:55] Finished 'es6' after 42 ms
[14:22:55] Finished '<series>' after 43 ms << first change, but no second third and etc.
I used similar configuration in couple of projects and it was fine, everything worked.
I don't know if this information is important, but I'm using Ubuntu 14.04
After long trying I found a solution for this problem.
I don't know why but this configuration works on Windows, but as appeared on Ubuntu I had to add ** to path of the watched file this part of code:
gulp.task('watch', function () {
gulp.watch( './**/test.js', gulp.series('es6') );
console.log('Running watch...');
});
Update: Seems like this is a bug in gulp-protractor. On their github page they filed it as a bug and will take a look into it. Source: https://github.com/mllrsohn/gulp-protractor/issues/64
Only possible workaround you can do until the bug is resolved is change the directory of your project to something that doesn't include spaces.
So I'm trying to get an Aurelia project started including front end unit testing. Here is where the problem starts. When I try to run the e2e gulp task I get the following error:
[10:45:44] using gulpfile ~\Documents\Visual Studio 2013\Projects\ProjectX\ProjectX\gulpfile.js
[10:45:44] Starting 'build-e2e'...
[10:45:44] Finished 'build-e2e' after 207 ms
[10:45:44] Starting 'e2e'...
'C:\Users\jorisd\Documents\Visual' is not recognized as an internal or external command, operable program or batch file.
C:\Users\jorisd\Documents\Visual Studio 2013\Projects\ProjectX\ProjectX\build\tasks\e2e.js:34
.on('error', function(e) {throw e; });
Error: protractor exited with code 1
Basically it's the highlighted code that has the problem. Since my path includes a space, it'll stop there for some reason.
Here's how my e2e.js file looks like right now:
var gulp = require('gulp');
var paths = require('../paths');
var to5 = require('gulp-babel');
var plumber = require('gulp-plumber');
var webdriverUpdate = require('gulp-protractor').webdriver_update;
var webdriverStandalone = require("gulp-protractor").webdriver_standalone;
var protractor = require('gulp-protractor').protractor;
// for full documentation of gulp-protractor,
// please check https://github.com/mllrsohn/gulp-protractor
gulp.task('webdriver-update', webdriverUpdate);
gulp.task('webdriver-standalone', ['webdriver-update'], webdriverStandalone);
// transpiles files in
// /test/e2e/src/ from es6 to es5
// then copies them to test/e2e/dist/
gulp.task('build-e2e', function() {
return gulp.src(paths.e2eSpecsSrc)
.pipe(plumber())
.pipe(to5())
.pipe(gulp.dest(paths.e2eSpecsDist));
});
// runs build-e2e task
// then runs end to end tasks
// using Protractor: http://angular.github.io/protractor/
gulp.task('e2e', ['build-e2e'], function(cb) {
return gulp.src(paths.e2eSpecsDist + '/*.js')
.pipe(protractor({
configFile: '/protractor.conf.js',
args: ['--baseUrl', 'http://127.0.0.1:9000']
}))
.on('end', function() { process.exit(); })
.on('error', function(e) { throw e; });
});
The problem is situating in the e2e task with the configFile option.
I tried change the line into the following:
configFIle: __dirname + '/protractor.conf.js',
But this aswell without result. If any of you know a workaround for including spaces in the configFile path, I'll be happy to hear it.
For me its working fine.
var angularProtractor = require('gulp-angular-protractor');
gulp.task('test', function (callback) {
gulp
.src([__dirname+'/public/apps/adminapp/**/test/**_test.js'])
.pipe(angularProtractor({
'configFile': 'public/apps/adminapp/app.test.config.js',
'debug': false,
'args': ['--suite', 'adminapp'],
'autoStartStopServer': true
}))
.on('error', function(e) {
console.log(e);
})
.on('end',callback);
});