DEV Community

Cover image for The Ultimate `npm run dev`
@lukeocodes πŸ•ΉπŸ‘¨β€πŸ’»
@lukeocodes πŸ•ΉπŸ‘¨β€πŸ’»

Posted on • Updated on

The Ultimate `npm run dev`

GitHub logo lukeocodes / express-nodemon-ngrok-starter

Express Nodemon and Ngrok - The Ultimate `npm run dev`

The Ultimate npm run dev

This is a starter app for Express.js.

The src/devApp.js runs your src/app.js using Nodemon as a module, starting Ngrok when the app is run, gracefully stopping Ngrok when the app is closed.

How Can I Use This?

src/app.js is just a standard hello-world/app.js from the Express.js site. You probably just need to start as you normally would, editing src/app.js as you build your app.

Clone this repository.

git clone https://github.com/lukeocodes/express-nodemon-ngrok-starter.git
Enter fullscreen mode Exit fullscreen mode

Install the dependencies.

npm install
Enter fullscreen mode Exit fullscreen mode

Production Mode

Nodemon, Ngrok and Dotenv are all devDependencies and only required inside src/devApp.js, so in production mode none of these libraries which are great for development are installed or required by the app.

Start the app without these modules.

npm start
Enter fullscreen mode Exit fullscreen mode

Development Mode

Start development mode with the Nodemon, Ngrok, and Dotenv modules.

npm run dev
Enter fullscreen mode Exit fullscreen mode

What Else?

You could use Livereload to…

Express.js

Start with the Express Hello World, by running these commands from an empty directory. First, initialise NPM.

npm init -y
Enter fullscreen mode Exit fullscreen mode

Now, install Express.

npm install express
Enter fullscreen mode Exit fullscreen mode

Add this code to an app.js file.

// app.js
const express = require('express')
const app = express()
const port = process.env.PORT || 3000

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
Enter fullscreen mode Exit fullscreen mode

Start it and check it out at localhost:3000.

node app.js
Enter fullscreen mode Exit fullscreen mode

Or, if you like, add a script to your package.json.

    "scripts": {
+     "start": "node app.js"
    },
Enter fullscreen mode Exit fullscreen mode

To run it like so:

npm start
Enter fullscreen mode Exit fullscreen mode

And, we're done! (Just kidding).

Ngrok

Now, you want to launch Ngrok so you can share your Hello World with THE world.

npm install ngrok -g
ngrok http 3000
Enter fullscreen mode Exit fullscreen mode

Start it and check it out at https://your-ngrok-hash.ngrok.io.

Awesome! (this isn't it, bare with me until the end).

Nodemon

Now, if you've ever worked on a React.js or Vue.js project and gone back to a normal Node.js project without Webpack, you've probably wanted to be able to reboot your app automatically whenever you make changes.

For which, you've probably stumbled on Nodemon for that. Install it as a devDependency.

npm install nodemon --save-dev
Enter fullscreen mode Exit fullscreen mode

A quick update to your package.json file and you can run your app with Nodemon.

    "scripts": {
+     "dev": "nodemon app.js",
      "start": "node app.js"
    },
Enter fullscreen mode Exit fullscreen mode

Now, you can run it with Nodemon like this:

npm run dev
Enter fullscreen mode Exit fullscreen mode

BUT, WHAT IF?

But, what if you can pop all these into your app itself? Yeh, you read that correctly! :exploding_head_emoji:

Firstly, create a devApp.js file.

Inside that file, add this example code from Nodemon, to run it as a module.

// devApp.js
const nodemon = require('nodemon')

nodemon({
  script: 'app.js',
  ext: 'js'
})

nodemon.on('start', async () => {
  console.log('app.js just started')
}).on('quit', async () => {
  console.log('killing app.js')
})
Enter fullscreen mode Exit fullscreen mode

Nextly, install Ngrok as a devDependency.

npm install ngrok --save-dev
Enter fullscreen mode Exit fullscreen mode

Now, modify the devApp.js file and add this code.

  // devApp.js
  const nodemon = require('nodemon')
+ const ngrok = require('ngrok')
+ const port = process.env.PORT || 3000

  nodemon({
    script: 'app.js',
    ext: 'js'
  })

+ let url = null

  nodemon.on('start', async () => {
-   console.log('app.js just started')
+   if (!url) {
+     url = await ngrok.connect({ port: port })
+     console.log(`Server now available at ${url}`)
+   }
  }).on('quit', async () => {
-   console.log('killing app.js')
+   await ngrok.kill()
  })
Enter fullscreen mode Exit fullscreen mode

Lastly, change your package.json up a little bit!

    "scripts": {
-     "dev": "nodemon app.js",
+     "dev": "node devApp.js",
      "start": "node app.js"
    },
Enter fullscreen mode Exit fullscreen mode

Now, when you start your server, your local URL and public URL are now output in the console and when you update your code, the node app is refreshed (but you keep your ngrok URL!)

Local URL and Remote URL output when the app starts and nodemon refreshes code automatically when it is changed

Top comments (4)

Collapse
 
pavelloz profile image
PaweΕ‚ Kowalski

I would add livereload to all that :)

Collapse
 
lukeocodes profile image
@lukeocodes πŸ•ΉπŸ‘¨β€πŸ’»

Ohhh I was building an API at the time so I hadn't considered this. Great idea!

Collapse
 
chathula profile image
Chathula Sampath

What abou use a package like npm-run-all

npmjs.com/package/npm-run-all

Collapse
 
lukeocodes profile image
@lukeocodes πŸ•ΉπŸ‘¨β€πŸ’» • Edited

I personally use concurrently, but all are great. Either npm-run-all or concurrently run their processes side-by-side but AFAIK decoupled.

I wanted this to gracefully terminate the Ngrok session when closing node. In concurrently you can use --kill-others-on-fail but that doesn't feel very graceful :)