Tutorial: Using Loopback 4 Together With Next.js on one Heroku instance

Dmitry Yakimov
BeadList
Published in
5 min readDec 7, 2018

--

Loopback 4 makes a great backend for an application. And Next.js is amazing for client side. And they work together very well.

When you run them on the separate servers you might won’t have any problems with deploy at all. But if you want to save some resources, and run them together on one server instance, it could get a little tricky. Today I’m going to show you how to do it. And we’ll use Heroku for deployment.

All together, we would need to follow these steps:

  1. Setting up Loopback 4;
  2. Setting up Next.js;
  3. Setting up the common server;
  4. Deploy on Heroku.

Our Loopback 4 server is going to be under the ./server path, and Next.js application would go to./client . So the project tree would look like this:

.
├── client
│ ├── index.js
│ ├── package.json
│ ├── pages
│ ├── server.js
│ └── ...
└── server
├── index.js
├── index.ts
├── package.json
├── src
├── tsconfig.json
└── ...

1. Setting Up Loopback 4

In order to install and Loopback 4, let’s just follow the official instructions from here.

We install @loopback/cli globally:

$ npm i -g @loopback/cli

And we create a new project:

$ lb4 app? Project name: frogfish-server
? Project description: app
? Project root directory: server
? Application class name: FrogfishServerApplication
? Select features to enable in the project
◉ Enable tslint
◉ Enable prettier
◉ Enable mocha
◉ Enable loopbackBuild
◉ Enable vscode
◉ Enable repositories
◉ Enable services

Then we start the server and check that everything is good:

$ cd server$ npm start

When we go to http://localhost:3000/ping we can see our application is running properly, and we see the following response:

{
greeting: "Hello from LoopBack",
date: "2018-12-06T18:42:31.950Z",
url: "/ping",
headers: {...}
}

Alright, looking good. Now let’s set up Next.js.

2. Setting Up Next.js

Installation

Same as Loopback 4, let’s just follow official instructions from here.

Outside of server dir we run this to init the project under the ./client dir:

$ mkdir client$ cd client$ npm initpackage name: (client) frogfish-client
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)

Then we install the dependencies:

$ npm install --save next react react-dom

And add scripts to our package.json:

{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}

Ok. Then we create a sample page on./client/pages/index.js :

export default () => <div>Welcome to next.js!</div>

Let’s check if everything is working:

$ npm run dev

And we go to http://localhost:3000/ and see the sample page. Looking good!

Custom Client Server

In order to make Next.js to run with Loopback 4, we would need a custom server for it. Let’s make one. And let’s make it wrap it into module, to make it reusable.

We create a file ./client/index.js with this contents:

// ./client/index.jsconst express = require('express');
const next = require('next');
module.exports = async function({
beforeNext = () => {},
dir = '.' } = {}
) {
const dev = process.env.NODE_ENV === 'development';
const port = process.env.PORT || 3000;
const app = next({ dev, dir });
const handle = app.getRequestHandler();
const server = express();
await app.prepare();
await beforeNext(server);
server.use(express.static(`${dir}/static`));
server.get('*', (req, res) => handle(req, res));
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on port: ${port}`);
});
};

As you can see we have created a server module, which can be executed from outside of the client. It has two arguments:

  • beforeNext — the function, which would called before Next.js handles the request. That’s where we are going to initiate our Loopback 4 app;
  • dir — the dir under which the Next.js project runs, by default it’s going to be . , but when we run it from outside it’s going to become ./client .

And then we create a runner under ./client/server.js :

// ./client/server.jsconst server = require('./');
server();

We change our package.json dev script like this:

{
"dev": "NODE_ENV=development node server.js",
}

And we check that we didn’t break anything:

$ npm run dev

Ok, so far so good. Let’s glue our server with client.

3. Set Up the Common Server

Server script

So now we have two directories in our project. One is ./client , which contains our Next.js project, and then we have ./server for Loopback 4 app. And in the root dir we are going to make our common server, which would serve both.

Let’s create a file with named./index.js with this contents:

// ./index.jsconst client = require('./client');
const serverApp = require('./server/dist/');
client({
dir: 'client',
beforeNext: async server => {
const app = new serverApp.FrogfishServerApplication();
await app.boot();
server.use('/api', app.requestHandler);
},
});

That’s how we can use both apps together under one server!

Configuring package.json

Now we are going to create common package.json in a root dir, where we just merging dependencies of both apps:

{
"name": "frogfish",
"version": "1.0.0",
"description": "",
"main": "index.js",
"author": "",
"license": "ISC",
"dependencies": {
"@loopback/boot": "^1.0.6",
"@loopback/context": "^1.2.0",
"@loopback/core": "^1.1.1",
"@loopback/openapi-v3": "^1.1.3",
"@loopback/repository": "^1.0.6",
"@loopback/rest": "^1.4.0",
"@loopback/rest-explorer": "^1.1.2",
"@loopback/service-proxy": "^1.0.3",
"express": "^4.16.4",
"next": "^7.0.2",
"npm-run-all": "^4.1.5",
"react": "^16.6.3",
"react-dom": "^16.6.3"
},
"devDependencies": {
"@loopback/build": "^1.0.1",
"@loopback/testlab": "^1.0.1",
"@types/node": "^10.11.2"
}
}

Then we install the dependencies:

$ npm install

Now let’s add scripts there for managing our app, for that we would need npm-run-all for running our scripts in parallel, we install it via:

$ npm install npm-run-all --save

And we add the following scripts:

{
"scripts": {
"dev": "NODE_ENV=development node .",
"build": "npm-run-all --parallel build:server build:client",
"build:client": "next build client",
"build:server": "lb-tsc es2017 --outDir server/dist -p server",
"start": "node .",
"heroku-postbuild": "npm run build"
}
}

There is some magic going on with TypeScript compilation. Apart from that, everything else is easy. Also notice heroku-postbuild script. It’s going to run after our application got deployed on heroku.

Fixing tsconfig.json

Now le’ts do the last thing here, let’s adjust ./server/tsconfig.json . In order to make TypeScript compilation to work, we have to fix its extends key:

{
"extends": "../node_modules/@loopback/build/config/tsconfig.common.json"
}

We’ve just added an extra dot before /node_modules .

4. Deploy on Heroku

Deploy on heroku is straightforward. We create an app there with a name frogfish . Then we deploy:

git remote add origin https://git.heroku.com/frogfish.git
git push

And we add HOST variable to our configuration:

heroku config:set HOST=frogfish.herokuapp.com

Now the app is up and running! Yahoo

As a last step, let’s change ./client/pages/index.js to make use of our new api:

import React, { Component } from 'react';export default class IndexPage extends Component {
state = {
response: {},
};
async componentDidMount() {
const response = await (await fetch('/api/ping')).json();
this.setState({ response });
}
render() {
return (
<div>
<p>Welcome to next.js!</p>
<p>{this.state.response.greeting}</p>
<p>
<pre>
{JSON.stringify(this.state.response, undefined, 2)}
</pre>
</p>
</div>
);
}
}

Then we deploy, and go to https://frogfish.herokuapp.com/ and yay, our Loopback 4 + Next.js app is up and running. We can see greetings both from both sides. Thank you very much.

Loopback 4 working together with Next.js

You can checkout the resulting source code on Github here.

I wish you some joyful coding sessions and easy integrations. See you next time!█

--

--

Dmitry Yakimov
BeadList

Web-consultant, Tech-enthusiast. Working on BeadList App: beadlist.com