How to use the Node debug module with Grunt? - node.js

How can I use Node's debug module with Grunt?
I know that to use the module I need to set the DEBUG env var in the command line like so:
$ DEBUG=* node app.js
But, I am struggling to figure out how to do it with Grunt.

I used grunt-env to help set env variable in grunt as below:
grunt.loadNpmTasks('grunt-env');
// Define the configuration for all the tasks
grunt.initConfig({
// Env-specific configuration
env: {
options: {
//Shared Options Hash
},
dev: {
NODE_ENV: 'development',
DEBUG: 'wukong:*,loopback:security:role,-not_this'
},
test: {
NODE_ENV: 'test',
DEBUG: 'wukong:*,-not_this'
}
},
// ...
}
However, it doesn't work because debug module load and save process.env.DEBUG at the very beginning of module initialization: https://github.com/visionmedia/debug/blob/master/node.js#L209
Thus, I played a trick to load the DEBUG variable again via its "hidden" public API - enable as:
const debug = require('debug');
debug.enable(process.env.DEBUG);
module.exports = debug;
When this debug wrapper is used instead, grunt could print out debug message as expected.
Hope this workaround works for you as well. ;)

Related

How do I make Vite not convert process.env to specific value during build?

Background
I use Vite to build my project from esModule to CommonJS, and I will run the result in NodeJS.
One problem that bothers me is that process.env has been converted to a specific value, but I just want process.env to stay the way it is because I will pass in the concrete value when NodeJS runs the result.
Although it is built using Vite, I think this should be a problem with Rollup.
UPDATE: It should be vite's problem.
Detail
My code looks something like this:
useVariable(process.env.ROOT)
The result of the build is something like this:
useVariable({}.ROOT)
The build result I expect:
useVariable(process.env.ROOT) // Keep it as it is
It's my config:
export default defineConfig({
build: {
outDir: '../../dist',
lib: {
entry: path.resolve(__dirname, './index.ts'),
name: 'main',
formats: ['cjs']
},
rollupOptions: {
plugins: [
autoExternal({ packagePath: './package.json' })
]
}
}
})

How to pass webpack env into nodejs application?

I compile my nodejs application with webpack.
And I want to pass variable to my application say version.
so after I run this command:
webpack --env.VERSION=1.2.2
I run my application but I got undefined on console.log({ v: process.env.VERSION });.
How to pass webpack env into nodejs application?
I can't use cross-env or something like that. I want to compile with webpack and having the env variables in my application.
Read the docs for the --env flag (here):
The webpack command line environment option --env allows you to pass in as many environment variables as you like. Environment variables will be made accessible in your webpack.config.js.
You can use the DefinePlugin plugin to have webpack replace strings with the value of your environment variables.
For example, to replace the use of process.env.VERSION in your application code to the value of the environment variable you have set using the --env flag at build time:
plugins: [
new webpack.DefinePlugin({
"process.env.VERSION": JSON.stringify(process.env.VERSION)
})
]
According to documentation on webpack, the env variable will be available in your webpack.config.js like this
const path = require('path');
module.exports = env => {
// Use env.<YOUR VARIABLE> here:
console.log('NODE_ENV: ', env.NODE_ENV); // 'local'
console.log('Production: ', env.production); // true
return {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
};
See here for more details :
https://webpack.js.org/guides/environment-variables/

Set NODE_ENV from Grunt task

I would like to set the NODE_ENV variable at the beginning of a Grunt task, to development or production, but it looks it's not as simple as I thought.
The reason, why I would like this is that I use grunt-webpack, which expects NODE_ENV to be set correctly to "development" or "production". But I also would like to initialize my tasks exclusively from grunt, if possible.
I created the following test Gruntfile, using the grunt-shell and cross-env modules:
function log(err, stdout, stderr, cb, e) {
if (err) {
cb(err);
return;
}
console.log(process.env.NODE_ENV);
console.log(stdout);
cb();
}
module.exports = function(grunt) {
grunt.initConfig({
shell: {
dev: {
command : 'cross-env NODE_ENV="development"',
options: {
callback: log
}
},
dist: {
command : 'cross-env NODE_ENV="production"',
options: {
callback: log
}
}
}
});
grunt.loadNpmTasks('grunt-shell');
};
Line 6 of log() should echo the actual value of process.env.NODE_ENV, but it constantly says undefined, even if I check it manually in the node console.
If I set it manually from the terminal, like set NODE_ENV=production (set is for Windows), everywhere echoes the value production, as I would like it to.
Your test won't work because grunt-shell runs a child_process and your callback runs after it ends and under the main process.
Same thing would happen with cross-env.
If you want to pass an environment variable to grunt-shell, you should use the options configuration according to the documentation.
For example:
grunt.initConfig({
shell: {
dev: {
command : 'echo %NODE_ENV%', //windows syntax
options: {
execOptions: {
env: {
'NODE_ENV': 'dev'
}
},
callback: log
}
}
}
});
This will still print undefined for process.env.NODE_ENV, but the value of NODE_ENV will be available in the stdout because of the echo.
On a side note, it sounds like you're trying to run a process (grunt-shell), which runs a process (cross-env), which runs a process (webpack or grunt-webpack).
Why not just use the cross-env example usage? It looks pretty close to what you need.
Or you can just define the variable in the task config itself and lose all of these wrappers.
LifeQuery's answer helped me a lot to find out what the problem actually was. I first realized that webpack.DefinePlugin() actually doesn't change anything on process.env.NODE_ENV (and it would be too late anyway, as it transforms code parsed by webpack after all loaders).
After this I created a solution, which does what I want. This is how my customized Gruntfile.js begins:
'use strict';
const path = require('path');
const webpack = require('webpack');
module.exports = function (grunt) {
// Setting the node environment based on the tasks's name or target
let set_NODE_ENV = function () {
const devTasks = ['webpack-dev-server', 'dev', 'hmr', 'watch'],
devTargets = [':dev'],
task = grunt.cli.tasks[0], // The name of the (first) task we initialized grunt with ('webpack-dev-server' if started 'grunt webpack-dev-server)
target = ':'+grunt.option('target'),
devEnv = (devTasks.indexOf(task) > -1 || devTargets.indexOf(target) > -1);
process.env.NODE_ENV = devEnv ? 'development' : 'production';
}();
const webpackConfig = require('../assets/webpack.config');
grunt.initConfig({
// ...usual Gruntfile content
});
};
I created a whitelist of grunt task names and targets when I set the process.env.NODE_ENV. As it is placed before the grunt.initConfig(), the configuration object can use process.env.NODE_ENV with the desired state.
It will set NODE_ENV to "development" if starting definitely webpack-dev-server, dev, hmr or watch tasks, or any other tasks with the :dev target.

How set/get environment specific variable in a Yeoman Ember app

Considering an Yeoman Ember app.
I've looked different tools like:
https://github.com/logankoester/grunt-environment
https://github.com/jsoverson/grunt-env
https://github.com/outaTiME/grunt-config
But I don't quite see how can you set/get for instance different adapter url in your router.js depending on some grunt/node environment.
One approach would be having for example two files: development.properties and production.properties, and using grunt you can copy them to a current.properties file and then you can read the current.properties file always, using for example nconf from any place of your application.
You just need to use the grunt-contrib-copy tasks in your grunt file.
Summary: create a gruntfile that read the environment from the command line and copy the corresponding file property to current.properties, and then in your route.js you just include nconf and you just use it.
Also as an alternative nconf can read parameters from the command line given to node when you run it, so you can avoid the grunt file and run it like node app.js --property=value and take the value of the property with nconf from your route.js
So I ended up figuring out a way that works well but only with two env:
I made a pull-request for the ember-generator to start using that pattern:
https://github.com/borisrorsvort/generator-ember/commit/66f26e9e5a7599da53cb99b85e8ef5864648349b
Here is an implementation that works with yeoman ember generator:
Your replace task should look something like this:
replace: {
app: {
options: {
variables: {
ember: 'bower_components/ember/ember.js',
ember_data: 'bower_components/ember-data-shim/ember-data.prod.js',
app_config: 'scripts/app_config/development.js'
}
},
files: [{
src: '<%= yeoman.app %>/index.html',
dest: '.tmp/index.html'
}]
},
dist: {
options: {
variables: {
ember: 'bower_components/ember/ember.prod.js',
ember_data: 'bower_components/ember-data-shim/ember-data.prod.js',
app_config: 'scripts/app_config/production.js'
}
},
files: [{
src: '<%= yeoman.app %>/index.html',
dest: '.tmp/index.html'
}]
}
}
======
Then add '##app_config' the index.html under ##ember and ##ember_data so that it get replaced by the correct string
======
Then create two files:
app/templates/scripts/app_config/development.js
app/templates/scripts/app_config/production.js
These contain an AppConfig onject that you can use in your Ember App
var AppConfig = {};
======
Now Imagine you want to change your adapter when you're building the app:
Just use:
MyApp.ApplicationAdapter = DS.RESTAdapter.extend({
host: AppConfig.apiAdapterUrl
});

Nodemon-like task in Grunt : execute node process and watch

I feel like I'm missing something.
Here is what I want to achieve :
Having a grunt task that executes my server.js and runs watch task in parallel. It feels to me that this is precisely one of the tasks grunt was designed for but I can't achieve this configuration.
Among others, I have read this :
Running Node app through Grunt
but I still can't make it.
Here is my Gruntfile.js :
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
watch: {
scripts: {
files: ['*.js'],
tasks: ['start'],
options: {
nospawn: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('start', function() {
grunt.util.spawn({
cmd: 'node',
args: ['server.js']
});
grunt.task.run('watch');
});
grunt.registerTask('default', 'start');
};
I have "grunt-contrib-watch": "~0.3.1" which should be higher version than grunt-contrib-watch#0.3.0 as in the previously mentioned post.
If you could help me achieve the proper configuration, I would be extremely grateful. But more in general, I don't understand why there is no official grunt-contrib-nodemon-like package and task since I have the feeling it would be another great reason to use grunt (which I really like as a tool !)
Thanks
Edit: grunt-nodemon
since writing this, a nice person developed that.
I was having a lot of trouble using grunt.util.spawn to fire off new processes. They would run, but they wouldn't give me any output back. Perhaps you can figure out what I could not in these docs. http://gruntjs.com/api/grunt.util#grunt.util.spawn
Two problems I see with what you have:
I think grunt.registerTask() has to take three arguments when you use a callback function to run your task.
I don't think you can just call node server.js over and over again everytime a file changes. It will work on the first time, for it to really work you'd have to manage the server as a child process, killing and restarting it on subsequent file changes.
For the registerTask arguments try this, just to see if you can get something to work in your current implementation.
http://gruntjs.com/api/grunt.task#grunt.task.registertask
It takes (taskName, description, taskFunction) like so:
grunt.registerTask('start', 'My start task description', function() {
grunt.util.spawn({
cmd: 'node',
args: ['server.js']
});
grunt.task.run('watch');
});
That might at least get your watch to run node server.js the first time a file changes.
Here's what I would do instead.
Either just use nodemon $ nodemon server.js as is
or...
Read the source and use grunt-develop
He is managing the server as a child process, might be what you're looking for.
or...
Get grunt-shell
npm install grunt-shell --save-dev
And use it to run nodemon for you:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
serverFile: 'server.js',
shell: {
nodemon: {
command: 'nodemon <%= serverFile %>',
options: {
stdout: true,
stderr: true
}
}
},
watch: { /* nothing to do in watch anymore */ }
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-shell');
grunt.registerTask('default', 'shell:nodemon');
};
$ grunt shell:nodemon
I sincerely hope that helps. Good luck!
Hi I also came across this problem and here is my solution (based on nackjicholson's answer). This uses grunt-nodemon in a spawned process. so I can:
Reload nodejs
Watch for changes to e.g. .less files
Get output of both tasks
grunt.loadNpmTasks('grunt-nodemon');
grunt.initConfig({
nodemon: {
dev: {
options: {
file: 'server.js',
nodeArgs: ['--debug'],
env: {
PORT: '8282'
}
}
}
},
});
grunt.registerTask('server', function (target) {
// Running nodejs in a different process and displaying output on the main console
var nodemon = grunt.util.spawn({
cmd: 'grunt',
grunt: true,
args: 'nodemon'
});
nodemon.stdout.pipe(process.stdout);
nodemon.stderr.pipe(process.stderr);
// here you can run other tasks e.g.
// grunt.task.run([ 'watch' ]);
});
Use grunt-concurrent
The issue is that tasks like watch and nodemon will never terminate, so grunt will never reach them. You need to spawn a new process.
You can do this easily using grunt-concurrent:
https://github.com/sindresorhus/grunt-concurrent
For example:
module.exports = function(grunt) {
grunt.initConfig({
...
concurrent: {
dev: {
tasks: ['nodemon', 'watch'],
options: {
logConcurrentOutput: true
}
}
}
});
};
The two will now run happily side by side.

Resources