Run npm script with nodemon command - node.js

I am testing GraphQL Server from Apollo and what to integrate nodemon to it. Here's sample file structure :
build/
src/
server.js
Here my npm scripts looks like this
"scripts": {
"start": "babel --presets es2015,stage-2 server.js -d build/ && node build/server.js",
"dev": "nodemon server.js" // Sample code here
}
What npm run start would do is to convert ES6 code into build/server.js using babel and execute it. This would start the server correctly.
What I want is to watch for changes in server.js or in src/ and restart the server if changes occur. Here I want to execute npm run start command if any changes occur. What is the correct 'nodemon' command to my need. Its better if I could use npm run dev like command to start development using nodemon.

you can use gulpjs to watch any changes in specific folders and then command it to do something.
With your sample, you want to convert the code to es6 too. so it also need gulp-bable and . you can include babel-preset-stage-2 if you want. So you can simply put the code below in gulpfile.js
gulp.task('build-es2015', () => {
return gulp.src('server.js')
.pipe(babel({
presets: ['es2015']
}))
.pipe(gulp.dest('build'));
});
gulp.task('watch', () => {
gulp.watch(['./app/*.js'], ['build-es2015'])
})
Basically, the task 'watch' will keep watching the specific files. When they are saved then it will to execute the task 'build-es2015' to convert to es6.
And then nodemon, it needs gulp-nodemon then you can do on gulpfile.js
gulp.task('server', () => {
nodemon({
script: 'build/server.js',
ext: 'js',
ignore: [
'server.js',
'node_modules/**',
'test/**',
'build/**'
]
})
.on('restart', () => { console.log(`Server restarted!`) })
})
The above will keep watching build/server.js'. whenever it is changed, nodemon will automatically restart the server.
And the last piece for gulpfile.js
gulp.task('dev', ['server', 'watch'])
Include the tasks that need to be executed for gulp command.
$ gulp dev
or with npm command
"scripts": {
"start": "gulp dev"
}
so you can npm run start as well.
And dont forget to require all packages in gulpfile.js
const gulp = require('gulp')
const babel = require('gulp-babel')
const nodemon = require('gulp-nodemon')

Related

how to run "npm start" by PM2?

I have seen many questions here but that was not working for me. That why asking this question?
I am using DigitalOcean Ubuntu 16.04 server. I have a node project run by "npm start".
Script is:
"scripts": {
"start": "node ./bin/www"
}
generally pm2 work for
pm2 start app.js
As my script is like this and run by npm start how can I run my server forever.
You can run built-in npm scripts like this:
pm2 start npm -- start
If you have a custom script, you can run like this:
pm2 start npm -- run custom
--
In your case, pm2 start npm -- start would run node ./bin/www. Change the start script to node app.js if you want to run node app.js.
Yes, you can do it very efficiently by using a pm2 config (json) file with elegance.
package.json file (containing below example scripts)
"scripts": {
"start": "concurrently npm:server npm:dev",
"dev": "react-scripts start",
"build": "node ./scripts/build.js",
"eject": "react-scripts eject",
"lint": "eslint src server",
"shivkumarscript": "ts-node -T -P server/tsconfig.json server/index.ts"
}
Suppose we want to run the script named as 'shivkumarscript' with pm2 utility. So, our pm2 config file should be like below, containing 'script' key with value as 'npm' and 'args' key with value as 'run '. Script name is 'shivkumarscript' in our case.
ecosystem.config.json file
module.exports = {
apps: [
{
name: "NodeServer",
script: "npm",
automation: false,
args: "run shivkumarscript",
env: {
NODE_ENV: "development"
},
env_production: {
NODE_ENV: "production"
}
}
]
}
Assuming that you have already installed Node.js, NPM and PM2 on your machine. Then below should be the command to start the application through pm2 which will in turn run the npm script (command line mentioned in your application's package.json file):
For production environment:
pm2 start ecosystem.config.js --env production --only NodeServer
For development environment:
pm2 start ecosystem.config.js --only NodeServer
...And Boooom! guys
My application is called 'app.js'. I have the exact same start script for an express Node.js application.
And after googling tons this solved my problem, instead of calling pm2 start app.js.
pm2 start ./bin/www
for this first, you need to create a file run.js and paste the below code on that.
const { spawn } = require('child_process');
//here npm.cmd for windows.for others only use npm
const workerProcess = spawn('npm.cmd', ['start']);
workerProcess.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
workerProcess.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
workerProcess.on('close', function (code) {
console.log('child process exited with code ' + code);
});
and run this file with pm2.
pm2 start run.js

Passing variables from NPM Scripts to Webpack

I have a production build with Webpack that uses node's process.env to set environment variables:
webpack.prod.babel.js:
const DefinePlugin = new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
API_URL: JSON.stringify('https://myprodurl.com'),
},
});
packge.json:
"scripts: {
"build:prod": "webpack"
}
It's working fine, but I need something different.
I need to set the production url as variable in the NPM Script.
So, instead of this:
npm run build:prod
I need this:
npm run build:prod --URL https://myprodurl.com
How about defining your environment variable in the command line, like:
URL=https://myprodurl.com npm run build:prod
I tested this with a simple script and was able to print out the URL.
"scripts": {
"test": "./myTest.js"
},
myTest.js:
#!/usr/local/bin/node
'use strict'
console.log(process.env.URL);
console.log('Done!');
then:
$ URL=https://whatever.com npm run test
> my-test#1.0.0 test /Test/my-test
> ./myTest.js
https://whatever.com
Done!
EDIT: As mentioned by #RyanZim, see the following for Windows: https://github.com/kentcdodds/cross-env
(disclaimer: I don't use Windows and have never tried this lib)

Webpack --watch and launching nodemon?

Thanks to an excellent answer by #McMath I now have webpack compiling both my client and my server. I'm now on to trying to make webpack --watch be useful. Ideally I'd like to have it spawn something like nodemon for my server process when that bundle changes, and some flavor of browsersync for when my client changes.
I realize it's a bundler/loader and not really a task runner, but is there some way to accomplish this? A lack of google results seems to indicate I'm trying something new, but this must have been done already..
I can always have webpack package to another directory and use gulp to watch it/copy it/browsersync-ify it, but that seems like a hack.. Is there a better way?
Install the following dependencies:
npm install npm-run-all webpack nodemon
Configure your package.json file to something as seen below:
package.json
{
...
"scripts": {
"start" : "npm-run-all --parallel watch:server watch:build",
"watch:build" : "webpack --watch",
"watch:server" : "nodemon \"./dist/index.js\" --watch \"./dist\""
},
...
}
After doing so, you can easily run your project by using npm start.
Don't forget config WatchIgnorePlugin for webpack to ignore ./dist folder.
Dependencies
npm-run-all - A CLI tool to run multiple npm-scripts in parallel or sequential.
webpack - webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
nodemon - Simple monitor script for use during development of a node.js app.
Faced the same problem and found the next solution - webpack-shell-plugin.
It
allows you to run any shell commands before or after webpack builds
So, thats my scripts in package.json:
"scripts": {
"clean": "rimraf build",
"prestart": "npm run clean",
"start": "webpack --config webpack.client.config.js",
"poststart": "webpack --watch --config webpack.server.config.js",
}
If I run 'start' script it launches next script sequence: clean -> start -> poststart.
And there is part of 'webpack.server.config.js':
var WebpackShellPlugin = require('webpack-shell-plugin');
...
if (process.env.NODE_ENV !== 'production') {
config.plugins.push(new WebpackShellPlugin({onBuildEnd: ['nodemon build/server.js --watch build']}));
}
...
"onBuildEnd" event fires only once after first build, rebuilds are not trigger "onBuildEnd", so nodemon works as intended
I like the simplicity of nodemon-webpack-plugin
webpack.config.js
const NodemonPlugin = require('nodemon-webpack-plugin')
module.exports = {
plugins: [new NodemonPlugin()]
}
then just run webpack with the watch flag
webpack --watch
In addition to #Ling's good answer:
If you want to build your project once, before you watch it with nodemon, you can use a webpack compiler hook. The plugin's code triggers nodemon in the done hook once after webpack has finished its compilation (see also this helpful post).
const { spawn } = require("child_process")
function OnFirstBuildDonePlugin() {
let isInitialBuild = true
return {
apply: compiler => {
compiler.hooks.done.tap("OnFirstBuildDonePlugin", compilation => {
if (isInitialBuild) {
isInitialBuild = false
spawn("nodemon dist/index.js --watch dist", {
stdio: "inherit",
shell: true
})
}
})
}
}
}
webpack.config.js:
module.exports = {
...
plugins: [
...
OnFirstBuildDonePlugin()
]
})
package.json:
"scripts": {
"dev" : "webpack --watch"
},
Hope, it helps.
There's no need to use plugins here. You could try running multiple nodemon instances like below. Try modifying the following script for your use case, and see if it works for you:
"scripts": {
"start": "nodemon --ignore './public/' ./bin/www & nodemon --ignore './public/' --exec 'yarn webpack'",
"webpack": "webpack --config frontend/webpack.config.js"
}
You don't need any plugins to use webpack and nodemon, just use this scripts on your package.json
"scripts": {
"start": "nodemon --ignore './client/dist' -e js,ejs,html,css --exec 'npm run watch'",
"watch": "npm run build && node ./server/index.js",
"build": "rimraf ./client/dist && webpack --bail --progress --profile"
},
#Ling has an answer very close to being correct. But it errors the first time somebody runs watch. You'll need to modify the solution as so to prevent errors.
Run npm install npm-run-all webpack nodemon
Create a file called watch-shim.js in your root. Add the following contents, which will create a dummy file and directory if they're missing.
var fs = require('fs');
if (!fs.existsSync('./dist')) {
fs.mkdir('./dist');
fs.writeFileSync('./dist/bundle.js', '');
}
Setup your scripts as so in package.json. This will only run watch if the watch-shim.js file runs successfully. Thereby preventing Nodemon from crashing due to missing files on the first run.
{
...
"scripts": {
"start": "npm run watch",
"watch": "node watch-shim.js && npm-run-all --parallel watch:server watch:build",
"watch:build": "webpack --progress --colors --watch",
"watch:server": "nodemon \"./dist/bundle.js\" --watch \"./dist/*\""
}
...
},
Assuming nodemon server.js touch the server.js file afterEmit:
// webpack.config.js
module.exports = {
// ...
plugins: [
// ...,
// 👇
apply: (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
require('child_process').execSync('touch server.js') // $ touch server.js
});
}
]
}
I tried most of the solution provided above. I believe the best one is to use nodemon-webpack-plugin .
It is very simple to use i.e. just add
const NodemonPlugin = require('nodemon-webpack-plugin')
to webpack file with
new NodemonPlugin() as your plugin.
Below are the scripts to use it:
"scripts": {
"watch:webpack-build-dev": "webpack --watch --mode development",
"clean-db": "rm -rf ./db && mkdir -p ./db",
"local-dev": "npm run clean-db && npm run watch:webpack-build-dev"
...
}
After this you can simply run npm run local-dev.
Adding a module to development is usually not as bad as adding to a production one. And mostly you will be using it for the development anyway.
This also doesn't require any additional package like nodemon or npm-run-all etc.
Also nodemon-webpack-plugin only works in watch mode.

How to define a gulp task that initiates watchify and gulp-stylus?

I am trying to create a composite gulp task which runs 2 separate watch tasks at the same time:
gulp.task('watch-css', watchCssTask); // uses gulp-stylus
gulp.task('watch-js', watchJsTask); // uses watchify (browserify)
What is the correct way to achieve the following with gulp?
gulp.task('watch', watchCssAndJsTask);
For instance, with vanilla npm tasks I would just do this:
"scripts": {
"watch-css": ...
"watch-js": ...
"watch": "npm run watch-css && npm run watch-js",
}
The following seems to work:
gulp.task('watch', [ 'watch-css', 'watch-js' ]);

How to deploy node that uses Gulp to heroku

I'm using gulp and also gulp plugins like gulp-minify-css, gulp-uglify etc (that listed as npm dependencies for my application).
Also I don't commit npm_modules folder and public folder, where all generated files are. And I can't figure out how to build my app (I have gulp build command) after deploy and setup my server (it's already looking for public folder).
It seems me a bad idea to commit before upload. Maybe there are some gentle decisions... Any thoughts?
Forked from: How to deploy node app that uses grunt to heroku
I was able to get this to work by adding this into my "package.json" file:
"scripts": {
"start": "node app",
"postinstall": "gulp default"
}
The postinstall script is run after the build pack. Check this for more information. The only annoying thing is that all of your dependencies have to live under "dependencies" instead of having separate "devDependencies"
I didn't need to do anything else with buildpacks or configuration. This seems like the simplest way to do it.
I wrote about the process I used here
You can do it!
There were a few key measures that helped me along the way:
heroku config:set NODE_ENV=production - to set your environment to 'production'
heroku config:set BUILDPACK_URL=https://github.com/krry/heroku-buildpack-nodejs-gulp-bower - to enable a customised Heroku buildpack. I incorporated elements of a few to make one that worked for me.
A gulp task entitled heroku:production that performs the build tasks that need to happen on the heroku server when NODE_ENV===production. Here's mine:
var gulp = require('gulp')
var runSeq = require('run-sequence')
gulp.task('heroku:production', function(){
runSeq('clean', 'build', 'minify')
})
clean, build, and minify are, of course separate gulp tasks that do the magic gulpage
If your application lives in /app.js, either:
(A) make a Procfile in the project root that contains only: web: node app.js, or
(B) add a start script to your package.json:
"name": "gulp-node-app-name",
"version": "10.0.4",
"scripts": {
"start": "node app.js"
},
And like #Zero21xxx says, put your gulp modules in your normal dependencies list in package.json, not in the devDependencies, which get overlooked by the buildpack, which runs npm install --production
The easiest way I found was:
Setup gulp on package.json scripts area:
"scripts": {
"build": "gulp",
"start": "node app.js"
}
Heroku will run build before starting the app.
Include gulp on dependencies instead of devDevependencies, otherwise Heroku won't be able to find it.
There is more relevant info about it on Heroku Dev Center: Best Practices for Node.js Development
How to deploy to Heroku (or Azure) with git-push
// gulpfile.js
var gulp = require('gulp');
var del = require('del');
var push = require('git-push');
var argv = require('minimist')(process.argv.slice(2));
gulp.task('clean', del.bind(null, ['build/*', '!build/.git'], {dot: true}));
gulp.task('build', ['clean'], function() {
// TODO: Build website from source files into the `./build` folder
});
gulp.task('deploy', function(cb) {
var remote = argv.production ?
{name: 'production', url: 'https://github.com/<org>/site.com', branch: 'gh-pages'},
{name: 'test', url: 'https://github.com/<org>/test.site.com', branch: 'gh-pages'};
push('./build', remote, cb);
});
Then
$ gulp build --release
$ gulp deploy --production
See also
https://github.com/koistya/git-push
https://github.com/kriasoft/react-starter-kit (tools/deploy.js)
There's a specific startup script that Heroku provides;
"scripts": {
"start": "nodemon app.js",
"heroku-postbuild": "gulp"
}
note that in your gulpfile.js (gulpfile.babel.js if you es6-ifed your gulp build process), you should have a task name default which will be automatically run after the dependencies are installed via Heroku.
https://devcenter.heroku.com/articles/nodejs-support#heroku-specific-build-steps
Heroku finds that there is a gulpfile in your project and expects there to be a heroku:production task (in the gulpfile). So all you need to do is register a task that matches that name:
gulp.task("heroku:production", function(){
console.log('hello'); // the task does not need to do anything.
});
This is enough for heroku to not reject your app.
I had to take a slightly different to get this working because I'm using browsersync:
package.json
"scripts": {
"start": "gulp serve"
}
gulp.js
gulp.task('serve', function() {
browserSync({
server: {
baseDir: './'
},
port: process.env.PORT || 5000
});
gulp.watch(['*.html', 'css/*.css', 'js/*.js', 'views/*.html', 'template/*.html', './*.html'], {cwd: 'app'}, reload);
});
Setting the port to be environment port is important to prevent error when deploying in Heroku. I did not need to set a postinstall script.
It's possible to piggyback any command you want over the top of npm install. Much like the linked question in your post, you can add an install directive in scripts within package.json that will run after all the node deps have been installed that does the build.
Your main issue will be sorting out the correct relative paths for everything.
{
...
scripts:{
install: "YOUR GULP BUILD COMMAND"
}
...
}

Resources