Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add serverless example hosted on AWS Lambda #4609

Closed
wants to merge 4 commits into from

Conversation

priyankpat
Copy link

I was able to get next.js working with serverless as requested by #4482.
This example uses with-react-i18next as a scenario where the express server is not initialized right away.

@timneutkens
Copy link
Member

Can we use hello-world as a base? 🤔 To not make things overly complex.

@priyankpat
Copy link
Author

@timneutkens Updated example with simple hello-world.

Copy link
Member

@timneutkens timneutkens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the i18n code can be removed then

Copy link
Author

@priyankpat priyankpat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove i18n code from the example and updated README instructions.


const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app.prepare() is missing here.

functions:
nextJsRootApp:
handler: lambda.handler
events:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can merge nextJsRootApp and nextJsAnyApp events - just change the events to this:

    events:
     - http: ANY {proxy+}
+    - http: ANY /

service: nextjs-aws-serverless

package:
exclude:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add yarn.lock as well.

"plugins": [
"transform-decorators-legacy"
]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove space before }


provider:
name: aws
runtime: nodejs6.10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should change this to Node 8.10 (better performance & cost less)

@dihmeetree
Copy link

I'm assuming we'll be waiting for #4496 in order for this to work, right? :D

@Skaronator
Copy link
Contributor

It works without #4496 like any other node.js server with next. (Just not as fast as with #4496)

@dihmeetree
Copy link

@Skaronator I tried to test this out.. however it didn't work? After I deployed the application and went to the site.. and tried to click the link.. it gave a "Forbidden" message? Any ideas on that?

@Skaronator
Copy link
Contributor

Skaronator commented Jul 1, 2018

Check out this repo: https://github.com/mitchellhuang/future

You need these files: lambda.js, next.config.js and server.js + serverless config

@dihmeetree
Copy link

@Skaronator Is the domain with the api gateway required? :)

@Skaronator
Copy link
Contributor

Yes you need API Gateway which trigger Lambda. You can either use your own domain or use the AWS Gateway URL.

@Skaronator
Copy link
Contributor

CloudFront is not required. (I think it doesn't even work since it is just a CDN)

Looks like you're trying to deploy mitchellhuang/future but I've never done that. Only copyed the relevant parts out of it.

@dihmeetree
Copy link

@Skaronator idk still couldn't get it working even after putting your stuff in.. the index page works fine..but after I click a link to go to a new route it just says Forbidden. I guess i'll just wait until an official example is released.

@@ -0,0 +1,31 @@
{
"name": "react-i18next-nextjs-example",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should update the name field without i18n-next

@skriems
Copy link

skriems commented Jul 26, 2018

I think I've found the culprit here @PR1YANKPAT3L . If you open up your browsers dev tools you'll notice that scripts fail to load from <url>/_next/... and the reason for that is, that the provider.stage defined in the serverless.yml file gets appended to the URL. So basically you need to use an assetPrefix here.
Since this is unique to the Lambda environment you can use an env var in your serverless.yml and have your app.setAssetPrefix in server.js based on that env var.

Note that this is not needed if you would use a custom domain via serverless-domain-manager. I'm looking into that now.

I've deployed the material-ui nextjs example to Lambda in this repo
https://github.com/skriems/next-material

Best

@dihmeetree
Copy link

dihmeetree commented Jul 27, 2018

@skriems Your repo worked great for me!

Note: To get the deployment working through Cloudfront and a custom domain, I needed to remove the following from the server.js file:

if (process.env.LAMBDA) {
  // `assetPrefix` needs to match `serverless.yml:provider.stage
  let assetPrefix = dev ? '/dev' : '/prod'
  app.setAssetPrefix(assetPrefix)
}

When setting up Cloudfront I made the Origin Domain Name the path to the function and the Origin Path either /prod or /dev.

My working version here: https://sls.vgo2x.com :)

@skriems
Copy link

skriems commented Jul 28, 2018

@lolcoolkat That looks cool :)

I've updated the repo now to utilizes serverless-domain-manager for optionally using a custom domain. I had to do amendments on the server.js as well:

  server.get('*', (req, res) => {
    if (process.env.LAMBDA) {
      let host = req.headers.host;
      let assetPrefix = 'https://' + host;
      if (host.indexOf('amazonaws.com') != -1) {
        // needs to match the stages defined in `serverless.yml`
        let stage = dev ? '/dev' : '/prod'
        assetPrefix += stage;
      }
      app.setAssetPrefix(assetPrefix);
    }
    handle(req, res)}
  );

This obviously depends on having setup a domain and certificate (which imho should be mandatory nowadays so I hardcoded it here).

So only if the app is deployed on Lambda it should set an assetPrefix. Otherwise it brakes running locally. By default this can simply be the protocol and the request.headers.host. Only if you directly invoke the function from its Lambda URL, we still need to append the stage.

Now, thinking this further in case of the custom domain we should also be appending the basePath actually from the serverless.yml. I needed to specify basePath: '' there, so that the lib create a mapping from the domains root / to our deployed stage. But one might prefer to mapp /v1 to our stage like for instance we're deploying a v1 API or so.

I think I'm only updating my docs in this regard and explain the hurdles I experienced. Note that you could simply opt-out of using a custom domain by specifying enabled: false in the serverless.yml

@PR1YANKPAT3L and/or @Skaronator I could either make the necessary commits here or create a new PR if you guys have no objections.

@Skaronator
Copy link
Contributor

Weird... I'm using a custom domain via serverless-domain-manager (not a subdomain) and everything just works without modifying the assetPrefix.

@skriems
Copy link

skriems commented Jul 28, 2018

How odd. I just tried again without adding a prefix and with basePath: '' but I get those 403's. Is it related to the region and/or endpointType ?

@Skaronator
Copy link
Contributor

Ah the execute-api.eu-central-1.amazonaws.com endpoint has a /prod which mess up the whole path while the custom domain doesn't have it. Thanks to this mapping:
image

@skriems
Copy link

skriems commented Jul 28, 2018

exactly that's the problem. Any opinion on how this should be included/documented in the example?

@Skaronator
Copy link
Contributor

Skaronator commented Jul 28, 2018

It might be better to use Lambda@Edge instead of Lambda with APIGateway but Serverless doesn't support it yet due to a bug in CloudFormation.

serverless/serverless#4796

@Enalmada
Copy link
Contributor

Enalmada commented Sep 4, 2018

@skriems next-material serverless example worked great. If the requested changes in this pull are not being acted on promptly, can we just get that into the next.js examples section?

Also, I see a few serverless example request tickets imply that there might be good reason for a next.js example to handle the "scenario where the express server is not initialized right away." Can any of the serverless hackers in this thread confirm if a serverless example based on "with-react-i18next" would be different in any fundamental way than one based on "hello-world"? Does the next-material example use an express server not initialized right away?

It would also be considerate to provide a cautionary note for new users that serverless may not be the optimal choice for consumer facing products due to the unavoidable latency it adds. A traditional deployment can consistently return sub 50ms response time but AWS Lambda, the same example varies wildly between 150ms and 2.5s when "warm".

@romainquellec
Copy link
Contributor

between 150ms and 2.5s when "warm".

If you have 2.5s of response time, you did something wrong with your lambda. Waiting for #4496 though !

@romainquellec
Copy link
Contributor

also, why serverless-http over aws-serverless-express ?

@Enalmada
Copy link
Contributor

Enalmada commented Sep 20, 2018

If you have 2.5s of response time, you did something wrong with your lambda.

@romainquellec It is certainly possible and testing was extremely unscientific. So everyone can do their own testing I will elaborate slightly: If I refresh my serverless next.js example quickly (once a second) the responses definitely tend to average closer to 150ms. I think this indicates my lambda was fine. If I wait a few minutes between each refresh (small enough interval that containers should be warm, trying to replicate my actual site traffic pattern), responses vary wildly between 150ms and 2.5s. I assume amazon knows my traffic pattern is insignificant and not giving me a "keep warm" status. YMMV and this is just food for thought as I was just messing around. (There does seem to be some evidence that warm up just reduces chances of cold start)

@timneutkens
Copy link
Member

I'm going to close this PR in favor of the work we're doing towards making Next.js output single-route lambdas.

@lock lock bot locked as resolved and limited conversation to collaborators Dec 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants