Node module to execute tasks grunt : "Gruntfile.js" not find - javascript

I'm currently trying to develop a module that will allow node to run Grunt tasks from the command line. This Node module is installed globally :
C:\Users\pcharpin\AppData\Roaming\npm\node_modules\task-app
The goal is that the use of "Grunt" commands is transparent to the user. To better explain my approach, a simple example of the use of my node module:
C:\Users\pcharpin\Desktop\demo-app> task-app copy
In this example, my module will copy a source directory to a destination directory.
Unfortunately, when I run the task Grunt, my node module indicates to me that there is no file "Gruntfile.js" within the directory "demo-app". However, this file should be found by my Node module within its own directory.
My tree Node module:
Task app
node_modules
grunt
src
task-app.js
Gruntfile.js
package.json
README.md
...
My task-app.js file, here's the code:
#!/Usr/bin/env node
var grunt = require('grunt');
var args = process.argv.splice(2)
checkArguments(args);
checkArguments function(args) {
[...]
runCopy();
}
runCopy = function() {
var spawn = require('child_process') spawn.
var exec = spawn('cmd', ['/ c', 'grunt copy']);
exec.stdout.on("data", function (data) {
console.log('' + data);
});
exec.stderr.on('data', function (data) {
console.log('' + data);
});
}
Then in my "Gruntfile.js" file, I have the code to perform the copy of the source to the destination directory:
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
copy {
srcWeb {
files: [{
cwd: '<%= pkg.srcWeb%>', //root to copy
src: '**/*', // copy all files and subfolders
dest: '<%= pkg.name%>/www/', // destination folder
expand: true // When required using cwd
}]
}
}
});
I don't understand why the Node module is not found in the "Gruntfile.js" file.
Is it required to have a file "Gruntfile.js" in this project directory? Is there another solution?
I would like to know too, is it possible that the file "Gruntfile.js" can read the file "package.json" in the project directory? This is to allow the user to configure this file to change the source path for example.
EDIT :
After some researches, I'm getting closer to the solution to my problem. To change the execution of "Gruntfile.js" which is the current directory by default, we can use --gruntfile option in command line.
As indicated in the source code grunt (grunt/lib/grunt/tasks.js) :
//Get any local Gruntfile or tasks that might exist. Use --gruntfile override
//if specified, otherwise search the current directory or any parent.
How can I specify the path of "Gruntfile.js" (found in my node module installed globally) for any Windows user ?
Here's an example :
C:\Users\username\projects\demo-app> task-app copy
In my source code, I execute the grunt task like this with --gruntfile option :
runCopy = function() {
var spawn = require('child_process').spawn;
var pathGruntfile = 'C:\Users\username\AppData\Roaming\npm\node_module\task-app';
var exec = spawn('cmd', ['/ c', 'grunt --gruntfile' + pathGruntfile + ' Gruntfile.js']);
exec.stdout.on("data", function (data) {
console.log('' + data);
});
exec.stderr.on('data', function (data) {
console.log('' + data);
});
}
EDIT 2 :
Pending a response, I found a temporary solution to get the "Gruntfiles.js" inside my Node module. But the disadvantage is to install all Node modules dependancies and my Node Module locally in the current directory.
var pathDirCurrent = process.cwd();
var pathGruntfile = pathDirCurrent.concat('\\node_modules\\task-app\\Gruntfile.js');
var spawn = require('child_process').spawn;
var exec = spawn('cmd', ['/c', 'grunt --gruntfile ' + pathGruntfile + ' create']);
exec.stdout.on("data", function(data) {
console.log('' + data);
});

Where are you running grunt from?
Your projects structure and grunt file looks OK. Maybe try and include a base task:
grunt.registerTask('default', ['copy']);

Finally, I understand the logic of using Grunt tasks. When you have a web project application which need to use tasks grunt, it must have the Gruntfile.js in current directory.
However, like as I said from my "edit 2", we can specified the Gruntfile.js with ---gruntfile option. So, it's not a disadvantage cause Grunt tool works with the Gruntfile.js in current directory where there is your web project application.
For each task grunt, I use the --gruntfile option to specify the path of Gruntfile.js as my example from "edit 2".

Related

Error when trying to use cd in a child process in node.js. Resource could not be found

Okay, so when I run the following spawnBot() function in an Electron window, cd throws an error saying that the requested resource could not be found. The following code is part of a file located at /toggle-gui/scripts.js, the electron window page is located at /toggle-gui/pages/index.html and I want to cd into /toggle-gui/imported_bots/toggle-base.
const { spawn } = require('child_process');
const { ipcRenderer } = require('electron');
var selectedBotDir = "./imported_bots/toggle-base";
var bot;
function spawnBot(){
console.log("Attempting to start Toggle...")
console.log("Currently selected bot directory: " + selectedBotDir)
try{
bot = spawn(`cd ${selectedBotDir}; npm install; npm start`, {shell: true, detached: true});
console.log("Process ID: " + bot.pid);
bot.stdout.on('data', data => {
console.log(data);
});
bot.stderr.on('data', data => {
console.log("ERROR: " + data);
});
return bot;
}
catch(error){
console.log(error);
console.log("Toggle failed to start. There should be extra logging output above.")
}
}
Some help here would be greatly appreciated.
The use of ./ in paths makes them relative, which means "treat this path as a subdirectory of the directory you're currently in." However, this "directory you're currently in" does not have to be the directory your Node.js code is located in but rather the directory the shell process you're creating using spawn () was spawned in, which, by default will be set to the directory you're running your Electron app from (i.e. where you ran npm run and not where your script is located).
Thus, you have to tell Node.js in what directory the shell process executing your OS code should be run in, which can be done by passing a cwd (current working directory) parameter to span () as stated in its documentation. The current script's directory can be accessed in Node.js using __dirname, which would lead to the following code:
bot = spawn(`cd ${selectedBotDir}; npm install; npm start`, {shell: true, detached: true, cwd: __dirname});
However, using this method you can get rid of the cd step entirely as you can directly set the cwd to be equal to selectedBotDir, given that that path actually starts with the current directory:
var selectedBotDir = `${__dirname}/imported_bots/toggle-base`;
// ...
try {
bot = spawn(`npm install; npm start`, {shell: true, detached: true, cwd: selectedBotDir});
// ...
} // ...
Please be aware, however, that this could break in multiple ways once you decide to package and distribute your app. By default, Electron apps will be packed into TAR-like archives, ASAR files, which will then be the __dirname. However, the OS cannot directly read from ASAR files and will once again fail to "find the requested resource". Also, if you're planning to distribute your app, don't expect users to also have NPM installed.

Uglify and Minify AngularJS Source Code without NodeJS

I want to uglify then minify my AngularJS source codes.
I have been searching for samples then I found grunt but grunt needs NodeJS our website does not run with NodeJS.
I can't find any good alternatives.
Any ideas?
Uglify code is only needed when you want to publish your code. The server doesn't need it, because it doesn't take into account spaces in code.
To clear some things up I'm showing what "grunt" is on my development machine below:
shaun#laptop:~/.npm$ which grunt
/home/shaun/local/bin/grunt
shaun#laptop:~/.npm$ ls -al /home/shaun/local/bin/grunt
lrwxrwxrwx 1 shaun shaun 39 Apr 15 2015 /home/shaun/local/bin/grunt -> ../lib/node_modules/grunt-cli/bin/grunt
shaun#laptop:~/.npm$ cat /home/shaun/local/lib/node_modules/grunt-cli/bin/grunt
#!/usr/bin/env node
'use strict';
process.title = 'grunt';
// Especially badass external libs.
var findup = require('findup-sync');
var resolve = require('resolve').sync;
// Internal libs.
var options = require('../lib/cli').options;
var completion = require('../lib/completion');
var info = require('../lib/info');
var path = require('path');
var basedir = process.cwd();
var gruntpath;
// Do stuff based on CLI options.
if ('completion' in options) {
completion.print(options.completion);
} else if (options.version) {
info.version();
} else if (options.base && !options.gruntfile) {
basedir = path.resolve(options.base);
} else if (options.gruntfile) {
basedir = path.resolve(path.dirname(options.gruntfile));
}
try {
gruntpath = resolve('grunt', {basedir: basedir});
} catch (ex) {
gruntpath = findup('lib/grunt.js');
// No grunt install found!
if (!gruntpath) {
if (options.version) { process.exit(); }
if (options.help) { info.help(); }
info.fatal('Unable to find local grunt.', 99);
}
}
// Everything looks good. Require local grunt and run it.
require(gruntpath).cli();
As you can see Grunt is a node script so it does require node to run a grunt based plugin. That said you can just download and run any node script from github or wherever, they are just JS files.
https://github.com/mishoo/UglifyJS2
^^ if you were to clone the above repository and had node installed you could just run
git clone https://github.com/mishoo/UglifyJS2.git
cd UglifyJS2
bin/uglify -m -- /full/path/to/input.js
# note the above assumes you already have node installed on the
# development machine since the bin/uglify file is interpreted/run
# by node VM
This will output the mangled js which you can then put on the server (without node at all). To reiterate your build process/tools don't need to be installed on the server (probably shouldn't be ideally).

Gulp : Prepare dist folder and edit ini file

I am trying to create a gulp task responsible to :
1. clean dist folder previouly created
2. Copy some folder inside new dist folder
3. Edit a ini file inside dist folder to update a key
var destination = './dist/test/v2';
// Copy ini file to dist folder
gulp.task('prepareDelivery', function () {
gulp.src([source + '/ini/app_sample.ini']).pipe(gulp.dest(destination + '/ini/'));
});
// update version in ini file
gulp.task('prepareAppIni', ['prepareDelivery'], function () {
var config = ini.parse(fs.readFileSync(destination + '/ini/app_sample.ini', 'utf-8'))
config.DATA.version = '1.0'
fs.writeFileSync(destination + '/ini/app.ini', ini.stringify(config, { section: 'section' }))
});
// default task
gulp.task('default', ['clean', 'prepareDelivery', 'prepareAppIni']);
I get this error :
Error: ENOENT: no such file or directory, open './dist/test/v2/ini/app_sample.ini'
I don't understand why, because i am waiting that prepareDelivery task is terminated before executing prepareAppIni task...
Could you help me ?
I don't understand why, because i am waiting that prepareDelivery task is terminated before
That's not correct.
Your default task has multiple dependencies (clean, prepareDelivery, prepareAppIni), and all of them start at the same time.
Most likely you want want prepareAppIni to depend on prepareDelivery. Which, in turn, should depend on clean task. Having this implemented, default should depend only on prepareAppIni:
gulp.task('default', ['prepareAppIni']);
Also, you are missing return in prepareDelivery, so gulp doesn't know when it finishes. Should be
// Copy ini file to dist folder
gulp.task('prepareDelivery', function () {
return gulp.src([source + '/ini/app_sample.ini']).pipe(gulp.dest(destination + '/ini/'));
});

gulp-rev creates a directory inside the destination directory

First of all, I would like to say that Gulp (for me) is creating more problems instead of solving them.
I wrote a gulpfile that concat some CSS files and put them inside a directory. The code for this task is the following:
var config = {
mainDir: 'app/assets'
};
config.stylesFiles = [
'bower_resources/admin-lte/dist/css/AdminLTE.min.css',
'bower_resources/admin-lte/dist/css/skins/_all-skins.min.css',
'css/app.css'
];
....
gulp.task('styles', function() {
return gulp
.src(config.stylesFiles, { cwd: config.mainDir })
.pipe(sourcemaps.init())
.pipe(concat('theme.css'))
.pipe(sourcemaps.write('../build/css'))
.pipe(gulp.dest('public/css/'))
.on('end', function() { gutil.log('Styles copied') });
});
It is very simple and works perfectly.
But, I would like to version this generated file. So I wrote a specific task to do it:
....
config.manifestFolder = process.cwd() + '/public/build';
gulp.task('versionCSS', function() {
return gulp
.src(['css/theme.css'], { cwd: 'public' })
.pipe(rev())
.pipe(gulp.dest('public/build/css'))
.pipe(rev.manifest(
{
base: config.manifestFolder,
cwd: config.manifestFolder,
merge: true
}
))
.pipe(gulp.dest(config.manifestFolder))
.on('end', function() { gutil.log('CSS files versioned') });
});
The problem is: when Gulp is going to run this task, it creates a folder inside the destination folder.
After running Gulp, I get this structure:
- public
- build
- css (destination folder for the versioned file)
- css (folder created by Gulp)
- versioned file that should be in the parent folder
- css
- concatenated file without version
I really don't know what to do anymore. I've already set the cwd and base options for the dest and src functions, changed the destinations, synchronized the tasks, etc. Nothing solves this stupid behavior.

Webstorm debugging with source maps from Browserify and Typescript

My project is a Laravel site, and I have the public folder renamed to "html". So my public files look like:
html
--js
----main.ts
And html is technically the root of the site for debugging purposes.
Using browserify, I have now generated some source maps for bundle.js, which have paths for main.ts. The problem is that they are pointing to the full path:
"html/js/main.ts"
Usually, I can run configurations to the html folder and catch breakpoints.
http://myapp.app:8000 ->> project>html
But this is not hitting breakpoints, since the html folder doesn't really exist in this setup. What's strange is that I can set break points in Chrome tools and it works. How can I set up Webstorm so it will hit break points in the html folder?
EDIT:
I am using the following gist for my source maps.
/**
* Browserify Typescript with sourcemaps that Webstorm can use.
* The other secret ingredient is to map the source directory to the
* remote directory through Webstorm's "Edit Configurations" dialog.
*/
'use strict';
var gulp = require('gulp'),
browserify = require('browserify'),
tsify = require('tsify'),
sourcemaps = require('gulp-sourcemaps'),
buffer = require('vinyl-buffer'),
source = require('vinyl-source-stream');
var config = {
client: {
outDir: './public/scripts',
out: 'app.js',
options: {
browserify: {
entries: './src/client/main.ts',
extensions: ['.ts'],
debug: true
},
tsify: {
target: 'ES5',
removeComments: true
}
}
}
};
gulp.task('client', function () {
return browserify(config.client.options.browserify)
.plugin(tsify, config.client.options.tsify)
.bundle()
.on('error', function (err) {
console.log(err.message);
})
.pipe(source(config.client.out))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('./', {includeContent: false, sourceRoot: '/scripts'}))
.pipe(gulp.dest(config.client.outDir));
});
I fixed it in Webstorm. The correct remote url for the html folder in run configurations is:
http://myapp.app:8000/js/html
Pretty weird, but Webstorm thinks that /js/html is a folder and that the source files are inside there.
EDIT 1 :Let me edit this answer. It turns out that the snippet above wasn't giving me all of the source maps. When inspecting the map file, the sources were being listed as js files and not ts files, which meant that the debugger wouldn't catch break points.
Here is the working gulp task, which watches any Typescript file for changes (as long as it's a dependency of main.ts and triggers browserify and the new sourcemaps. It requires the tsify plugin.
'use strict';
var watchify = require('watchify');
var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var gutil = require('gulp-util');
var sourcemaps = require('gulp-sourcemaps');
var assign = require('lodash.assign');
// add custom browserify options here
var customOpts = {
entries: ['./html/js/main.ts'],
debug: true
};
var opts = assign({}, watchify.args, customOpts);
var b = watchify(browserify(opts));
gulp.task('bundle', bundle); // so you can run `gulp js` to build the file
b.on('update', bundle); // on any dep update, runs the bundler
b.on('log', gutil.log); // output build logs to terminal
b.plugin('tsify')
function bundle() {
return b.bundle()
// log errors if they happen
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
.pipe(source('bundle.js'))
// optional, remove if you don't need to buffer file contents
.pipe(buffer())
// optional, remove if you dont want sourcemaps
.pipe(sourcemaps.init({loadMaps: true})) // loads map from browserify file
// Add transformation tasks to the pipeline here.
.pipe(sourcemaps.write({includeContent: false, sourceRoot: './'})) // writes .map file
.pipe(gulp.dest('./html/js'));
}

Categories