-
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
[RFC] Rendering in Next.js (SSR, Pre-rendering, CSR, SPA) #7355
Comments
yay for more granular tradeoffs! |
+1 for "mixed case", the app shell pattern is very common for us. |
I found this after discussing an issue on Spectrum about Auth. If the app has centralised its page auth (Or other data centric logic) into the _app.js file this breaks things quite badly. It should also check for |
Can this work while using Apollo client (and other components that pull data)? |
I think it is not the good approach. For now, yes you can know if a page requires data or not. But tomorrow with Suspense it will not be possible to know it before rendering it. |
@glenarama if we check for a @PullJosh Yes and no, if you want SSR for components that are fetching data then you'll need to make sure of including a |
@neoziro You're right, suspense will change things but it's not yet out, this is just the initial implementation. |
Is there any chance to extract the NextJS compiler into its own |
I like the sound of this. I wonder if there's any solution, though it would probably require additions to the api, would allow me to still have a getInitialProps, but it would be invoked on the client when exported and things would otherwise behave the same as Ssr. Perhaps I could define path globs in next config to declare whats static? I imagine I can write once and choose how to deliver it separately. A use case might be shipping a static site to humans and server rendered site to robots. |
@lfades the problem is that it is not possible to implement with Suspense. Except saying « we support Suspense, yes but please tell us that this page has no request » and it breaks all the flexibility of Suspense. I am just saying that including this kind of change could (in future) become a breaking change when you will have to remove it. It is just a « be careful » message. |
I don't follow the reasoning - if you have a custom _app.js with a Personally I don't like this proposal (or the implementation) it adds a lot of dangerous edge cases to data caching which could introduce security issues down the road. |
Note that if _app.js has a custom getInitialProps method we'll opt-out of this new behavior. Also note that this is the first iteration on the problem. We're going to incrementally add more.
Instead of saying "introduce security issues down the road" please give concrete
First of all the Next.js compiler is not a webpack plugin, and it can't be one, as it does far more than just handle webpack and it could work without webpack. Besides that you'd end up with a (most likely) worse implementation of just a fraction of the features Next.js has. Re: Suspense. As said on twitter it's definitely possible. Can't share what I've been working on right now but already have a proof of concept. |
Glad to hear about the _app.js opt out. Regarding my security concern - I've walked through the concept in more detail and am less concerned. I do have some hooks based data in components - but I guess they should really be in getInitialProps so docs can cover this. |
This is not completely implemented yet but #7293 is a start (the getInitialProps part). |
I love the additional granularity in this proposal - it's a really elegant way to improve the so-called Documents to Applications Continuum. There will still be, from how I understand it, a gap in this proposal concerning routing for static pages in that you'll still need to define your redirects. To take your example above of a client-side rendered application, which, with this RFP could be a page in a larger project, you'll need two things beyond triggering the static build.
The way I've solved this is to create a single file called something like
module.exports = [
{ externalURL: `/customers/:customerId/order/:orderId`, staticPage: `/order` },
{ externalURL: `/customers/:customerId`, staticPage: `/customer` },
{ externalURL: `/customers`, staticPage: `/customers` }
]
...
// This allows the app to respond to the dynamic routes like `/posts/{postId}` and is the
// Next.js equivalent of the redirects in serve.json file. See scripts/build-serve-config.js
routes.forEach(route => {
server.get(route.externalURL, (req, res) =>
app.render(req, res, route.staticPage, req.params)
)
})
...
const fs = require(`fs`)
const path = require(`path`)
const redirects = require(`../redirects`)
const OUTPUT_PATH = path.join(__dirname, `../out`)
const FILE_NAME = `serve.json`
const config = {
renderSingle: true,
trailingSlash: true,
rewrites: redirects.map(redirect => ({
source: redirect.externalURL,
destination: redirect.staticPage
}))
}
fs.writeFile(
path.join(OUTPUT_PATH, FILE_NAME),
JSON.stringify(config, null, 2),
err => {
if (err) { throw err }
console.log(`Generated: ${OUTPUT_PATH} ${FILE_NAME}`)
}
) What I like about this RFP is that each page (which is sometimes a separate team) defines more of its own behavior. To take this concept further each page could define its own routing too. The problem is that most routing uses wildcards, and isn't flat which means route order matters. You can see in the example below how this would fall on its face if the class Order extends Component {
static routes = [
`/customers/:customerId/order/:orderId`
`/customers/:customerId/order`
]
render () {
return (
<p>I'm a customer invoice</p>
)
}
} Maybe Express router composition can be a source of inspiration. Another option, which is out of scope for this RFP, is to define Next.js routing with a separate config. I'm not sure what the best option is here. |
Now, I use |
I'd also be interested in prerendering dynamic routes, if that's feasable // /pages/[dynamic]/some-page.jsx
export const config = {
prerenderedRouteParams: {
dynamic: [ 'value1', 'value2' ]
}
}
export default function SomePage ({ data }) {
return (
<div>{data}</div>
)
};
SomePage.getInitialProps = async ({ query }) {
const data = await fs.readFile(`../data/${query.dynamic}.txt`)
return { data };
}; Where the page would be prerendered twice, once for each of the values Edit: What I'm mainly looking for is a way to 'bake' translations in my localized application. I'd just like a way to inline i18n messages into my bundles instead of having to serve or include some sort of |
Going to close this RFC as it was landed in Next.js 9: nextjs.org/blog/next-9. There's a follow-up RFC coming for dynamic rendering. |
This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you. |
Next.js currently has 2 modes of rendering:
next export
These modes work fine if your application only has pages of a certain type. For example zeit.co/docs is completely static. However more often than not your application is not binary, and requirements for static rendering change over time.
For example, zeit.co has a blog with static content, marketing pages, a dashboard and more. In the current model, zeit.co would be deployed with the serverless target and every page becomes a serverless function, including the blog and marketing pages that can actually be generated at build time.
Furthermore we've seen a common pattern where you'd want the dashboard to be an appshell type application that only shows the header and a loading spinner in the pre-rendered response, then after hydrating the page the data is fetched and rendered to make the application feel faster. This is generally referred to as a client-side rendered application.
Since Next.js is in control of the compilation pipeline we can decide at build time if a page will always get the same result by inferring if the page has data requirements. If it doesn't have data requirements we'll automatically render the page as a static HTML file.
When this proposal is implemented you'll be able to choose between pre-rendering and dynamic rendering on the page level.
Goals
API
This proposal doesn't need any API changes, it's mostly related to changing the semantics and internals of Next.js to export HTML in certain cases during
next build
.Initially, we will cover the case where
getInitialProps
is not defined. Meaning that if a page doesn't havegetInitialProps
it is automatically exported as HTML.This is always going to render the same, so during build, we export it to an HTML file.
We might also need to detect router usage, but we won't cover that in the initial implementation as it's not as common. In this case you probably don't want to do dynamic rendering.
On the Now side of things
@now/next
will be updated to upload the.html
files generated by the build.The text was updated successfully, but these errors were encountered: