inserting text in a gulp stream - javascript

I would like to hard-code a variable into a GULP task (for development purposes and not production), I need something like this:
gulp.task('buildJS', function() {
gulp.insert('var DEV = true;') // inserting the text somehow
.src([
'./js/a.js',
'./js/b.js',
'./js/c.js'
])
.pipe(concat('main.min.js'))
.pipe(gulp.dest('./js/'));
});
I tried to google it, but I get a bunch of bad results, also not sure what exactly to look for here, but can only describe here.
As you can see in the first line, I would like to insert some variable that comes before all other things (in this specific case, and then the rest of the files should be included, and it all gets concatenated into one file at the end, but I am not sure how to do that... Thanks for any help with this!

You can use the gulp-header plugin that allow to append text at the beginning of your files and which support templating.
You can do something like :
var header = require('gulp-header');
gulp.task('buildJS', function() {
gulp.src([
'./js/a.js',
'./js/b.js',
'./js/c.js'
])
.pipe(header('var DEV = true;'))
.pipe(concat('main.min.js'))
.pipe(gulp.dest('./js/'));
});
Or if you only want to append it on the concatened file
gulp.task('buildJS', function() {
gulp.src([
'./js/a.js',
'./js/b.js',
'./js/c.js'
])
.pipe(concat('main.min.js'))
.pipe(header('var DEV = true;'))
.pipe(gulp.dest('./js/'));
});

You may want to use gulp-header : https://www.npmjs.org/package/gulp-header
In your case, put it after the concat operation in the pipeline.

Related

how to run code when rollup watcher fires

Anyone know how to run code whenever the rollup watcher fires? I saw some references to trapping watcher events, like 'start', but I'm using a rollup.config.js file and I have no idea where and how I'd check for such events. FYI, I'm learning service workers and I want to modify the service worker file (appending a '\n' would be sufficient) whenever any of my source code changes.
On a separate forum, I received the following answer. It sounds correct to me, but I haven't implemented it yet so take it for what it's worth:
if you have your npm run dev command run node some-script.js and have some-script.js do something similar to https://rollupjs.org/guide/en/#rollupwatch then you can do a watcher.on('event' call and re-run w/e it is you want to run.
you can use your existing config, and import it into some-script.js to pass as options to rollup.watch, with the addition of any watch specific options you'd like to add.
In many cases, the best way to do this is by writing a rollup plugin. Plugins have a watchChange callback that you can use to something when changes are detected. If you only want to do it when certain files change, you could use the minimatch library to check if the changed file matches a glob you pass in or configure somewhere.
This is a sketch of the solution I came up with:
function demoWatcherPlugin(globs) {
let doTheAction = false
return {
watchChange(id) {
// Does the file that just changed match one of the globs passed into
// this plugin?
const relPath = path.relative(__dirname, id)
if (
globs.some(
(item) => minimatch.match([relPath], item).length > 0
)
) {
doTheAction = true
}
},
async buildEnd() {
if (doTheAction) {
// Do the action you want to perform when certain files change
}
},
}
}
Usage (in rollup.config.js):
plugins: [
demoWatcherPlugin(['src/foo/**/*.js']),

Gulp combine two gzip files

I want to combine two gzipped files: dist/public/scripts/vendors.js.gz and dist/public/scripts/scripts.js.gz. I am currently trying to do it like this:
gulp.task('scriptCombination', ['compressScripts'], () => {
var jsDest = 'dist/public/scripts';
gulp.src(['dist/public/scripts/vendors.js.gz', 'dist/public/scripts/scripts.js.gz'], { base: '.' })
.pipe(concat('new-file.js.gz'))
.pipe(gulp.dest(jsDest));
});
Right now it seems like the first file is zipping correctly, but the second file always seems to get messed up. Upon return and unzip, the files will look good at first, but scrolling down it seems like things get really messy. new-file.js.gz ends up looking something like this when it is unzipped in the browser:
oadprogress","reset","queuecomplete"];e.forEach(p,function(o){var n=t.callbacks[o]||e.noop;s.on(o,function(){n.apply(null,arguments),t.$$phase||t.$root.$$phase||t.$apply()})})}}}}])}"object"==typeof module&&module.exports?module.exports=o(require("angular"),require("dropzone")):"function"==typeof define&&define.amd?define(["angular","dropzone"],o):o(e.angular,e.Dropzone)}(this);
‹�����í=ksÛ¶–ß÷W0œ\/¹Ah;¶¡ÂzœWë½Mš‰tîf²Z„-Æ©’”EÖ߃'¤(ÇN;s7Ó©…×p^À9�Oçù¸N‹ÜyìÃü¦xž¥ãsÏ_žŠ¢,ÍϽj\Ì0žâ¼Fq]—éɼÆ×eæ//âÒIó‰H:8ÃõQ|ò’Õ> ùoê(¤àîe\'^(˜ŠŒ‘èÚ‹iŽ¿d·¶<
ý´Ï«ƒ¦·
(good and minified for the first file, bad for the second)
How can I combine these two files in gulp?

Pass parameter to Gulp task in gulpfile.js (not command-line)

EDIT: As I wrote IN THE TITLE AND FROM THE BEGINNING, this is not about command-line parameters and is thus NOT A DUPLICATE. //EDIT
I have a Sass setup with an indefinite number of uniquely-designed pages (page_1, page_2, etc), each having their own sass/pages/page_1/page_1.scss file.
The pages all belong to the same website, and each page's sass file #imports the same set of files from a sass/includes folder.
With a basic gulp task watching sass/**/*, every page's styles get compiled anytime I make a change to any page's styles. Obviously this doesn't scale well.
I tried using gulp-watch, but it doesn't catch if changes are made to one of the included .scss files. It only catches changes made to the files that actually get compiled into an equivalent .css.
For the purposes of having my gulpfile be as DRY as possible, the best solution I could come up with was to maintain a basic array of folder names in gulpfile.js, and to loop through and watch each of them separately, using the same sass-compiling task for each folder.
var pageFolderNames = [
'page_1',
'page_2'
// etc
];
Then for the gulp task, I have:
gulp.task('watch_pages', function()
{
// Get array length
var numPages = pageFolderNames.length;
// Add a new watch task for each individual page
for (var i = 0; i < numPages; i++)
{
gulp.watch('sass/pages/' + pageFolderNames[i] + '/**/*.scss', ['sass_page']);
}
});
The (simplified) task that compiles sass:
// Task: Compile page-specific Sass
gulp.task('sass_page', function()
{
return gulp.src('sass/pages/' + pageFolderNames[i] +'/**/*.scss')
.pipe(plumber(plumberErrorHandler))
.pipe(sass(...))
.pipe(gulp.dest('css/pages/' + pageFolderNames[i]));
});
This approach (I know my JS-fu is weaksauce) results in an error:
'sass_page' errored after 71 μs
ReferenceError: i is not defined
Is there any way to pass parameters, such as i, to gulp tasks to get this working? Alternately, is there a better way to accomplish what I'm trying to do? I have a sneaking suspicion there is. :-/
I found out there is an on change event for gulp watch. So this might be what you're looking for:
var pagesDir = 'sass/pages/';
gulp.task('watch_pages', function() {
gulp.watch(pagesDir + '**/*')
.on("change", function(file) {
// absolute path to folder that needs watching
var changedDest = path.join(__dirname, pagesDir);
// relative path to changed file
var changedFile = path.relative(changedDest, file.path);
// split the relative path, get the specific folder with changes
var pageFolder = changedFile.split('\\')[0];
gulp.src(path.join(pagesDir, pageFolder) +'/**/*.scss')
.pipe(plumber(plumberErrorHandler))
.pipe(sass(...))
.pipe(gulp.dest('css/pages/' + pageFolder));
console.log(changedDest);
console.log(changedFile);
console.log(pageFolder);
});
});
Also, this way you don't need to declare the folder variables. If you add directories within the path being watched, it should pick it up and name the destination folder accordingly.
Theoretically the gulp task to compile sass should work within the watch task. I played around with the paths, and it seems to spitting them out. Let me know what happens, I can modify if necessary.
The required packages:
var gulp = require("gulp"),
path = require("path"),
rimraf = require("rimraf");
BTW, since you already have access to the file path, you can perhaps target the specific scss file instead of the whole directory.
As Brian answered, the best approach is to have one watcher. In the same way as the principle of delegation with dom event listeners. it's better, even in our case it can not really matter. We need our thing done. if the consumed resources and performance doesn't bother us. It's ok. But stay as Brian answered. one watcher is the best approach. then you've got to get the file that was changed. and from there you get your page folder. So for that i will not add a thing. Except that you don't necessarily need to use the .on("change". You can directly set the same parameter for your function as this example show:
watch('./app/tempGulp/json/**/*.json', function (evt) {
jsonCommentWatchEvt = evt
gulp.start('jsonComment')
})
evt here is what Brian set as file.
What i want to add, is about how to pass a parameter from your watcher to your task. For example about the i in your initial work. A way of doing that, that i see and use, is to set a global variable that hold the data wanted to be passed. So it's accessible in both blocks. You set the value in watcher just before starting the task. And then you use it in the task. A good practice, is to save it in a task local variable just at start. That way you avoid the problem that it can change by another watch handling triggering.
For a lively example. check my answer out here : https://stackoverflow.com/a/49733123/7668448

Change some html code into antoher with GULP

Thank you for checking my question. This may sound trivial but I need help here.
I want to learn how to change HTML code with GULP. Or just change some strings with GULP. For example today I need to change this:
<img class="social" src="../symbols/facebook.svg">
to this:
<svg class="social">
<use xlink:href="../symbols/sprite.svg?v201608061556#facebook"></use>
</svg>
As you can see I am building icon system via symbols and I want to keep my original HTML clean as it can be. So I can work without any watchers and such. Later I just run GULP once and it does the job: create sprite and change HTML to use this sprite.
I tried gulp-replace and it can change one string to another with regex, but it looks too complicated for me with regex. I am not even sure that it is possible to do with regex. And I also want to add timestamp as ?v201608061556. So I want to run some JavaScript that I can write in gulp file.
Next one I tried is gulp-dom and it looks like the thing I need. But I can't make it work due to some errors:
if (node.nodeType === NODE_TYPE.DOCUMENT_NODE) {
^
TypeError: Cannot read property 'nodeType' of undefined
Error log in terminal:
So the questions is:
Is it possible to make with regex and gulp-replace package?
Does anyone know gulp-dom
package. Can I make it work somehow? Is it possible to complete my
task with it?
Is there another way to write JavaScript in Gulp task
so I can take a string, process it according to my needs with all JavaScript functionality and save?
Can I work with HTML from Gulp the same way
I work when I code websites? Work with DOM, use
querySelector and classList for example? Maybe jQuery?
Thanks.
Ok, I found a gulp-change. It gives you file content as a string. You can do everything you want with that string with javascript and then return it back to pipe.
It would be easier to diagnose the issue if you had posted your gulp tasks stream. With the information you provided I believe you are getting this error because (if you are following the example on the plugin page) you are probably returning the element you modified, not the complete Document representation. Below follows the example from the gulp plugin page:
gulp.task('html', function() {
return gulp.src('./src/index.html')
.pipe(dom(function(){
return this.querySelectorAll('body')[0].setAttribute('data-version', '1.0');
}))
.pipe(gulp.dest('./public/'));
});
There are two crucial steps you should take to manipulate the DOM with gulp-dom:
first make the changes on the element(s) you want using simple js DOM manipulation methods such as getElmentById, setAttribute, appendChild, etc.
once that is done, your gulp stream should return this (the whole Document), not the element(s) you are targeting for modification.
In your case you could do something like this (If you find this too verbose you may try to use a different plugin/approach altogether):
var gulp = require('gulp');
var dom = require('gulp-dom);
gulp.task('domManipulation', function() {
return gulp.src('app/index.html')
.pipe(dom(function(){
// cache/create all elements you will work with --'this' is your Document
var parentDiv = this.querySelector('div.imgParent');
var img = this.querySelector('img.social');
var svg = this.createElement('svg');
var use = this.createElement('use');
// DOM manipulation
svg.classList.add('social');
use.setAttribute('xlink:href', "../symbols/sprite.svg?v201608061556#facebook");
svg.appendChild(use);
parentDiv.replaceChild(svg, img);
return this; // return the whole Document
}))
.pipe(gulp.dest('dist'));
});
I tested the code above and it works just fine. Hope this helps.

Grunt task grunt.option set by previous task returns undefined

I'm running a number of grunt tasks on a project. One of which sets a number of grunt.options grunt.option(key, value) which I need to access in a subsequent task var option = grunt.option(key). These options are returning undefined when I try to access them in the latter task.
If I log the variable at the head of the latter task, it is shown before that task is run and I am unable to access the previously set value in the tasks config.
Is there something I need to do between setting the grunt.option and using it in another task to notify grunt of the change? Am I doing something inherently wrong here? Or is there a better way to do this with a global variable of sorts (my research pointed me to using grunt.option)
My Gruntfile.js
grunt.log.writeln('loading tasks');
grunt.loadTasks('grunttasks');
grunt.log.writeln('tasks loaded');
grunt.registerTask(
'jenkins',[
'clean', //clears out any existing build folders
'curl', //gets build config file from remote server
'set-env', //sets the grunt.options based on the build config file
'string-replace:config', //attempts to access the new grunt.options
....
....
....
....
]
);
In my set-env task, I set some environment variables based on the contents of a text file returned in the curl task. This works fine and I can log all the grunt.options immediately after setting them so I know they are being set correctly.
set-env-task
module.exports = function(grunt) {
grunt.registerTask('set-env', 'set-env', function() {
......
......
for (var i = 0; i < propFile.length; i++) {
if (propFile[i] !== '') {
......
......
keyValues[propName] = propValue;
grunt.option(propName, propValue);
console.log("FROM GRUNT.OPTION " + grunt.option(propName));
......
......
}
}
......
......
});
};
When I try and access the grunt.options set in the above task from my string-replace (or any other subsequent) task undefined is returned. If I set test values to these grunt.options at the start of my Gruntfile.js I can access them with no issue:
module.exports = function(grunt) {
grunt.config('string-replace', {
..........
..........
config:{
files: configFiles,
options: {
replacements: [
..........
..........
{
pattern: /var _OPTION_KEY = \"(.*?)\"\;/ig,
replacement: 'var _OPTION_KEY = "'+grunt.option('_OPTION_KEY')+'";' //grunt.option('_OPTION_KEY') here is undefined
}
..........
..........
]
}
}
..........
..........
});
grunt.loadNpmTasks('grunt-string-replace');
}
(I have double, triple and quadruple checked that I'm using the correct option keys)
The problem is that you're accessing the variables from the grunt option set during the "config stage" of the task, which runs one time, before you set the options in your set-env task. Evaluating the custom option key at that point in the code indeed should yield undefined. (Note that this is practically the equivalent of using the initConfig block)
What you an do instead is instead of reading the option values from the options object, modify the config object of the task directly, using grunt.config.set, which would enable you to do what you've been trying.
So basically, instead of
grunt.option(propName, propValue);
use something like
grunt.config.set('mytask.replacements', options.replacements);
(Of course, this will require a sizable reworking of your code, I don't get into that.)
edit: probably there's an even cleaner solution using the templating functionality of grunt, see this stackoverflow answer, and the grunt api docs on templating:
Template strings can be processed manually using the provided template functions. In addition, the config.get method (used by many tasks) automatically expands <% %> style template strings specified as config data inside the Gruntfile.
The point being that these are evaluated not when the config block is parsed, but only when the task reads the values using config.get.
Your pattern of using the options object to share values between tasks works better if it's between two custom tasks of yours - you can set it in one task, read it in the other, not in the configuration, but as an actual step of running the tasks.
In general, although it seems doable, I'd say this is not the workflow grunt has in mind - if you know which environment you're running grunt in, it's easier to pass in the environment parameters through the options command-line flag directly when you run a grunt task, which would already take effect in any task configuration you're doing.

Categories