Debugging grunt with Intellij - node.js

I'm trying to debug grunt with Intellij (IDEA).
The technologies are: NodeJS, express, AngularJS.
The problem:
Debugger does not stop on breakpoints.
I'll be happy to hear your thoughts.
configuration tab:
Node interpreter: C:\Program Files\nodejs\node.exe
Javscript file: C:\Users[user]\AppData\Roaming\npm\node_modules\grunt-cli\bin\grunt
Browser / Live Edit tab:
http://localhost:3000/
and here is the Gruntfile.js:
var path = require('path');
module.exports = function (grunt) {
grunt.initConfig({
express: {
dev: {
options: {
script: 'server.js'
}
},
},
watch: {
html: {
files: [ '**/*.html'],
options: {
livereload: true
}
},
server: {
files: [ 'server.js'],
tasks: ['express:dev'],
options: {
livereload: true,
spawn: false // Without this option specified express won't be reloaded
}
},
js: {
files: [ '**/*.js'],
options: {
livereload: true
}
}
},
open: {
express: {
// Gets the port from the connect configuration
path: 'http://localhost:3000'
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-express-server');
grunt.loadNpmTasks('grunt-open');
grunt.registerTask('default', ['express:dev', 'watch' ])
};

Just tried a sample Angular+Express application run as a Grunt task. I've used your Gruntfile.js (unchanged). My Node.js Run configuration looks as fololows:
configuration tab:
Node interpreter: C:\Program Files\nodejs\node.exe
Javscript file: C:\Users[user]\AppData\Roaming\npm\node_modules\grunt-cli\bin\grunt
Working directory: my project root - the folder where Gruntfile.js is located
Live Edit tab:
After launch enabled
with JavaScript Debugger enabled
http://localhost:3000
I set breakpoints in my controllers.js and run the configuration above in debugger => breakpoints in Angular code work as expected. Breakpoints in my server code don't :)
To get breakpoints in server-side code working, I did the following:
added 'debug: true' to dev options in Gruntfile.js:
express: {
dev: {
options: {
script: 'server.js',
debug: true
}
}
},
modified the node_modules\grunt-express-server\tasks\lib\server.js, line 65, changing '--debug' to '--debug-brk=' ('--debug-brk=47977' in my case)

Try installing the JetBrains IDE Support extension for chrome, and then create a javascript Debug configuration like this:
(source: ignaciosuay.com)
My grunt server is running in the port 9000, so change it for 3000.
note: You need to run grunt before running this configuration.
If you have any query, please have a look to this post where is explained step by step how to debug AngularJS with Intellij.

Related

PM2 Script Not Found for bin/www

Recently i decided to run my app with pm2 as a service. For me pm2 start app.mjs runs the app as a service but it seems pm2 doesn't run my express application correctly. I used express npm to build an app like this:
//Imports
import express from "express";
//Setups
const app = express();
const port = process.env.PORT;
app.get("/", async (req, res) => {
res.send("Hello world!");
});
//Running server
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
Also tried pm2 start ./bin/www that gives me an Script not found error and it seems to be okay with express-generator not the express npm alongside an app. App works correctly in dev mode (node app.mjs).
UPDATE
I solved the problem with help of Konstantinos Lamogiannis. After setup the config file as well as the answer, i changed my app.mjs to app.js form and changed the import style to const variable = require(""); and it fixed my problem. I don't know why that happened but it seems the pm2 npm may confilct with new nodejs feature which supports the import ES6 syntax.
pm2 log was giving to me this error: unhandledRejection you may have forgotten to catch a Promise rejection !
You can try creating a file with name: ecosystem.config.js in your projects root folder and then add the following code in the file:
module.exports = {
apps: [{
name: 'yourAppName',
script: 'bin/www/app.mjs', // the path of the script you want to execute,
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
instances: 1,
autorestart: true,
watch: false,
error_file: 'err.log',
out_file: 'out.log',
log_file: 'combined.log',
time: true,
env: {
},
}],
};
In the config above you will notice that in script property its value is bin/www/app.mjs. I assume that you have app.mjs under bin/www directory and placed that value.
Then run pm2-runtime start ecosystem.config.js
EDIT #1
Assuming that your startup file is in your project's root directory use script: 'app.mjs'.
So your final ecosystem.config.js will be:
module.exports = {
apps: [{
name: 'yourAppName',
script: 'app.mjs', // the path of the script you want to execute,
// Options reference: https://pm2.keymetrics.io/docs/usage/application-declaration/
instances: 1,
autorestart: true,
watch: false,
error_file: 'err.log',
out_file: 'out.log',
log_file: 'combined.log',
time: true,
env: {
},
}],
};
Try then pm2-runtime start ecosystem.config.js from your root's project directory (where app.mjs is located).

How to start node through gulp-nodemon with a flag?

How to start node through gulp-nodemon with a flag?
gulp.task('default', function() {
// listen for changes
livereload.listen();
// configure nodemon
nodemon({
// the script to run the app
"script": 'server.js',
"ignore": ["*.test.js", "logs/*"],
"ext": 'js',
env: { 'NODE_ENV': 'development', 'DEBUG':'*' },
}).on('restart', function(){
// when the app has restarted, run livereload.
gulp.src('server.js')
.pipe(livereload())
.pipe(notify('Reloading page, please wait...'));
})
})
I'd like to start it with the flag DEBUG=* for using it with the debug library. However its not accepting it through env. Adding it after the script name results in an error.
How do I add a flag to nodemon within a gulp script?
Take a look at this issue. It is suggested there to set stdout: true or to use the exec option, i.e.:
nodemon({
...
exec: 'node DEBUG=*'
});
If this does not work you can try the options args and nodeArgs shown in this issue, i.e.:
nodemon({
...
args: ['DEBUG=*']
});
I did not try these approaches myself but I hope they will help.
Debug is not any more using a flag like you can read it in several blog posts. It now uses an env variable instead.
nodemon({
"script": 'server.js',
"ignore": ["*.test.js", "logs/*"],
"ext": 'js',
"env": { 'NODE_ENV': 'development', 'DEBUG':'*' },
})
or by running it with env var on shell
DEBUG=* node server.js

webpack-dev-middleware and Express - can't get them to collaborate

I am trying to set up my first project using Webpack and Express but somehow I am doing something wrong.
This is what I did:
1. CREATED SAMPLE PROJECT
Created a sample project using express-generator. My folder structure is something like:
express-project
-app.js
-webpack.config.js
-public
-javascripts
-modules
-build
2. SET UP HANDLEBARS
Set up handlebars as view/template engine and created a couple of routes
3. WEBPACK CODE
Created the Webpack specific code/configuration as follows
webpack.config.js
var webpack = require('webpack');
var path = require('path');
var webpackHotMiddleware = 'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&overlay=false';
module.exports = {
resolve: {
alias: {
handlebars: path.resolve('public/vendor/handlebars-v4.0.5.js'),
bootstrap: path.resolve('public/vendor/bootstrap/js/bootstrap.js'),
pubsub: path.resolve('public/vendor/ba-tiny-pubsub.js')
}
},
context: path.resolve('public/javascripts'),
entry: {
cart: ['./modules/cart', webpackHotMiddleware],
index: ['./modules/products.js', webpackHotMiddleware],
vendor: ['bootstrap', 'pubsub', webpackHotMiddleware]
},
output: {
path: path.resolve('public/javascripts/build'),
publicPath: 'javascripts/build/',
filename: '[name].js',
chunkFilename: "[id].js"
},
module: {
loaders: [
// some loaders here
]
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
}
app.js
// some code before
var app = express();
(function() {
// Step 1: Create & configure a webpack compiler
var webpack = require('webpack');
var webpackConfig = require(process.env.WEBPACK_CONFIG ? process.env.WEBPACK_CONFIG : './webpack.config');
var compiler = webpack(webpackConfig);
// Step 2: Attach the dev middleware to the compiler & the server
app.use(require("webpack-dev-middleware")(compiler, {
noInfo: false,
publicPath: webpackConfig.output.publicPath,
stats: {
colors: true
}
}));
// Step 3: Attach the hot middleware to the compiler & the server
app.use(require("webpack-hot-middleware")(compiler, {
log: console.log,
path: '/__webpack_hmr',
heartbeat: 10 * 1000
}));
})();
// some code after
4. JS CODE ON TEMPLATE
Then on the handlebars page I require the bundled javascripts
<script src="javascripts/build/common.js"></script>
<script src="javascripts/build/vendor.js"></script>
<script src="javascripts/build/cart.js"></script>
5. NPM START
Finally if I start the server using the standard npm start I see in the shell that webpack bundles everything with no errors but if I go to localhost:3000/ it does not find any of the assets created by Webpack. Instead if I run webpack to create the various bundles as if I were on production, everything is created correctly and it works as expected.
Hope someone can figure out what I am doing wrong.
Thanks
I managed to figure out what was causing the problem, by adding a slash in these 2 lines everything started to work properly:
context: path.resolve('public/javascripts/'),
path: path.resolve('public/javascripts/build/'),

Running a node express server using webpack-dev-server

I'm using webpack to run my react frontend successfully using the following config:
{
name: 'client',
entry: './scripts/main.js',
output: {
path: __dirname,
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query:{
presets: ['es2015', 'react', 'stage-2']
}
}
]
}
}
I'm trying to put up a node.js express backend as well, and would like to run that through webpack as well, so that I have a single server running both the backend and frontend, and because I want to use babel to transpile my javascript.
I made a quick testserver looking like this:
var express = require('express');
console.log('test');
var app = express();
app.get('/', function(req, res){
res.send("Hello world from Express!!");
});
app.listen(3000, function(){
console.log('Example app listening on port 3000');
});
If I run this with node index.js and open my browser on localhost:3000 it prints "Hello world from Express!!". So far so good. Then I tried creating a web-pack config for it:
var fs = require('fs');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
module.exports = [
{
name: 'server',
target: 'node',
entry: './index.js',
output: {
path: __dirname,
filename: 'bundle.js'
},
externals: nodeModules,
module: {
loaders: [
{
test: /\.js$/,
loaders: [
'babel-loader'
]
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
}
}
When I run the command webpack-dev-server it starts up successfully (it seems). However, if I go to my browser on localhost:3000 now, it just says that the webpage is not available, just as when the server is not running at all.
I'm very new to both node and webpack, so either I have made a small mistake somewhere, or I'm way off ;)
Webpack-dev-server is great for client side development but it will not deploy Express api's or middleware. So in development I recommend running two separate servers: One for the client and one for your server side api's.
Nodemon npm install --save-dev nodemon is a good backend development server that will give you hot-redeploy of your api's, or you can just use express and restart when you make changes. In production the client and api will still be served by the same express server.
Set a lifecycle event for both nodemon and webpack-dev-server in your package.json to make starting them easy (example: npm run dev-server).
"scripts": {
"start": "webpack --progress --colors",
"dev-server": "nodemon ./server.js localhost 8080",
"dev-client": "webpack-dev-server --port 3000",
}
Or, to run express directly from node:
"scripts": {
"start": "webpack --progress --colors",
"dev-server": "node dev-server.js",
"dev-client": "webpack-dev-server --port 3000",
}
// dev-server.js
const express = require('express');
const app = express();
// Import routes
require('./_routes')(app); // <-- or whatever you do to include your API endpoints and middleware
app.set('port', 8080);
app.listen(app.get('port'), function() {
console.log('Node App Started');
});
Note: The api server must use a different port than webpack-dev-server.
And finally in your webpack-dev-config you need to use a proxy to redirect calls to your api to the new port:
devServer: {
historyApiFallback: true,
hot: true,
inline: true,
host: 'localhost', // Defaults to `localhost`
port: 3000, // Defaults to 8080
proxy: {
'^/api/*': {
target: 'http://localhost:8080/api/',
secure: false
}
}
},
// and separately, in your plugins section
plugins: [
new webpack.HotModuleReplacementPlugin({
multiStep: true
})
]
**Bonus points for having a single script to start and kill both
Since webpack-dev-server is just a tiny express server with compile on change and hot reload.
So, if you already got a express server for backend API, just merge the compile on change and hot reload into your express server.
Then after take a look at the package.json of webpack-dev-server, i find the key is just
webpack-dev-middleware
const express = require('express'); //your original BE server
const app = express();
const webpack = require('webpack');
const middleware = require('webpack-dev-middleware'); //webpack hot reloading middleware
const compiler = webpack({ .. webpack options .. }); //move your `devServer` config from `webpack.config.js`
app.use(middleware(compiler, {
// webpack-dev-middleware options
}));
app.listen(3000, () => console.log('Example app listening on port 3000!'))
So, when you run your BE server, it will compile all the things using webpack, and watch for changes, LOL ~
Also, add webpack-hot-middleware for hot reloading function, see Hot Module Replacement
From your questions here and here, it appears that you are using ReactJS with ES6. I faced the exact same issue, and here is how I tackled it -
Have multiple entry points for your application
In particular you can put all your vendor files like JQuery, React etc into one chunk. This way, your vendor files will remain the same even when you modify your souce files. You can add this line to your webpack config
entry: {
vendors: ['react','reactDom','jquery'] //Any other libraries
}
Use the CommonsChunkPlugin to have webpack determine what code/modules you use the most, and put it in a separate bundle to be used anywhere in your application.
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendors', 'dist/js/vendors.js', Infinity),
]
Use React Hot Loader
Run npm install react-hot-loader --save-dev. Make sure you have installed webpack-dev-server first.
Then you need to change your loaders to this -
loaders: [
{
test: /\.jsx?$/,
loaders: ['react-hot'],
include: path.join(__dirname, 'public')
},{
loader: 'babel',
query: {
presets: ['react', 'es2015']
},
include: path.join(__dirname, 'public')
},
]
Make sure React Hot Loader comes before Babel in the loaders array. Also make sure you have include: path.join(__dirname, 'public') to avoid processing node_modules, or you may get an error like this -
Uncaught TypeError: Cannot read property 'NODE_ENV' of undefined
Modifications to your script tags in your index.html page
If your html has something like this -
<script src="/dist/js/vendors.js"></script>
<script src="/dist/js/app.bundle.js"></script>
Change this to point to your webpack-dev-server proxy -
<script src="http://localhost:8080/dist/js/vendors.js"></script>
<script src="http://localhost:8080/dist/js/app.bundle.js"></script>
Run webpack-dev-server --hot --inline,
wait for the bundling to finish, then hit http://localhost:3000 (your express server port) in your browser.
If you run into any errors, you could find this troubleshooting guide very useful.
Hope this helps, and you can take a look at the webpack setup for my project here
Just faced the same issue and came with another solution (found out more information about it later, but here it is).
Instead of using the webpack-dev-server, use the webpack --watch command so files are compiled again upon changes. Once the files are updated on the dist (or any other compiled files folder) you can set to run the nodemon on the dist folder and watch only the dist files.
This way it is possible to have the express server running and serving the front-end as you would in a production environment (or kinda) and benefit from the fast reloads.
Here's a link with some solutions to combine the webpack watch and nodemon.
My scripts section is something like this at this moment (I'm using the run-all solution):
"scripts": {
"serve": "npm-run-all --parallel serve:webpack serve:nodemon",
"serve:webpack": "webpack --progress --colors --watch",
"serve:nodemon": "nodemon ./dist/app.js --watch dist"
},
I found this to be a really simple solution that works with create-react-app, where you just want to use npm start to start the webpack-dev-server and you can't mess around with the webpack config. Just use http-proxy-middleware in Express to proxy all requests that the server doesn't itself handle to the webpack-dev-server:
import express from "express"
import { createProxyMiddleware } from "http-proxy-middleware"
const app = express()
// Put your web APIs here, for example:
app.get("/hello", (req, res) => {
res.send("Hello World")
})
...
// This goes after all your other routes:
if (!isProduction) {
app.use("*", createProxyMiddleware({ target: "http://127.0.0.1:3000", ws: true }))
}
app.listen(5000)
Note 1: To keep this simple, I am not using HTTPS. (Use environment variable HTTPS=false to have webpack-dev-server use HTTP.)
Note 2: You only want to create the proxy in development mode - in production, you would probably use express.static to serve your compiled single-page app.
Run npm start on your React project and start your Express server. Then (using the port numbers in the example code) browse to http://localhost:5000. You will see your React front-end and it will be able to send API requests to your Express server, all on port 5000. Hot module replacement works too!
quick answer: webpack-dev-server has an express built in, just use onAfterSetupMiddleware or onBeforeSetupMiddleware to get the app instance
module.exports = {
//...
devServer: {
onBeforeSetupMiddleware: function (devServer) {
if (!devServer) {
throw new Error('webpack-dev-server is not defined');
}
// **devServer.app is an express**
devServer.app.get('/some/path', function (req, res) {
res.json({ custom: 'response' });
});
},
},
};
tl;dr
there are some ways to make it work, the one above is what I love most, let's have a look at other work arounds
1.proxy: config webpack dev server with proxy
this way you need an extra process for backend only, that means an extra step to start and stop your service, still it's a good enough solution, simple and works
2.webpack-dev-middleware: a middleware for express
lack both documentation and maintainess, I was using it and made it work, but when some package updates it fails to work

Grunt livereload with node.js application

I have written an application in Node.js (with Express & socket.io) and I would like to use Grunt to compile my client-side stuff with livereload while developing and being connected to Node.js application. How can I do this? (Preferably without running Node.js app in another port and client in another port, because of pathing and cross-domain issues)
I installed also Yeoman and it's using out of the box grunt-contrib-livereload package, but from what I understood it's using Node.js Connect server for serving client-side files, thus being separated from my Node.js application..
Example from Gruntfile.js generated by Yeoman:
var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
var mountFolder = function (connect, dir) {
return connect.static(require('path').resolve(dir));
};
// ... cut some parts
grunt.initConfig({
watch: {
livereload: {
files: [
'<%= yeoman.app %>/*/*.html',
'{.tmp,<%= yeoman.app %>}/styles/*.css',
'{.tmp,<%= yeoman.app %>}/scripts/*.js',
'<%= yeoman.app %>/images/*.{png,jpg,jpeg}'
],
tasks: ['livereload']
}
// ..cut some parts
},
connect: {
livereload: {
options: {
port: 9000,
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, 'app')
];
}
}
}
}
// ..cut some parts
});
grunt.registerTask('server', [
'clean:server',
'coffee:dist',
'compass:server',
'livereload-start',
'connect:livereload',
'open',
'watch'
]);
Not sure if you have solved this question yet, but I have done this by adding my express application as a middleware attached to the 'connect.livereload.options.middleware' option.
However, automatic reloading of server side code doesn't work. For that you could implement a reload friendly server using a simple 'node ./server.js', create a connect middleware that acts as a transparent proxy to your development server, and invoke that within your Gruntfile.js before your standard connect/livereload server starts.
connect: {
options: {
port: 9000,
// change this to '0.0.0.0' to access the server from outside
hostname: 'localhost'
},
livereload: {
options: {
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, 'app'),
require('./server') // your server packaged as a nodejs module
];
}
}
}
}
server.js:
var app = express();
...
// Export your server object.
module.exports = app;
My answer is using Gulp that I am more familiar with, instead of Grunt, but I imagine the same approach would work with Grunt as well.
See my repository (and an older one) and my other answer.
Neither any browser extension nor adding any script to your files is needed.
The solution is based on the gulp-livereload and connect-livereload packages working together. First, you start your live reload listener, and pipe into it any file changes (change * to any more specific node-glob to listen to only specific files):
var gulpLivereload = require('gulp-livereload');
gulpLivereload.listen();
gulp.watch('*', function(file) {
gulp.src(file.path)
.pipe(gulpLivereload());
});
Second, you configure your server to use the listener as middleware via connect-livereload:
var connect = require('connect');
var connectLivereload = require('connect-livereload');
connect()
.use(connectLivereload())
.use(connect.static(__dirname))
.listen(8080);
See the packages for more information on how they work internally.
In the Gruntfile, remove connect:livereload and open from server task.
Add following script in the HTML file
<!-- livereload script -->
<script type="text/javascript">
document.write('<script src="http://'
+ (location.host || 'localhost').split(':')[0]
+ ':35729/livereload.js?snipver=1" type="text/javascript"><\/script>')
</script>

Resources