Dom_munger issue with Node 7.7.3 - Path must be a string - node.js

I'm trying to update an application to support Node -v 7.7.3. But when I am running the grunt task dom_munger as per below:
dom_munger:{
read: {
options: {
read:[
{selector:'script[data-concat!="false"]',attribute:'src',writeto:'appjs', isPath: true},
{selector:'link[rel="stylesheet"][data-concat!="false"]',attribute:'href',writeto:'appcss'}
]
},
src: 'app/index.html'
}
}
I receive error:
Warning: Path must be a string. Received [ 'app/index.html' ] Use --force to continue.
I wonder if there is a way to rewrite above grunt task or if there might be a good alternative to dom_munger. Any help would be appreciated.

Per the grunt-dom-munger Github:
When isPath is true, the extracted values are assumed to be file
references and their path is made relative to the Gruntfile.js rather
than the file they're read from.
Try removing the isPath property, or altering it to match the path from your Gruntfile to the index.html file.

Remove isPath: true, and make sure that path in src attribute relative to the Gruntfile.js rather than the file they're read from.
If needs make a replace in path:
dom_munger: {
replacePath: {
options: {
callback: function($, file){
var scripts = $('script[data-concat!="false"]');
// NOTE: path is made relative to the Gruntfile.js rather than the file they're read from
for(var i=0, s, il=scripts.length; i<il; i++){
s = scripts[i];
if(s.attribs.src){
s.attribs.src = s.attribs.src.replace('../', '');
}
}
}
},
src: 'temp/index.html'
},
read: {
options: {
read: [
{selector:'script[data-concat!="false"]',attribute:'src',writeto:'appjs'},
{selector:'link[rel="stylesheet"][data-concat!="false"]',attribute:'href',writeto:'appcss'}
]
},
src: 'temp/index.html'
}
}

Thanks you! But this only seems to work if the Grunt and Index are in the same folder structure. My structure looks like this:
- /app
-index.html
- gruntfile.js
And without the attribute 'isPath' the dom_munger will look for js files in the same directory as where the Gruntfile is places.

Related

Rollup bundle using exports instead of module.exports

I have a library I am bundling using rollup and this is a section from the rollup.config.js file:
export default {
input: `src/${libraryName}.ts`,
output: [
{ file: pkg.main, name: camelCase(libraryName), format: 'cjs', sourcemap: true },
{ file: pkg.module, format: 'es', sourcemap: true },
],
....
}
It generates two files dist/libname.umd.js and dist/libname.es5.js. I have confirmed from putting a console.log statement in both the files that using require('libname') loads the dist/libname.umd.js. However, the following line:
var x = require('libname').X
console.log(x) // This is undefined
prints undefined. So, I tried to edit the dist/libname.umd.js file manually and at the bottom of the file I saw:
exports.X = X;
with the overall variable X being bundled somewhere above in the file. I modified this to:
module.exports.X = X;
and then it seems to work. I am a bit new to node/js so I wasn't sure if it this is the way to be exporting modules, but on reading a blog post (http://www.hacksparrow.com/node-js-exports-vs-module-exports.html) it turns out both of them should be fine? I am still a bit unclear on this one though.
Also, when I simply did this:
console.log(require('libname')
it prints [Function: uniqSetWithForEach] and console.log(require('libname')()) prints [].
EDIT So for the time being, just so that I can continue my work I have modified rollup.config.ts to add an outro:
export default {
...
output: [
{ file: pkg.main, name: camelCase(libraryName), format: 'cjs',
sourcemap: true,
outro: 'module.exports = Object.assign({}, module.exports, exports)'
}
]
...
}
and this seems to do it for now, but I'm pretty sure it's not a clean solution.

Grunt variable as filename and file path

I'm trying to use Grunt option to define a file path and file name. This used to work but now I'm getting an unexpected token error.
var myTarget = grunt.option('target');
'build/assets/css/' + myTarget + '.css': 'source/scss/' + myTarget + '/styles.scss'
You should use the special placeholders for variables in file names and strings. First, you should load the option (using grunt.option()) or configuration (using grunt.congif()), as an option for the Grunt initConfig method. Then you should use the special placeholders <%= varname %> to use the loaded options or configurations.
grunt.initConfig({
target : grunt.option('target'),
...
files : {
'build/assets/css/<%= target %>.css' : 'source/scss/<%= target %>/styles.scss'
}
...
});
Configuration can also load an object, so the special placeholder can match object properties too:
grunt.config('definitions', (function() {
return {
target : 'my-target'
};
})());
Later on your config:
grunt.initConfig({
config : grunt.config('definitions'),
...
files : {
'build/assets/css/<%= config.target %>.css' : 'source/scss/<%= config.target %>/styles.scss'
}
...
});
Read more about Grunt option, config and templates in the Grunt official website.
Hope it helps.

grunt-open for two different files

grunt-open for two different files
I use the grunt-open plugin which works OK.
Now I need to open an additional file with a different task.
How can I do that?
I have tried:
open: {
file: {
path: appPath + '/coverage/lcov/index.html',
path2: appPath + '/coverage/lcov-report/index2.html'
}
}
//Here I want to open first line
grunt.registerTask('openCoverage', ['exec', 'copy', 'mocha_istanbul', 'open:path']);
//Here I want to map second line
grunt.registerTask('MochaWeb', ['exec', 'copy', 'mochaTest', 'open:path2']);
From the documentation it is clear that the path parameter holds the filepath of the file you want to open. You won't be able to add suffixed versions of "path", like path2. Instead, you will need to use separate targets for each file you wish to open. Your config would then look like the following:
open: {
openCoverage: {
path: appPath + '/coverage/lcov/index.html'
},
MochaWeb: {
path: appPath + '/coverage/lcov-report/index2.html'
}
}
Next, you will add these targets to your task definitions:
grunt.registerTask('openCoverage', ['exec', 'copy', 'mocha_istanbul', 'open:openCoverage']);
grunt.registerTask('MochaWeb', ['exec', 'copy', 'mochaTest', 'open:MochaWeb']);

Folder copy including files in gulp

I'm trying to copy 2 folders onto a single build folder and for the second path I want to copy whole libs folder including libs folder itself to destination.
var paths = {
'standalone' : '../app-ui/assets/js',
'standalone_libs' : '../app-ui/libs',
'destination' : '../SomeFolder'
}
gulp.task('folder-copy', function() {
return gulp.src([paths.standalone_js + '/*', paths.standalone_libs + '/*']).pipe(gulp.dest(paths.destination));
});
Structure according to code
->SomeFolder
->app.js [ file from ../app-ui/assets/js ]
-> angular/angular.js [ file from ../app-ui/libs ]
-> lodash/lodash.js [ file from ../app-ui/libs ]
Actual Structure wanted
->SomeFolder
->app.js [ file from ../app-ui/assets/js ]
-> libs
-> angular/angular.js [ file from ../app-ui/libs ]
-> lodash/lodash.js [ file from ../app-ui/libs ]
You could specify the base in gulp.src :
return gulp.src(['some/path/app/*', 'libs/**/*'], {base: '.'})
.pipe(gulp.dest('build'));
This will copy all your files in libs, with the directory structure intact. But the directory structure will be preserved for app.js also...
I would just do two separate copy.
You can use merge-stream. There's a recipe in gulp repository. It would boil down to something like this :
var merge = require('merge-stream')
var libs= gulp.src('libs/**/*', {base: '.'})
.pipe(gulp.dest('build'));
var app = gulp.src('app.js')
.pipe(gulp.dest('build'));
return merge(libs, app);
Try removing the /* because this means the whole content inside the folder is what you want.
So for the libs, I would not add the /* like follows
return gulp.src([paths.standalone_js + '/*', paths.standalone_libs ]).pipe(gulp.dest(paths.destination));
What about changing this:
var paths = {
'standalone' : '../app-ui/assets/js',
'standalone_libs' : '../app-ui/libs',
'destination' : '../SomeFolder'
}
to this:
var paths = {
'standalone' : '../app-ui/assets/js',
'standalone_libs' : '../app-ui/(libs)',
'destination' : '../SomeFolder'
}

How to scan an entire directory tree with node.js?

Often I would want to scan an entire directory tree (a directory, and everything inside it, including files, subdirs, and those subdir contents too, and their subdir contents too, etc etc).
How would one accomplish this with node? Requirements, is that it should be asynchronous to take advantage of super fast non-blocking IO - and not crash when processing too many files at once.
-- I've updated this answer in 2017 for the progress since 2012 --
Ended up creating these to accomplish it:
https://github.com/bevry/safefs - which now uses https://npmjs.org/package/graceful-fs (which didn't exist before)
https://github.com/bevry/scandirectory - there is also now a vast array of like projects like this
I also created this which is lightweight and super fast:
https://github.com/bevry/readdir-cluster
You can use the module npm dree if you want to achive that. It returns a json that describes the directory tree and it allows you to specify also a fileCallback and a dirCallback, so you can do this:
Here is the code:
const dree = require('dree');
const fileCb = function(file) {
// do what you want
}
const dirCb = function(directory) {
// do what you want
}
dree.scan('path-to-directory', { extensions: [ 'html', 'js' ] }, fileCb, dirCb);
If you want to stick with the 'fs' module, you can do some recursive functions to get them.
Heres a function I made recently to get the tree of a directory.
const fs = require("fs");
// dir is file, depth is how far into a directory it will read.
function treeFiles(dir, depth = 1000) {
if (depth < 1) return;
var sitesList = {};
fs.readdirSync(dir).forEach((file) => {
let base = dir + '/' + file;
// Add file to siteslist object.
sitesList[file] = {"stats": fs.statSync(base), "dir": false};
// Recursive to get directory and tree of files
if (fs.statSync(base).isDirectory()) {
sitesList[file]["dir"] = true;
sitesList[file]["ls"] = treeFiles(base, depth - 1);
}
});
return sitesList;
}
So if I have a file structure which looks like
nodejs_app >
- app.js
- config.js
- images >
- - logo.png
Then the final output of my function reading the nodejs_app directory will look like
{
"app.js": {"stats": {}, "dir": false},
"config.js": {"stats": {}, "dir": false},
"images": {"stats": {}, "dir": true, "ls": {
"logo.png": {"stats": {}, "dir": false}
}
}
Then just call the function with directory and depth into the directory if you want.
let dir = require("path").join(__dirname, "nodejs_app");
let tree = treeFiles(dir);
console.log(tree);
Of course change paths and names to fit your code. I included the depth as to reduce time it takes for it to finish reading a directory.

Resources