Using Grunt to Replace Text in a File - node.js

I'm trying to get Grunt to replace a path reference and I'm not sure what I'm doing wrong. This looks like it should work. Essentially, I'm copying a Bootstrap file up a directory and changing the #import paths, so I'm just trying to replace 'bootstrap/' with the new destination path 'MY/NEW/DEST/PATH/bootstrap'. I don't want to use a module for something as straight forward as this, seems needless. Everything works but the replace.
var destFilePath = path.join(basePath, file);
// Does the file already exist?
if (!grunt.file.exists(destFilePath)) {
// Copy Bootstrap source #import file to destination
grunt.file.copy(
// Node API join to keep this cross-platform
path.join(basePath, 'bootstrap/_bootstrap.scss'),
destFilePath
);
// Require node filesystem module, since not a global
var fs = require('fs');
// Replace #import paths to be relative to new destination
fs.readFile(destFilePath, 'utf8', function(err, data) {
// Check for any errs during read
if (err) {
return grunt.log.write(err);
}
var result = data.replace('/bootstrap\//g', 'bootstrap/bootstrap/');
fs.writeFile(destFilePath, result, 'utf8', function(err) {
return grunt.log.write(err);
});
});
}

You wrapped your regex in quotes - don't do that and it should work fine:
var result = data.replace(/bootstrap\//g, 'bootstrap/bootstrap/');

Related

modify nodejs require() to search for .min.js

O/S is ubuntu 16, node version is 4.2.6.
I have source / development code and run / distribution code, the source.js files are minified and mangled to create equivalent source.min.js files, and I would like for node js require to automatically search for .min.js files as well as .js files.
But as I have a lot of files, I would prefer not to have to go through every require in every file and instead modify the built-in require() function.
This is a very simple implementation of a stand alone function, but how can I modify the built-in function to behave the same way ?
function require(file){
try{return require(file)}
catch(e){return require(file+='.min.js')}
}
You can achieve this by modifying prototype function require of Module class and apply it globally
Here is how you can do it :
var pathModule = require('path');
var assert = require('assert').ok;
module.constructor.prototype.require = function (path) {
var self = this;
assert(typeof path === 'string', 'path must be a string');
assert(path, 'missing path');
try {
return self.constructor._load(path, self);
} catch (err) {
// if module not found, we have nothing to do, simply throw it back.
if (err.code === 'MODULE_NOT_FOUND') {
throw err;
}
// resolve the path to get absolute path
path = pathModule.resolve(__dirname, path+".min.js")
// Write to log or whatever
console.log('Error in file: ' + path);
}
}

Creating and naming a new file according to a string - gulp

Total newbie in Gulp, really would like some assistance..
I am trying to name & create a new file using a string that exist in another file. this will give me the name of the white label that was deployed onto the server.
The content of the file that holds the string is (among other things) {"TITLE":"name_env"}
name_env should be the new name of the file with the suffix of .web
meaning that the new file would be like this name_env.web
What I've came up until now was:
gulp.task('label', function () {
var str = require('path/to/file/file.json')
return file('label', str, {src: true})
.pipe(gulp.dest('build/'))
});
Am I on the right track ?
Hopefully I've managed to explain myself..
Here's gulp file which will do your task(assuming there's dist folder already exist!!)
var gulp = require('gulp');
var fs = require('fs');
gulp.task('label', function() {
var buffer = JSON.parse(fs.readFileSync('path/to/file.json', 'utf8'));
return fs.writeFile('dist/' + buffer['TITLE'] + '.web' , buffer, { flag: 'wx' }, function(err) {
if (err) throw err;
console.log("It's saved!");
});
});

Node.js - How to grab the class names from a .scss file

I wanted to ask if anyone knows of a good solution for how to use node.js to look in a .scss file and grab all the classes listed and to then put them in either an object or an array?
The thing with this is that you are going to need the sass folder to be available to you server, this is not a recommended practice since you only publish the css compiled file, there is no need to also publish the dev assets.
However if you do so, you will need to read .scss file using node and from there use a regex to match the .class strings inside the file.
This will make the reading of the file:
var fs = require('fs');
function readSassFile () {
fs.readFile('./public/scss/components/_styles.scss', 'utf8', function (err, data) {
if (err) {
console.log(err);
return;
}
regexArray(data);
});
}
As you can see, at the end if the readFile retrieves the file with success, I'm calling a function regexArray() and sending the data of the file loaded.
In the regexArray function you need to define a regex to evaluate the string of the file loaded.
function regexArray (data) {
var re = /\.\S*/g;
var m;
var classArray = [];
while ((m = re.exec(data)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
classArray.push(m[0]);
}
console.log(classArray);
}
the var re is the regular expression matching any string starting with a . and ending with a non-whitespace character which will match your css class names.
then we evaluate the m variable when is different from null and store the results in the array classArray, then you can log it to see the results.
I made the test with the path that is in the fs.readFile method, you can change it for you own path.

Is there an alternative to require() in Node.JS? A "soft require" which tries to find a file but doesn't error if it isn't there

I'm loading a config.json file using require('./config.json') but I don't want to require a config file if they want to pass command line arguments instead, or just use the defaults. Is there any way to try to load a JSON file this way but not spit out an error if it can't be found?
For general modules, you can check for existence before trying to load. In the following path is whatever path you want to load and process() is a function performing whatever processing you'd like on your module:
var fs = require("fs");
fs.exists(path, function (exists) {
if (exists) {
var foo = require(path);
process(foo);
}
else {
// Whatever needs to be done if it does not exist.
}
});
And remember that path above must be an actual path, and not a module name to be later resolved by Node as a path.
For a JSON file specifically, with path and process having the same meanings as above:
fs.readFile(path, function (err, data) {
if (err) {
// Whatever you must do if the file cannot be read.
return;
}
var parsed = JSON.parse(data);
process(parsed);
});
You can also use try... catch but keep in mind that v8 won't optimize functions that have try... catch in them. With path and process meaning the same as above:
try {
var foo = require(path);
process(foo);
}
catch (e) {
if (e.code !== "MODULE_NOT_FOUND")
throw e; // Other problem, rethrow.
// Do what you need if the module does not exist.
}

Meteor/Node writeFile crashes server

I have the following code:
Meteor.methods({
saveFile: function(blob, name, path, encoding) {
var path = cleanPath(path), fs = __meteor_bootstrap__.require('fs'),
name = cleanName(name || 'file'), encoding = encoding || 'binary',
chroot = Meteor.chroot || 'public';
// Clean up the path. Remove any initial and final '/' -we prefix them-,
// any sort of attempt to go to the parent directory '..' and any empty directories in
// between '/////' - which may happen after removing '..'
path = chroot + (path ? '/' + path + '/' : '/');
// TODO Add file existance checks, etc...
fs.writeFile(path + name, blob, encoding, function(err) {
if (err) {
throw (new Meteor.Error(500, 'Failed to save file.', err));
} else {
console.log('The file ' + name + ' (' + encoding + ') was saved to ' + path);
}
});
function cleanPath(str) {
if (str) {
return str.replace(/\.\./g,'').replace(/\/+/g,'').
replace(/^\/+/,'').replace(/\/+$/,'');
}
}
function cleanName(str) {
return str.replace(/\.\./g,'').replace(/\//g,'');
}
}
});
Which I took from this project
https://gist.github.com/dariocravero/3922137
The code works fine, and it saves the file, however it repeats the call several time and each time it causes meteor to reset using windows version 0.5.4. The F12 console ends up looking like this: . The meteor console loops over the startup code each time the 503 happens and repeats the console logs in the saveFile function.
Furthermore in the target directory the image thumbnail keeps displaying and then display as broken, then a valid thumbnail again, as if the fs is writing it multiple times.
Here is the code that calls the function:
"click .savePhoto":function(e, template){
e.preventDefault();
var MAX_WIDTH = 400;
var MAX_HEIGHT = 300;
var id = e.srcElement.id;
var item = Session.get("employeeItem");
var file = template.find('input[name='+id+']').files[0];
// $(template).append("Loading...");
var dataURL = '/.bgimages/'+file.name;
Meteor.saveFile(file, file.name, "/.bgimages/", function(){
if(id=="goodPhoto"){
EmployeeCollection.update(item._id, { $set: { good_photo: dataURL }});
}else{
EmployeeCollection.update(item._id, { $set: { bad_photo: dataURL }});
}
// Update an image on the page with the data
$(template.find('img.'+id)).delay(1000).attr('src', dataURL);
});
},
What's causing the server to reset?
My guess would be that since Meteor has a built-in "automatic directories scanning in search for file changes", in order to implement auto relaunching of the application to newest code-base, the file you are creating is actually causing the server reset.
Meteor doesn't scan directories beginning with a dot (so called "hidden" directories) such as .git for example, so you could use this behaviour to your advantage by setting the path of your files to a .directory of your own.
You should also consider using writeFileSync insofar as Meteor methods are intended to run synchronously (inside node fibers) contrary to the usual node way of asynchronous calls, in this code it's no big deal but for example you couldn't use any Meteor mechanics inside the writeFile callback.
asynchronousCall(function(error,result){
if(error){
// handle error
}
else{
// do something with result
Collection.update(id,result);// error ! Meteor code must run inside fiber
}
});
var result=synchronousCall();
Collection.update(id,result);// good to go !
Of course there is a way to turn any asynchronous call inside a synchronous one using fibers/future, but that's beyond the point of this question : I recommend reading this EventedMind episode on node future to understand this specific area.

Resources