menu
Channels
Team

Suggestions: NextJS Serverless Build

January 31, 2019 at 7:46pm

Suggestions: NextJS Serverless Build

January 31, 2019 at 7:46pm (Edited 7 months ago)

NextJS canary has a build option which turns every page(route) into a Lambda ready function.

So, when you run the 'next build' process, it splits built pages out into '.next/serverless/pages/page.js' as an example. Then from the lambda routes you can import those builds and serve that route as a lambda function.

const next = require('../../front/.next/serverless/pages/index.js')
const server = new http.Server((req, res) => next.render)
exports.handler = async function http(req,res) {
console.log("This is res", res)
return next.render(req,res)
}

The issue I'm running into is that the "function signature" required by the function returned by the build needs the http response object. The above code snippet gives me an error of 'res.end is not a function' which makes sense because the res object provided by Begin looks like this

{ succeed: [Function: succeed], fail: [Function: fail] }

Is there any way to get access to the response object or any suggestions on how one might use this feature to build SSR NextJS with Begin?

Relevant section of NextJS docs here: https://github.com/zeit/next.js/#serverless-deployment


January 31, 2019 at 7:48pm

hi @agstover ! sorry for the trouble. that isn't begin's function sig…just the default lambda function signature. we do have a request-like object as the first param. the second param is called context…and a third optional param for a lambda is a node style errback. anyhow! none of that matters, I'm 💯% certain we can coerce this thing into giving you a string. would you mind zipping the package giving you trouble and sending it to me? I tried hunting the next code but its pretty big and there's over 362 references to render. my email: brian@begin.com

  • reply
  • like

Sent! From the main directory you should be able to just run npm run build and then npm run start

  • reply
  • like

super interested in the solution

  • reply
  • like

I kinda fell into a hole reading next source there lol

  • reply
  • like

(I understand y'all took some of the troubleshooting here offline and it's working, will let you report back in your own time!)

Just a heads up: without additional context, that require('../../front/.next/serverless/pages/index.js') concerns me. If that's being required out of a Begin Function dir (i.e. src/http/get-index) it will only work locally – root dependencies are basically devdeps in this kind of project.

If so, you may want to consider src/shared (which allows you to require from @architect/shared).

  • reply
  • like

So I moved the entire front directory into shared.

Now require is require('@architect/shared/front/.next/serverless/pages/index.js')

The issue I'm running into is that there is a NextJS function called send-html.js that ties off the request/response cycle with res.end(html). It doesn't return the html value. I'm not sure how to mock this behavior. The only way I can get the built HTML is saving the result in an out of scope variable.

exports.handler = async function http(req) { req.url = req.path let body let res = { end(html){ console.log("HTML!!!!!!", html) body = html }, getHeader: () => {}, setHeader: () => {} } const result = await next.render(req,res) console.log("THIS IS RESULT", result) return {type:'text/html; charset=utf8', body} }

This seems very bad. Also, the html makes it to the browser, but it brings along MIME Type errors

Edited
  • reply
  • like
  • reply
  • like

yikes! looks like it wants to load a bunch of javascript files relative to your root

  • reply
  • like

ok, but that is progress

  • reply
  • like

so we have a couple of options here

  • reply
  • like

you could create get /_next/:part/:file and get /_next/:part/:other/:file

  • reply
  • like

and then you have to somehow get those files serving from those routes

  • reply
  • like

=/

  • reply
  • like

not super ideal and getting quite hacky

  • reply
  • like

architect, and by extension begin, is really url based for a good reasons (lambda functions coldstart is pretty vicious when you get over 5mb)

  • reply
  • like

so we have one function per route

  • reply
  • like

there is a feature inbound I'm working on to catch all requests to get-index lambda if they aren't defined by other lambdas

  • reply
  • like

which will make this significantly easier

  • reply
  • like

then you'll only need get / and you can put these build files in that lambda and, with a little logic, it'll serve the right ones when it needs them

  • reply
  • like

that feature is at least a week out from begin.com tho

  • reply
  • like

Ok, well I see what's happening in that the html is requesting build files from a relative path. Will take me a minute to wrap my head around what you're saying here, but let me sit with it a bit and look over the Next docs to see if I can make any progress. Thank you for all your help!

  • reply
  • like

np np, certain we can get this working (and stoked to make it WAY easier asap!)

like-fill
1
  • reply
  • like