Lessons Learned Building in Next.js

Part 3: Testing, Deploying, and Running

Brandon Richey
8 min readMay 24, 2017

Last Updated: 5/9/2017

Oh man, this crab. This crab, everyone. This crab.

Previous Post in this Series

Current Versions:

  • React: v15.4
  • next.js: v2.3

Where We Left Off

We have everything we need to build our app, but now we actually need to make this app a little more production-ready! As I went through the process of making my app a little more battle-tested and ready-to-use, here were some of the things I needed to learn and set up/configure to bring my app to the next level!

Testing with Jest/Enzyme

I didn’t hit too many snags with setting up my testing environment. You’ll need to deviate a little bit from the standard testing methods used by create-react-app, however, and you’ll have to install a few extra packages to make everything work. First of all, you’ll want to install babel-preset-es2015, enzyme, jest, and react-addons-test-utils.

Directory Structure: __tests__ at root level

For tests to run correctly, you’ll need to place a __tests__ directory in the root of your next.js project. This should then mimic the directory structure of the rest of your app, so your __tests__ directory might look something like this for a basic next.js app:

- (root)/
- __tests__/
- pages/
- index.test.js
- components/
- hello.test.js
- pages/
- index.js
- components/
- hello.js

If you try to place a __tests__ inside of pages/ or something similar to that structure, you might end up getting a lot of errors when you try to build your app via next build. You’ll also need to change your .babelrc file for things to work correctly:

{
"env": {
"development": {
"presets": ["next/babel"]
},
"production": {
"presets": ["next/babel"]
},
"test": {
"presets": ["es2015", "next/babel"]
}
}
}

Basically, for the test environment, we need to let babel know that it should be using the es2015 presets as well as everything next provides for the test to work (such as support for JSX). Finally, you’ll want to modify the package.json file to provide a few extra helper commands you can run from your command line in your next.js project.

package.json changes

That being said, all of this won’t just work without also modifying your package.json file to expose a couple of scripts. Add the following to the scripts section of your package.json file for your project:

"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"

Now you can have your test watcher waiting for any changes to files with npm run test:watch (or yarn test:watch, or run them as a one-time deal with npm test (or yarn test)!

Deployment

Okay, you’ve finished your awesome project (great job!) and you’re ready to ship this thing into production! But wait, how precisely do you go about doing that? It will certainly be a little more complicated than just deploying a single html file and single js file, but the good news is that if you’re using something like nginx, it should actually be a pretty simple endeavor!

Building on Production

Let’s start with building on our production box. You’ll need a few things installed on the server (I’m assuming this is not something like a docker environment, although that’s entirely possible too): node.js and npm. You should be able to upload your finished product onto your server where you’re planning on running this (or a build server that is running the same deployment target).

From there, you’ll SSH into that box and begin the build process with npm install in the directory of your project. Assuming that all went well, you can then run npm run build or yarn build to start building the production-ized version of your site. Finally, when that’s all done, you can run npm start or yarn start to begin running your app!

Setting up environment configs with dotenv

That being said, you’ll probably want to configure the app a little more than just the default port setup. Maybe there’s a backend API you need to communicate with and that might change in the future and you’d like to be able to change it without redeploying your entire app. I added the dotenv package to allow me to create a .env file that I keep on my production build server (separate from my dev .env file, so I specifically ignore that file with .gitignore). This way can I set things like PORT=1234 and API_HOST=https://api.whatever.com and change them quickly and easily without requiring a full redeploy!

Adding dotenv and configuring

dotenv by itself won’t just work without a little bit of work on your end, something I figured out through some good ol’ fashioned trial and error (and I mean a lot of error) work! First, install the dotenv package (simple enough). Next, you’re going to open up server.js, and add the following:

require('dotenv').config();

And finally, if you haven’t already customized your webpack configuration through next.config.js, you’ll need to create that file. From there, add the following:

const webpack = require('webpack');require('dotenv').config();module.exports = {
webpack: config => {
config.plugins.push(
new webpack.DefinePlugin({
'process.env.API_HOST': JSON.stringify(process.env.API_HOST),
'process.env.PORT': JSON.stringify(process.env.PORT)
})
);
return config;
}
};

What this will do is allow Webpack to detect any calls to process.env.WHATEVER (depends on what values you expose in the above config file), and replace them with the appropriate values! This will be enough to allow you to expose process.env.WHATEVER in your client files or services or what have you and make sure they’re functioning the same in dev mode, production mode, server mode, client mode, whatever!

Running the app

Finally, you’re there. Your app is built, it’s configured, everything about it is (more or less) perfect! You will just need to get things running first.

Configuring SSL

One thing you’ll want to do is set up your SSL certs. You can either do this the old-fashioned way by buying certs or you can use Let’s Encrypt! Now, this is pretty far outside the scope of this particular post, but I’ll try to revisit this topic for both next.js and Elixir/Phoenix, since I ran into issues setting up both of those!

Configuring nginx

Finally, you’ll want to configure nginx to act as a reverse proxy to your next.js app! Now, I will preface this by saying this is just one possible way to get up and running out of about a million. I found this to be the easiest to get up and running, but you may have another pipeline or server or whatever that works better for you or your company. Again, you do you! For the most part, after I had my app up and running, all I had to do was configure nginx, restart the server, and voila, my app was accessible to the public! Here is a sample app (complete with a very basic sample SSL config using Let’s Encrypt). Just replace mygreat.site with whatever it is your site is and wherever the encryption keys live for your Let’s Encrypt configuration, as well as the port you’re going to use under the location / section:

server {
listen 80;
listen [::]:80;
server_name mygreat.site;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/letsencrypt/live/mygreat.site-0001/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mygreat.site-0001/privkey.pem;
server_name mygreat.site;location / {
proxy_pass http://localhost:1234;
}
client_max_body_size 5m;
}

Final Thoughts

So here we are at the end! We have an app up and running and everything is perfect, right? Overall, I think this was a worthwhile project to pursue, and I didn’t find it to be much more difficult than starting an app with create-react-app. I find the two to be pretty similar to each other in approach, but again, it’s important to note that it’s not just a 1:1 copy and paste between the two. You’ll have to modify your project structure and layout in some ways. I think create-react-app is a -very- slightly better start for a developer just because it gives you more things baked into the defaults (for example, everything related to testing is already there and ready to go, which is very nice).

What you get here, though, is a slightly more opinionated approach to things like project layout and I’ve found that it forced me into better design habits through making the alternatives just plain too hard to do or not worthwhile to pursue in the first place! I can’t just shoehorn Redux state all over the place because next.js won’t let you do that without jumping through substantial, possibly-on-fire hoops!

The server-side/client-side thing can run you into a couple of weird issues where a page works when you navigate to it, but the moment you hit refresh the page breaks (or vice-versa!), which can be very difficult to debug at times. In addition, I found the error handling and stacktraces to be more useful in general in my create-react-app project vs. my next.js project.

Next, the performance! On a fast machine with a fast network connection, I found the general impressions of speed and load times to be roughly equivalent. I also had this app powered by an Elixir/Phoenix API, which meant that the full load time for multiple items getting populated from the API was still well under 1s from start to DOMContentLoaded (generally anywhere from 500ms to 1s). That’s nothing to scoff at for a relatively small and underpowered Linode VPS!

In terms of the time frame, I went from a mostly complete create-react-app to a fully-functioning next.js app in the span of about two days, and a good chunk of that was just figuring things out (and playing Mario Kart in between). Overall, it was a fun project and I think I made the right call bringing next.js into my app. My project is smaller, better organized, and faster, and all of those are wins in my book. I wouldn’t say anything I learned was too heavily next.js-specific either, so that other fear of mine was soundly squashed by the end of the project!

Check out my new books!

Hey everyone! If you liked what you read here and want to learn more with me, check out my new book on using the latest version of Create React App:

This covers everything you need to know to become proficient using Create React App v2 to become a better, more productive front-end developer, and really dive deep into the details of Create React App all while building a new React project from scratch!

And, of course, my Phoenix Web Development book is also still available if you want to learn more about Elixir web development:

I’m really excited to finally be bringing this project to the world! It’s written in the same style as my other tutorials where we will be building the scaffold of a full project from start to finish, even covering some of the trickier topics like file uploads, Twitter/Google OAuth logins, and APIs!

--

--