DEV Community

loading...
Cover image for A crash course on serverless-side rendering with React.js, Next.js and AWS Lambda

A crash course on serverless-side rendering with React.js, Next.js and AWS Lambda

Adnan Rahić on December 03, 2018

Disclaimer: Zeet is sponsoring this blogpost for the next month. I tried it out the other day. It's like serverless but for running entire back...
pic
Editor guide
Collapse
dallashuggins profile image
Dallas Huggins

Great tutorial - thank you! I finished the tutorial and successfully deployed, but am getting errors when navigating to the site. When navigating to https://[unique id].execute-api.us-east-1.amazonaws.com/dev/, I get the message {"message": "Internal server error"}. One nuance is that I removed the customDomain section, as I was hoping to use the AWS endpoint.

One thing I did when testing, is I added "dev": "next" to the scripts object in the package.json, so when I run npm run dev, I get the correct information displaying at localhost:3000, localhost:3000/dogs, etc.

Also, I added the code below to the server.js file, and when I navigate to https://[unique id].execute-api.us-east-1.amazonaws.com/dev/test, I get the 'Hello World!' message displaying, as expected:

server.get('/test', (req, res) => {
res.send('Hello World!');
});

The full server.js file is below. The server.get function with the res.send works, but the server.get functions with the app.render always throw an error.

const express = require('express');
const path = require('path');
const dev = process.env.NODE_ENV !== 'production';
const next = require('next');
const pathMatch = require('path-match');
const app = next({ dev });
const handle = app.getRequestHandler();
const { parse } = require('url');

const server = express();
const route = pathMatch();
server.use('/next', express.static(path.join(_dirname, '.next')));
server.get('/test', (req, res) => {
res.send('Hello World!');
});
server.get('/', (req, res) => {
app.render(req, res, '/')
});
server.get('/dogs', (req, res) => {
app.render(req, res, '/dogs')
});
server.get('/dogs/:breed', (req, res) => {
const params = route('/dogs/:breed')(parse(req.url).pathname)
return app.render(req, res, '/dogs/_breed', params)
});
server.get('*', (req, res) => handle(req, res))

module.exports = server;

Any insight would be greatly appreciated! Let me know if I can provide any additional information. Sorry if I'm doing anything real obvious, as I am completely new to Next.js and still fairly beginner with AWS.

Collapse
drumline18 profile image
drumline18

I would add the same exact comment. I get Internal server error. If I try to add the /test get route, it works fine. If I try next locally it displays fine on localhost:3000. I myself has not even removed the customDomain section as I have a domain on Route 53 for that.

I have just tried copying the repo provided in the article and deploying it to my domain. Still the same Internal server error.

Collapse
hzburki profile image
Haseeb Burki

I get the same error when deploying the app to AWS.

Error:
{
message: "Internal server error"
}

The routes work fine locally, except the dynamic _breed route which results in a 404.

I've tried everything myself and also cloned the git repo as is to test. Both give the exact same result mentioned above. I have a custom domain linked via "sls create_domain" command.

Collapse
its_ku profile image
Mo City Donald

Same here. I'm getting the internal server error and the issue has to do with calling app.render. Further research leads me to believe that the problem stems from not calling app.prepare before configuring the server.

Collapse
shood profile image
s-hood

for local development and testing:
npm run dev will run it has a next app without serverless (only pages are available, no serverless functionality written in server.js). You need to use serverless-offline github.com/dherault/serverless-off...

Collapse
qm3ster profile image
Mihail Malo

Hi, this raised a couple a questions with me:

  1. What benefit does serverless provide in this scenario? What are the alternatives(aws cli?terraform?idk.)?
  2. Why is your article on nuxt mentioned only in the list at the end, although this is almost exactly the same thing again?
Collapse
adnanrahic profile image
Adnan Rahić Author

Hey, glad to answer.

  1. The Serverless Framework makes it easy to deploy resources and create a domain. You can use whatever tool you like, AWS SAM, the AWS CLI, CloudFormation, Terraform, etc. It's totally up to you what you want to use. Using the Serverless Framework lowers the barrier to entry for devs who are not familiar to the services and tools AWS provides. It's just easier to get started with.
  2. It's mentioned at the end solely because Vue and React are two totally different frameworks with different ecosystems. I didn't want to create confusion. Vue devs can follow the Nuxt guide, while React devs can follow this one. :)

Hope this answers your questions. Feel free to let me know if you have any more. :D

Collapse
garyburgmann profile image
Gary Burgmann

I have stumbled on a few of your tutorials Adnan and they are all awesome. I actually read through all of this before realising it was you (I got into Serverless when I read your Express, Mongo + Serverless tutorial on hackernoon). NextJS is great and I am stoked that it is just as easy to deploy to Lambda. Thank you!

Collapse
adnanrahic profile image
Adnan Rahić Author

Hey Gary! Wow, thanks for the kind words. I'm glad I can help the community understand serverless architectures. Stay tuned for more tutorials. :)

Collapse
arswaw profile image
Arswaw

This was the error I received after I ran 'npm run deploy' for the first time.

I have a domain name that ends in .info

Could that be the cause?


Error: Could not set up basepath mapping. Try running sls create_domain first.

Error: Error: 'react-ssr.happyweather.info' could not be found in API Gateway.

NotFoundException: Invalid domain name identifier specified
Collapse
sebas profile image
Sebastian Mantilla

Hi,

Once I deploy this, I'm able to load the front page, but all the next resources (*.js) come back as 403, any idea why?

Thanks for your help,

Collapse
clarsen profile image
Case Larsen

FWIW, you're probably seeing issue from not deploying with custom domain and needing to have the stage in the path to access the resource, e.g.
https://XXXXX.execute-api.us-east-1.amazonaws.com/production/_next/static/YYYYY/pages/index.js is needed but https://XXXXX.execute-api.us-east-1.amazonaws.com/_next/static/YYYYY/pages/index.js is what the express response actually renders.

This explains some of issue and attempts to make it work github.com/dougmoscrop/serverless-...

as well as this: github.com/zeit/next.js/issues/6447

Collapse
adnanrahic profile image
Adnan Rahić Author

Can you try cloning the repo and deploying it? If that works, there has to be a strange issue somewhere in your code. Compare your project to the cloned repo. Hopefully, that'll help you out. :)

Collapse
billypurvis profile image
Billy Purvis

Hi - this doesn't work.

The only route that does work (without defining a specific route definition in server.js) is index.js.

Any other pages under /pages fails to render with a 404, although, they do work fine in local environment.

Perhaps there's some other settings that aren't listed in this article?

Collapse
hzburki profile image
Haseeb Burki

It doesn't work when I clone it from the repo either. The only thing I've changed were the values in secret.json

On local routes work fine, except for the dynamic "_breed" route. It results in 404 Not Found.

On deploying to AWS all routes result in message: "Internal server error" ... you can check it out at ecom.ideamappers.com

Collapse
drumline18 profile image
drumline18

That does not work. It gives and internal server error as soon as you try using app.render.

Collapse
joachimgoo profile image
joachimgoo

Hi,

I have exactly the same issue.
Where you able to solve it?

Thanks

Collapse
arswaw profile image
Arswaw

I saw that Next.js 8 was released after you published this article. It has a section about how serverless is now supported. Should I do anything differently because of this?

Collapse
ivanoats profile image
Ivan Storck

Have you done any performance testing on this setup? I would be interested to know some numbers like TTFB and others.

Collapse
adnanrahic profile image
Adnan Rahić Author

I haven't actually. I'd be stoked to know the performance too. Once I find the time, I'll surely check it out. If you get around to doing it yourself, please let me know! :D

Collapse
squillace91 profile image
João Vitor Squillace Teixeira

Hey, this is great thanks! For those following the tutorial and copying and pasting the code, there is a typo in index.js.. it is missing ). FYI

Collapse
adnanrahic profile image
Adnan Rahić Author

Oh wow, nice catch! Thanks for that. I've gone in and fixed the typo. I'm glad you like the tutorial. :)

Collapse
joshglazer profile image
Josh Glazer

Is it possible to display images from the static folder once the site is deployed? I added an image for a logo to the static folder and am displaying it in the header component. It shows while I'm developing on localhost, but when I deploy to AWS it shows as a broken image.

Here's my code:
github.com/joshglazer/freetimeupda...

Collapse
joshglazer profile image
Josh Glazer

I figured this out myself. In case anyone's curious, you can fix this by adding the following line of code to your server.js file.

server.use('/static', express.static('static'))

Collapse
bitttttten profile image
bitten

So you keep the secrets file locally? What if you are on a team and want to deploy this through CI/CD? Would you handle that on there?

Collapse
adnanrahic profile image
Adnan Rahić Author

You use AWS KMS. Here's a nice Serverless plugin. :)

nordcloud / serverless-kms-secrets

🔑🔐☁️ Serverless plugin to encrypt variables with KMS

Serverless KMS Secrets

A Serverless Plugin for the Serverless Framework which helps with encrypting service secrets using the AWS Key Management Service (KMS)

Introduction

This plugins does the following:

  • It provides commands to encrypt and decrypt secrets with KMS

Installation and configuration

In your service root, run:

npm install --save-dev serverless-kms-secrets

Add the plugin to serverless.yml:

plugins
  - serverless-kms-secrets

Configure the plugin into the custom block in serverless.yml. For example:

custom
  serverless-kms-secrets
    secretsFile: kms-secrets.${opt:stage, self:provider.stage}.${opt:region, self:provider.region}.yml (optional)
  kmsSecrets: ${file(kms-secrets.${opt:stage, self:provider.stage}.${opt:region, self:provider.region}.yml)}

By default, the plugin creates secrets to the file kms-secrets.[stage].[region].yml. This can be overriden with the secretsFile parameter in the serverless-kms-secrets configuration.

Add Decrypt permissions to your lambda function with e.g. this block in IamRoleStatements:

    - Effect: Allow
      Action:
      - KMS:Decrypt
      Resource: ${self:custom.kmsSecrets.keyArn} 

Usage

Creating KMS Key

Create a KMS key in AWS IAM service, under Encryption keys. Collect…

Collapse
grath90 profile image
Cole

Considering lambda cold starts; what does this do for initial load times?