Best ways to merge folders using nodejs, grunt or gulp - node.js

I have two folders and I just want to merge them (overwriting BaseFolder files with ExtendedFolder ones when present)
Example:
BaseFolder
---main.js
---test.js
ExtendedFolder
---main.js
Result expected:
ResultFolder
---main.js (from ExtendedFolder)
---test.js (from BaseFolder)
I similar question has been asked but without a satisfying answer: Grunt. Programmatically merge corresponding files in parallel folders with concat

EDIT: I just realized my previous answer wouldn't work. I am posting new code.
If you just have two specified folders and want to merge their content, it would be pretty straightforward with gulp (this assumes that the folder names are known before and don't change):
var gulp = require('gulp');
gulp.task('moveBase',function(){
return gulp.src('BaseFolder/*')
.pipe(gulp.dest('ResultFolder/'));
});
gulp.task('moveExtended',['moveBase'],function(){
return gulp.src('ExtendedFolder/*')
.pipe(gulp.dest('ResultFolder/'));
});
gulp.task('mergeFolders',['moveBase','moveExtended']);
The files in BaseFolder having the same names as files in ExtendedFolder get overwritten.
The key here is the order of copying. First, copy the folder whose files should be overwritten in case of a conflict. You can split the copying into two tasks and take advantage of the dependency system - task moveExtended depends on moveBase which ensures that it will be copied later.

I was able to do exactly what I wanted using https://www.npmjs.org/package/event-stream
var gulp = require('gulp')
, es = require('event-stream');
gulp.task('web_dev', function () {
es.merge(gulp.src('./BaseFolder/**/*')
, gulp.src('./ExtendedFolder/**/*'))
.pipe(gulp.dest('out'));
});

Related

Node : What is the right way to delete all the files from a directory?

So I was trying to delete all my files inside a folder using node.
I came across 2 methods .
Method 1
Delete the folder using rmkdir. But if I plan on adding the images on the same folder then I use mkdir and creates the same folder again and appends the files to it.
Example: I have an Add Files and Delete ALL button. When I click deleteAll , the folder gets deleted. And when I click add then the folder gets created and the file gets added to that folder
Method 2
Using readdir , I loop through the files and stores in an array and then delete only the files instead of the folder.
Which is the best way to do it ? If its not among these then please advice me a better solution.
The rm function of ShellJS will do the trick. It works as a one-liner, and it works cross-platform, and is well tested and documented. It even supports recursive deletes.
Basically, something such as:
const { rm } = require('shelljs');
rm('-rf', '/tmp/*');
(Sample code taken from ShellJS' documentation.)

How to copy files as templates, injecting values to them, to a different folder?

I used this library, mem-fs-editor (https://github.com/sboudrias/mem-fs-editor), in a Yeoman generator a few weeks ago. It worked nicely, but now I tried to use it again in a different scope and I couldn't do anything. Obs: I used it because this is the library Yeoman provides to handle the file system.
In Yeoman Generators we can copy files from a template folder, passing values to inject in the code, to a different folder. And that's precisely what I need, but I can't use Yeoman this time.
I tried the same code I used in my Yo Generator, but it don't work. So I'm not sure how mem-fs works. No errors are thrown and even the code provided by the author of the project don't work to me.
I tried this (and some other things with copyTpl) with no success
var memFs = require('mem-fs');
var editor = require('mem-fs-editor');
var store = memFs.create();
var fs = editor.create(store);
console.log(fs.write('./somefile.js', 'var a = 1;'));
Anyone knows how it works or what else I can do to make this happen?
mem-fs-editor author here.
mem-fs stands for memory file-system. All the files you creates are stored in memory and won't get written to disk until you call:
editor.commit(callback);
Yeoman does that automatically for you. It is this way with Yeoman to collide every file changes together and then being able to only prompt for file conflicts once (rather than everytime a single file is being written to).

node.js and ncp module - fails to copy single file

I am using Node.js v6.3.1 and ncp v2.0.0
I can only get ncp to copy the contents of a directory, but not a single file within that directory.
Here is the code copying the contents of a directory recursively that works:
var ncp = require("ncp").ncp;
ncp("source/directory/", "destination/directory/", callback);
...and here is the same code but with a file as the source:
var ncp = require("ncp").ncp;
ncp("source/directory/file.txt", "destination/directory/", callback);
From this all I can think is that ncp was specifically designed to copy directories recursively, not single files maybe?
I had thought about using something like fileSystem's read/write stream functions as described here but really for consistency I was hoping to stick with ncp.
Update:
I have found another package called node-fs-extra which does what I want without the need for me to add event handlers to the operations, like I would have to do with the fileSystem read/write solution.
Here is the code that is working:
var fsExtra = require("fs-extra");
fsExtra.copy("source/directory/file.txt", "destination/directory/file.txt", callback);
Obviously this still is inconsistent, but at least is a little less verbose.
Ok I have figured out what I was doing wrong.
I was trying to copy a file into a directory, where as I needed to copy and name the file inside a directory.
So here is my original code that does not work:
var ncp = require("ncp");
ncp("source/directory/file.txt", "destination/directory/", callback);
...and here is the fixed code working, notice the inclusion of a file name in the destination directory:
var ncp = require("ncp");
ncp("source/directory/file.txt", "destination/directory/file.txt", callback);
So it looks like ncp wont just take the file as is, but needs you to specify the file name at the other end to successfully copy. I guess I was assuming that it would just copy the file with the same name into the destination directory.
I have found another package called node-fs-extra which does what I want without the need for me to add event handlers to the operations, like I would have to do with the fileSystem read/write solution.
Here is the code that is working:
var fsExtra = require("fs-extra");
fsExtra.copy("source/directory/file.txt", "destination/directory/file.txt", callback);
Obviously this still is inconsistent, but at least is a little less verbose.

Node js. Writing directory to the archive, without path to this directory

Got some task, it is not hard, but i have some trouble.
Maybe someone already has similar problem.
My task is writing to zip archive some folder, with files and other folders in it with using NodeJS
I try to use AdmZip pakage
folder project structure:
var AdmZip = require('adm-zip');
let Archive = new AdmZip();
Archive.addLocalFolder('Archive/filesFolder', '');
Archive.writeZip('Archive/newArchive.zip);
I must get archive with 'filesFolder', instead i get archive with 'Archive' folder and in it i have 'filesFolder'.
If anybody know, how to record only target folder, and not the sequence of a way folders?
What happens is that you are providing Archive/filesFolder as value to writeZip and that means include in the zip Archive folder and inside that include filesFolder.
For testing purpose change the value of writeZip() to just filesFolder.zip and it should zip content of Archive as filesFolder.zip in current working directory. See below (you can copy/paste the bit of code and run it and it should work).
var zip = new AdmZip();
// I don't know why you provided a second argument to below, I removed it
// There was nothing about it in the documentation.
zip.addLocalFolder('./Archive');
//rename the value of the following to just filesFolder.zip
zip.writeZip('filesFolder.zip');
The above should output the content of Archive to the current working directory as filesFolder.zip
I did mention this in my comment and your commend seem to indicate that you have path issue, so try the above script.

Add a Timestamp to the End of Filenames with Grunt

During my Grunt tasks, add a unique string to the end of my filenames. I have tried grunt-contrib-copy and grunt-filerev. Neither have been able to do what I need them to...
Currently my LESS files are automatically compiled on 'save' in Sublime Text 3 (so this does not yet occur in my grunt tasks). Then, I open my terminal and run 'grunt', which concatenates (combines) my JS files. After this is done, then grunt should rename 'dist/css/main.css' and 'dist/js/main.js' with a "version" at the end of the filename.
I have tried:
grunt-contrib-copy ('clean:expired' deletes the concatenated JS before grunt-contrib-copy' can rename the file)
grunt-filerev ('This only worked on the CSS files for some reason, and it inserted the version number BEFORE the '.css'. Not sure why it didn't work on the JS files.')
Here's my Gruntfile.js
So, to be clear, I am not asking for "code review" I simply need to know how I can incorporate a "rename" process so that when the tasks are complete, I will have 'dist/css/main.css12345 & dist/js/main.js12345' with no 'dist/css/main.css' or 'dist/js/main.js' left in their respective directories.
Thanks in advance for any help!
UPDATE: After experimenting with this, I ended up using grunt-contrib-rename and it works great! I beleieve the same results can be achieved via grunt-contrib-copy, in fact I know it does the same thing. So either will work. As far as support for regex, not sure if both support it, so may be something else worth looking into before choosing one of these plugins :)
Your rename:dist looks like it should do what you want, you just need to move clean:dist to be the first task that runs (so it deletes things from the prior build rather than the current build). The order of tasks is defined by the array on this last line:
grunt.registerTask('default', ['jshint:dev', 'concat:dist', 'less:dist', 'csslint:dist', 'uglify:dist', 'cssmin:dist', 'clean:dist', 'rename:dist']);
That said, I'm not sure why you want this behavior. The more common thing to do is to insert a hash of the file into the filename before the file extension.
The difference between a hash and a timestamp is that the hash value will always be the same so long as the file contents don't change - so if you only change one file, the compiled output for just that file will be different and thus browsers only need to re-downloaded that one file while using cached versions of every other file.
The difference between putting this number before the file extension and after the extension is that a lot of tools (like your IDE) have behavior that changes based on the extension.
For this more standard goal, there are tons of ways to accomplish it but one of the more common is to combine grunt-filerev with grunt-usemin which will create properly named files and also update your HTML file(s) to reference these new file names
I'm not sure to understand completely what end you want, but if you add a var timestamp = new Date().getTime(); at the beginning of your gruntfile and concatenate to your dest param that should do the job.
dest: 'dist/js/main.min.js' + timestamp
Is it what your looking for?

Resources