Gulp-header plus merge-stream results in a glitch? - gulp

Here’s some puzzling behavior.
I want to create a gulp task that will 1) build js-files into one file using gulp-requirejs-optimize and place it into the build directory, 2) copy a couple of config js-files into relevant subfolders of the build directory, and 3) add a header to these files.
Here’s how I am attempting to do this:
In a banner.js file, I create a header using gulp-header:
var header = require('gulp-header');
var bannerTemplate = [
'/**',
' * Hello ${name}',
' */'
].join('\n');
var banner = header(bannerTemplate, {name: 'world'});
module.exports = banner;
Then, in the file that is building javascript, I do the following:
var gulp = require('gulp');
var merge = require('merge-stream');
var requirejsOptimize = require('gulp-requirejs-optimize');
var banner = require('./banner.js');
gulp.task('js:build:test', function() {
// this is the entry point for our javascript files;
// will produce a single main.js file
var jsEntry = path.join(global.paths.jsDirectory, 'main.js');
var options = {
baseUrl: global.paths.jsDirectory,
mainConfigFile: path.join(global.paths.jsDirectory,
'libs/customized/requirejs/require.config.js'),
preserveLicenseComments: false
};
var jsOutput = path.join(global.paths.buildDirectory, 'js');
// I am also copying the require.js library and its customization; don't ask why
var jsForCopy = [
path.join(global.paths.jsDirectory, 'libs/vendors/requirejs/require.js'),
path.join(global.paths.jsDirectory, 'libs/customized/requirejs/**/*.js')
];
var requirejsOptimized = gulp.src(jsEntry)
.pipe(requirejsOptimize(options))
.pipe(banner)
.pipe(gulp.dest(jsOutput));
var copiedJS = gulp.src(jsForCopy, {base: global.paths.root})
.pipe(banner) // having this line will cause a glitch
.pipe(gulp.dest(global.paths.buildDirectory));
return merge(requirejsOptimized, copiedJS);
});
So here is where it is getting interesting. If I pipe through my banner only the stream that is building the main.js file (var requirejsOptimized in my code sample), then everything is fine — I get a build folder with correct files and correct structure:
if, however, I also pipe through the banner the stream that is copying other js files (var copiedJS in my code sample), then the structure of my build directory gets all jumbled up:
(notice the duplication of main.js and the absence of the libs folder with its subfolders)
So my question is, am I doing something obviously wrong with my gulp task here? Is it an expected result or is it a glitch of some kind?

I wouldn't reuse the banner stream in both pipelines. Both pipelines are writing to and reading from the same stream. That is why the output is weird.
Instead, use a new banner stream for each pipeline:
Change banner.js so it exports a function that creates a new banner stream
module.exports = function createBannerStream() {
return header(bannerTemplate, {name: 'world'});
};
In your main file invoke the function when you need a banner stream
var requirejsOptimized = gulp.src(jsEntry)
.pipe(requirejsOptimize(options))
.pipe(banner()) // <-- note the function call here
.pipe(gulp.dest(jsOutput));
var copiedJS = gulp.src(jsForCopy, {base: global.paths.root})
.pipe(banner()) // <-- note the function call here
.pipe(gulp.dest(global.paths.buildDirectory));

Related

How do I delete the regular(jpg, png ) images after converting them to webp usging gulp?

I'm new to gulp. Trying to optimize the images and convert them into webp format. I was able to achieve that using gulp-webp. But it seems there are now two version of the images inside my dist/img folder one is the original and a webp version. So how do I get only the webp not the original one inside my dist/img folder?
Here how my project directories look like:
project
|-dist
|-css
|-img
|-js
|-src
|-css
|-img
|-js
gulp.js
...
Here is webp conversion function:
function webpImage() {
return src('dist/img/**/*.{jpg,png}')
.pipe(imagewebp())
.pipe(dest('dist/img'))
}
I would first say you should not delete source file, it is ok to keep them. What you want to do is having to different destinations. One of which should be deployed (the compiled, minified and webp for example) and the other should be version and used in your cdci pipelines perhaps.
But then, if you really want to remove the source file, you can use gulp-clean while being in a gulp script.
Your gulp clean script could look like that :
const { src, task } = require('gulp');
const clean = require("gulp-clean");
const logger = require('node-color-log');
function cleanImagesTask() {
const root = "path/to/images/you/want/to/delete";
logger.color('yellow').log(`Clean images`);
return src(root,{allowEmpty: true},{read: false}).pipe(clean({force:true}));
};
const cleanImagesFolder = task('clean:images', cleanImagesTask);
exports.cleanImagesFolder = cleanImagesFolder;
And if you want to deploy in a different dest, could use something similar to :
const { src, dest, task } = require( 'gulp' );
const logger = require('node-color-log');
function copyImagesToDest(callback) {
const imagesSource = "path/to/your/images/**/*";
const imagesDestination = "path/to/destination/";
logger.color('green').log(`Copy images from ${artifactData} to: ${destination}`);
return src(imagesSource)
.pipe(dest(destination))
.on('end', function () {
logger.color('green').log(`Copy to: ${destination}`);
callback();
});
};
const copyImages = task('copy:images', copyImagesToDest);
exports.copyImages = copyImages ;

How to deal with Access-Control-Allow-Origin for myDrive files

The question arises from this note:
Someone here suggested using div's. The HTML requirement is very
skeletal. The 3D display is basically canvas, but it requires seven
three.js files, ten js files of my own making to exchange parameters
and other variables with the global variable and .dae collada files
for each of the 3D models you can see. If they could be linked in like
jQuery that might be the solution but I wonder about conflicts.
on Questions on extending GAS spreadsheet usefulness
principally, if they can be linked like jQuery part
The files to be linked are on myDrive. The thinking is that if I can copy the files into GAS editor, it seems as secure and more flexible to bring them into the html directly.
code.gs
function sendUrls(){
var folder = DriveApp.getFoldersByName("___Blazer").next();
var sub = folder.getFoldersByName("assembler").next();
var contents = sub.getFiles();
var file;
var data = []
while(contents.hasNext()) {
file = contents.next();
type = file.getName().split(".")[1];
url = file.getUrl();
data.push([type,url]);
}
return data;
}
html
google.script.run.withSuccessHandler(function (files) {
$.each(files,function(i,v){
if(v[0] === "js"){
$.get(v[1])
}
})
})
.sendUrls();
The first url opens the proper script file but the origin file is not recognisable to me.
I am not sure that this is a proper answer as it relies on cors-anywhere, viz:
function importFile(name){
var myUrl = 'http://glasier.hk/cors/tba.html';
var proxy = 'https://cors-anywhere.herokuapp.com/';
var finalURL = proxy + myUrl;
$.get(finalURL,function(data) {
$("body").append(data);
importNset();
})
}
function importNset(){
google.script.run
.withSuccessHandler(function (code) {
path = "https://api.myjson.com/bins/"+code;
$.get(path)
.done((data, textStatus, jqXHR) => {
nset = data;
cfig = nset.cfig;
start();
})
})
.sendCode();
}
var nset,cfig;
$(document).ready(function(){
importFile();
});
but it works, albeit on my machine, using my own website as the resource.
I used the Gas function in gas Shop to make the eight previously tested js files into the single tba.html script only file. I swapped the workshop specific script files for those needed for google.script.run but otherwise that was it. If I could find out how to cors-enable my site, I think I might be able to demonstrate how scripts might be imported to generate different views from the same TBA and spreadsheet interfaces.

gulp-assemble & gulp-watch not recompiling site when changes are made to data, includes or layouts

I'm having issues using gulp-assemble with gulp-watch. I want gulp to watch the entire assemble source directory (data, includes, layouts and pages) and recompile the site when ever a file changes.
I'm able to get this working correctly for pages, but gulp is not recompiling the site when changes are made to the data, includes or layouts files.
I've added a watch task to the example gulpfile.js in the gulp-assemble repository:
var gulp = require('gulp');
var htmlmin = require('gulp-htmlmin');
var extname = require('gulp-extname');
var assemble = require('assemble');
var middleware = require('./examples/middleware');
var gulpAssemble = require('./');
// setup items on the assemble object
assemble.data({site: {title: 'Blog'}});
assemble.data(['test/fixtures/data/*.{json,yml}']);
assemble.layouts(['test/fixtures/layouts/*.hbs']);
assemble.partials(['test/fixtures/includes/*.hbs']);
// arbitrary middleware that runs when files loaded
assemble.onLoad(/index\.hbs/, middleware(assemble));
// render templates in `test/fixtures`
gulp.task('default', function () {
gulp.src('test/fixtures/pages/*.hbs')
.pipe(gulpAssemble(assemble, { layout: 'default' }))
.pipe(htmlmin({collapseWhitespace: true}))
.pipe(extname())
.pipe(gulp.dest('_gh_pages/'));
});
// ============================================================
// my watch task
// ============================================================
gulp.task('watch', ['default'], function() {
gulp.watch('test/fixtures/**/*.{hbs,yml,json}', ['default']);
});
If I run gulp watch and save a change to any of the .hbs files in the pages directory, I see gulp trigger the default in my terminal output, and I see the .html file in _gh_pages update with the change.
However, if I save a change to any of the .hbs, .json, or .yml files in the data, includes or layouts directories, I see gulp trigger the default in my terminal output, but I see no changes to the _gh_pages .html file(s). I have to run the gulp default task manually in order to get the changes applied to the _gh_pages files.
What do I need to change in order to get the desired behaviour?
gulp-watch will only execute code inside the function for the default task, so to get things like data and layouts to reload, you'll need to move those pieces of code to inside the function (Just before gulp.src).
var gulp = require('gulp');
var htmlmin = require('gulp-htmlmin');
var extname = require('gulp-extname');
var assemble = require('assemble');
var middleware = require('./examples/middleware');
var gulpAssemble = require('./');
// arbitrary middleware that runs when files loaded
assemble.onLoad(/index\.hbs/, middleware(assemble));
// render templates in `test/fixtures`
gulp.task('default', function () {
// setup items on the assemble object
assemble.data({site: {title: 'Blog'}});
assemble.data(['test/fixtures/data/*.{json,yml}']);
assemble.layouts(['test/fixtures/layouts/*.hbs']);
assemble.partials(['test/fixtures/includes/*.hbs']);
gulp.src('test/fixtures/pages/*.hbs')
.pipe(gulpAssemble(assemble, { layout: 'default' }))
.pipe(htmlmin({collapseWhitespace: true}))
.pipe(extname())
.pipe(gulp.dest('_gh_pages/'));
});
// ============================================================
// my watch task
// ============================================================
gulp.task('watch', ['default'], function() {
gulp.watch('test/fixtures/**/*.{hbs,yml,json}', ['default']);
});

Prepend custom strings to JS files while concatenating

I am trying to migrate our build process to gulp from existing custom bash build script. We concatenate several unminified opensource JS files like bootstrap, lazyload, ... and our own JS files. We uglify each JS file (removing their licenses as well) in an order, prepend custom license text to some of them as required and concatenate to create the output JS file. The custom license text are currently kept as strings in the bash script.
How to achieve this in gulp without creating intermediate files?
Will it also be possible to selectively avoid uglifying some JS scripts?
Ok, I spent some time learning up gulp and it's plugins and here is a working version. The points here are using the foreach on each JS retrieved from the JSON config file, pushing the streams to an array and finally using merge on the array streams.
Here are the plugins used and the JSON structure defined:
var gulp = require('gulp');
var each = require('foreach');
var debug = require('gulp-debug');
var gulpif = require('gulp-if');
var jshint = require('gulp-jshint');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat-util');
var es = require('event-stream');
var cache = require('gulp-cached');
var remember = require('gulp-remember');
// Structure that holds the various JS files and their handling
var Config = {
js: {
output_dir: 'path/to/output/file/',
output_file: 'outputfile.js',
src: [{
name: 'bootstrap',
src: ['path/to/bootstrap.js'],
run_lint: false,
run_uglify: true,
license: '/* bootstrap license */'
}, {
name: 'lazyload',
src: ['path/to/lazyload.js'],
run_lint: false,
run_uglify: true,
license: '/* lazyload license */'
}, {
name: 'inhouse-js',
src: ['path/to/inhouse/ih-1.js', 'path/to/inhouse/ot/*.js'],
run_lint: true,
run_uglify: true,
license: ''
}]
}
}
The build task, with caching as we will be using it in development also:
gulp.task('build', ['build:js']);
gulp.task('build:js', function() {
var streams = [];
each(Config.js.src, function(val, key, array) {
var stream = gulp.src(val.src)
.pipe(cache('scripts'))
.pipe(gulpif(val.run_lint, jshint('.jshintrc')))
.pipe(gulpif(val.run_lint, jshint.reporter('jshint-stylish')))
.pipe(gulpif(val.run_uglify, uglify({
compress: {
drop_console: true
}
})))
.pipe(concat.header(val.license + '\n'));
streams.push(stream);
});
es.merge.apply(this, streams)
.pipe(remember('scripts')) // add back all files to the stream
.pipe(concat(Config.js.output_file))
.pipe(gulp.dest(Config.js.output_dir));
});
If you would like to debug, a good option will be to insert debug plugin like this example around the 'gulp-remember' plugin call above:
.pipe(debug({title: 'before remember:'}))
.pipe(remember('scripts')) // add back all files to the stream
.pipe(debug({title: 'after remember:'}))
And here's the watch task:
gulp.task('watch', function() {
var watch_list = [];
each(Config.js.src, function(val, key, array) {
watch_list.push.apply(watch_list, val.src);
});
// Watch .js files
var watcher = gulp.watch(watch_list, ['build']);
watcher.on('change', function(event) {
console.log('File '+ event.path +' was '+ event.type +', running tasks..');
if (event.type === 'deleted') { // if a file is deleted, forget it
delete cache.caches['scripts'][event.path];
remember.forget('scripts', event.path);
}
})
});
You can use lazypipe() to reuse parts of the build:js task with normal build.

Using Jekyll with Gulp and Livereload

This question has hinted me on how to run Jekyll with Gulp.
It works fine except I’m unable to trigger livereload (but it runs without errors).
My knowledge of Node is limited, so I’m probably missing something...
var gulp = require('gulp');
var refresh = require('gulp-livereload');
var lr = require('tiny-lr');
var server = lr();
gulp.task('jw', function(){
var spawn = require('child_process').spawn,
j = spawn('jekyll', ['-w', 'build']);
j.stdout.on('data', function (data) {
console.log('stdout: ' + data); // works fine
refresh(server); // doesn’t trigger
});
});
gulp-livereload requires files piped into it via gulp.src() or other vinyl input sources. In this case, I recommend adding gulp-watch to watch for the files that Jekyll writes, and reload based on that.
It would look something like this:
var gulp = require('gulp');
var refresh = require('gulp-livereload');
var watch = require('gulp-watch');
var lr = require('tiny-lr');
var server = lr();
gulp.task('jw', function(){
var spawn = require('child_process').spawn,
j = spawn('jekyll', ['-w', 'build']);
j.stdout.on('data', function (data) {
console.log('stdout: ' + data); // works fine
});
watch({glob: '/glob/path/to/jekyll/output'}, function(files) {
// update files in batch mode
return files.pipe(refresh(server));
});
});
As long as Jekyll only rewrites changed files, this will work perfectly. However, if it overwrites everything, then livereload will do little more than refresh the browser on every change.
You can trigger livereload at the end of the build, making it reload the page so you won't have multiple refresh :