9. Serving the full-stack app in development

Looking at the scripts section of our package.json file, we're given the serve command by Vue CLI 3. This command calls the Vue CLI 3 service binary, which boots a pre-configured Webpack dev server that serves our client app.

But in this project we're going to need two Node-based servers; the Webpack dev server for the client, which will run on port 8080, and also a server for the Express API we're about to build, which we can put on a different, like 8070.

Rename serve script

With that in mind, let's remove the ambiguity about what the serve script does and rename it to the more specific serve:client.

Running the Node server

You'll see in the source code we have a boilerplate for our API server in this file server/index.js.


const express = require("express");
const app = express();

const port = 8070;
app.listen(port, () => {
  console.log(`Listening on port ${port}`);

In the next video we'll address what that code does. But for now, just be aware that we can run our server from the terminal with the simple command:

$ node server

The reason that works without having to specify the file index.js is that that file is considered the default if you just provide the directory name in a Node CLI command.

Anyway, all the server does currently is listens on the port 8070 and console logs a message to tell us so. It doesn't actually do anything else yet.

Adding server script

So let's kill the server by pressing Ctrl + C and add that command as a script in package.json so we can easily start our server.


"scripts": {
  "serve:server": "node server"

Let's quickly try that now and confirm it works.

$ npm run serve:server


If we make a change to our server code, like modifying the console log message, we'll have to manually restart the server for the change to take effect, which is a bit annoying.

The Webpack dev server, as you probably know, will rebuild the client package anytime the code in the client folder changes.

Let's now install and setup the Nodemon package which we can configure to watch the server folder for changes and trigger a restart.

Firstly, we'll need to install the latest version:

$ npm i -D nodemon

To use it, let's update the start script to be:


"script": {
  "serve:server": "nodemon server"

Now, if we make a small change to the code we'll see if the server restarts automatically.

[change a character in the console log]

For me that doesn't work, I believe because I'm using a mounted drive with Vagrant, so in my case, I'm going to add the "-L" flag which is the slightly less efficient legacy watch mode.

"script": {
  "serve:server": "nodemon server -L"

With that done, I'll restart the server, and making changes to the index file, you'll see will restart the server.

concurrently NPM package

So now we have our two separate development servers set up; the Webpack dev server for the client app, and Nodemon for the server app.

How can we now run them simultaneously?

Since these development servers both run as foreground tasks, we'll need to pipe one command into the other like this:

$ npm run serve:client | npm run serve:server

This does work, but it makes a mess of console outputs. Also if one process fails, the other will still keep running and you may not even notice.

So a better way is to use the concurrently NPM package. Let's install it and save it as a development dependency:

$ npm i -D concurrently

npm run serve

With that installed, let's create a new package.json script called "serve" and get this to call concurrently.

To use concurrently, you just have to pass any commands as a series of arguments to the binary.

The arguments need to be in double quotes, so we'll have to escape those, and in fact we can use a wildcard to call both of our serve scripts with one argument.

We'll also add the -k switch which will kill both processes if either one dies.

"script": {
  "serve": "concurrently \"npm:serve:*\" -k",

So let's try it. It's not perfect, but you'll see that at least the terminal output is now delinated by a header prefixed to each line which makes it easier to see what's going on.

$ npm run serve

Let's jump over to the browser now and test localhost:8080 to see the client dev server working, and localhost:8070 to see the backend dev server working, as this error message confirms.