-
Notifications
You must be signed in to change notification settings - Fork 27k
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
Serverless Next.js #5927
Serverless Next.js #5927
Conversation
This is amazing 🙏 |
This is awesome. I would love an example of how to deploy dynamic next.js to netlify with function support also - (https://www.netlify.com/docs/functions/). |
Does this mean client side |
@jesstelford No, this PR changes nothing to the client compilation, only the server compilation, meaning that the serverless output can be ran with just the single file. |
🎉 Thanks for clarifying! |
I'll try to migrate my existing Next.js app running on Not that the production doesn't work well, but the local development is a real pain (express, next, serverless-offline, hmr, all those don't just play well with my current setup) Kinda worried about environment variables, as I rely on them though. And I use custom stages as well, I remember Next wasn't so friendly about that, by forcing either production or development. |
Extends on #5927, instead of `.default` we'll expose `.render` which is semantically more correct / mirrors the naming of the custom server API. I've updated the spec in #5927 to reflect this change. (copied from #5927): ```js const http = require('http') const page = require('./.next/serverless/about.js') const server = new http.Server((req, res) => page.render(req, res)) server.listen(3000, () => console.log('Listening on http://localhost:3000')) ```
@adamszeptycki I think the But a example how to deploy to lambda with serverless would be well welcome (including s3+cloudfront for assets) |
Does the |
@jakewies Yes you can.
package.json
|
@timneutkens noticed we don't follow the same build directory structure as here is the build dir structure for
vs serverless target:
having that pages dir under a build dir can be useful for a variety of use cases. One such is that it allows serving different versions of the codebase at the same time for testing purposes. thoughts? |
@Skaronator I think @jakewies meant passing configuration down to the runtime environment, like next/config does. I've got a temporary solution using
and then access in your code like always |
@maggo For the record, I believe that's what https://github.com/mrsteele/dotenv-webpack is about. I'm also struggling with ENV variables. The very particular way Next.js handles them makes it unfriendly to work with, from my experience. For instance, one of my devs created a SENTRY_DSN env variable today, and stored its value in the const serverRuntimeConfig = {};
const publicRuntimeConfig = {
GROUP_NAME: process.env.GROUP_NAME,
NODE_ENV: process.env.NODE_ENV, // XXX Used in utils/env
SENTRY_DSN: process.env.SENTRY_DSN
};
module.exports = {
serverRuntimeConfig,
publicRuntimeConfig,
}; I really don't like it. First, the design is broken because loading Also, this particular env variable isn't a secret, it's the same in localhost, staging, production and therefore I don't care about git tracking it, it just makes things easier and isn't a security issue. So I don't even see the point storing it in a .env file. (but that's another issue I guess) Finally, do you see what's happening here? I gotta define a ENV var in a .env file, which is then loaded by next.config.js, injected by next.runtimeConfig.js, then use the next/config getConfig method to retrieve it, to finally be able to use it. Why? Because I need it on the frontend part of the app, and there is no other way to load env vars for the frontend. If I would only need it on the backend, I could just reference it as we usually do in a node app, using See how overcomplicated this all got? Not transparent, fails silently, overcomplicated, multiple references and configuration for a single ENV var, and a hell of a brainfuck to debug when it doesn't work because it's a needle in a haystack issue. So, I tried hard to find another way and didn't fine anything better within a hour of work. But in the process of finding for a better solution, I found https://github.com/mrsteele/dotenv-webpack and I believe it would just solve my issues. It fixes the issue completely differently, by replacing the references to any ENV var and hardcoding them in the bundled version. It's not something I usually like, but it's most likely a better way to handle ENV vars than relying on the publicRuntimeConfig and alike, and is definitely more straight-forward, IMHO. So, if you have some feedback regarding its usage, I'm interested. You seem to consider this as a temporary solution, while I'm thinking migrating towards it because I haven't found any better solution really. |
@Vadorequest yeah I didn't like the I meant temporary as in my own local configuration and I'm hoping that we'll see something like this in next soon. Maybe we should set up an RFC for this. |
@timneutkens How would you pass any parameters from the server to the functions? I am able to get the actual values from the request, but nextjs never sees them. I tried to do that using the page.render(req, res, '/item', {something: '123', id:'someID'}) In my view code, I can then grab both 'something' and 'id' from function Item({ query }) {...}
export default Item |
It should be handled on the proxy level. As documented This is to prevent many of the common pitfalls people currently have when using the custom server API. |
Where would this proxy need to be? Wouldnt it still be before the page.render call? My understanding is that I need to wrap the functions in a serverless handler. For example: exports.handler = async (event) =>
event.path.indexOf('_next') > -1 ? handleStaticAssets(event) : await handleRoute(event);
Could anyone else please shed some light on how to pass parameters. Or is this impossible with the current implementation? |
I'm not entirely sure what you're trying to do based on the code, but it seems like you're creating 1 lambda to handle multiple routes instead of having a separate lambda for each route.
This will then be passed onto the render function (including query). However the wrapper should only be in charge of converting the incoming payload to a Node.js http req/res compatible format, in case of AWS Lambda it'll look like this: #6070 (comment) |
This does not change existing behavior.
building to serverless is completely opt-in.
target: 'serverless'
innext.config.js
next build --lambdas
(was only available on next@canary so far)This implements the concept of build targets. Currently there will be 2 build targets:
The serverless target will output a single file per
page
in thepages
directory:pages/index.js
=>.next/serverless/index.js
pages/about.js
=>.next/serverless/about.js
So what is inside
.next/serverless/about.js
? All the code needed to render that specific page. It has the Node.jshttp.Server
request handler function signature:So how do you use it? Generally you don't want to use the below example, but for illustration purposes it's shown how the handler is called using a plain
http.Server
:Generally you'll upload this handler function to an external service like Now v2, the
@now/next
builder will be updated to reflect these changes. This means that it'll be no longer neccesary for@now/next
to do some of the guesswork in creating smaller handler functions. As Next.js will output the smallest possible serverless handler function automatically.The function has 0 dependencies so no node_modules are required to run it, and is generally very small. 45Kb zipped is the baseline, but I'm sure we can make it even smaller in the future.
One important thing to note is that the function won't try to load
next.config.js
, sopublicRuntimeConfig
/serverRuntimeConfig
are not supported. Reasons are outlined here: #5846So to summarize:
req
andres
coming from Node.jstarget: 'serverless'
innext.config.js
TODO:
import()
into the function file, so that no extra files have to be uploaded.assetPrefix
at build time for serverless targetnext.config.js
property fortarget
Need discussion:
publicRuntimeConfig
/serverRuntimeConfig
as they're runtime values. I think we should support build-time env var replacement with webpack.DefinePlugin or similar.