Allow Next.js to become fully hybrid by providing methods to do both static generation and server-side rendering on a per-page basis.
getStaticProps
- Opt-in to static generation (SSG) at next build
time.getServerSideProps
- Opt-in to server-side rendering (SSR) which renders on-demand.getStaticPaths
- Return list of parameters for dynamic routes to do static generation (SSG)This RFC exclusively discusses API additions. All new functionality is completely backwards compatible and can be incrementally adopted. This RFC introduces no deprecations.
When building websites or web applications you generally have to choose between 2 strategies: Static generation (SSG) or server-side rendering (SSR).
Next.js instead lets you build hybrid applications that allow you to choose per-page which strategy is used. Starting with Next.js 9, pages without getInitialProps
get statically optimized and output as .html
files upon next build
.
However, you might want to do data fetching while generating static pages for your specific use case.
For example, to statically generate marketing pages from a CMS or a blog section of the site.
Using getInitialProps
would opt you into SSR in that case.
Next.js currently has a next export
command, that makes the application fully SSG, losing the hybrid nature of Next.js.
If you use next export
with getInitialProps
there is another problem that surfaces. getInitialProps
is called at build time (which is great), but then when you use next/link
to move between pages getInitialProps
is called client-side, instead of using the next export
result.
This also means the data source (CMS / API endpoint) is called directly on client-side transitions, if your data source is down, client-side transitions break while moving between pages.
We've collaborated with heavy users of SSG and next export
in Next.js like HashiCorp (thanks @jescalan) and extensively investigated the right constraints for introducing two new data fetching methods: getStaticProps
and getServerSideProps
. But also a way to provide parameters to statically generate static pages for dynamic routes: getStaticPaths
(replacement for exportPathMap
that is per-page).
These new methods have many advantages over the getInitialProps
model as there is a clear distinction between what will become SSG vs SSR.
getStaticProps
marks the page to be statically generated at build time (when running next build
)getStaticPaths
allows for returning a list of parameters to generate at build time for dynamic routesgetServerSideProps
marks the page to be server-side rendered on every request and is the most similar to the current getInitialProps
behavior when using a server.Separating these methods also allows us to provide the correct context object that can be typed using TypeScript. When you opt for a specific rendering strategy you get the correct values, currently with getInitialProps
you have to guess what is available on SSG vs SSR when using TypeScript.
Furthermore, by making these methods explicit, it'll allow us to document the different trade-offs more clearly.
Note that all these methods are top-level on the page component file and can't be nested, similar to getInitialProps
.
getStaticProps
Using getStaticProps
means the page will be rendered statically at build time (SSG).
This new method will allow you to do data fetching for a page that will be statically generated into a .html
file at next build
time.
Next.js will also automatically generate a JSON file that holds the result of getStaticProps
at next build
time. This is being used for client-side routing.
When client-side routing through next/link
or next/router
, Next.js will fetch this JSON file to get the props needed to render the page client-side.
Properties are returned under a props
key so that other options can be introduced in the future.
// pages/index.js
// getStaticProps is only called server-side
// In theory you could do direct database queries
export async function getStaticProps(context) {
return {
// Unlike `getInitialProps` the props are returned under a props key
// The reasoning behind this is that there's potentially more options
// that will be introduced in the future.
// For example to allow you to further control behavior per-page.
props: {}
};
}
The context
will contain:
params
- The parameters when on a dynamic route.getStaticPaths
This is an extension on getStaticProps
usage for dynamic routes.
getStaticPaths
replaces the need for having a exportPathMap
and works per-page.
Since you might want to statically generate a list of urls that have a dynamic parameter, like in the example below a slug
. Next.js will provide a getStaticPaths
method that allows for returning a list of urls. Since it's a async
method you can also fetch that list from a data source like your CMS.
// pages/blog/[slug].js
// `getStaticProps` gets a `params` object holding the dynamic parameters
// For `/blog/hello-world` it would look like `{ slug: 'hello-world }`
export async function getStaticProps({ params }) {
return {
props: {}
};
}
// `getStaticPaths` allows the user to return a list of parameters to
// render to HTML at build time.
export async function getStaticPaths() {
return {
paths: [
// This renders /blog/hello-world to HTML at build time
{ params: { slug: "hello-world" } }
]
};
}
In many cases you might not want to pre-render every possible route in your application at build-time (for example if you have millions of products). For this reason Next.js will automatically generate a fallback
page that is a render of the page without data (so that a loading state can be shown) for when the page hasn’t been generated yet.
The exact behavior of serving will be:
In case you want paths that weren’t generated at build time to result in a 404 that is also possible by returning fallback: false
from getStaticPaths
// `getStaticPaths` allows the user to return a list of parameters to
// render to HTML at build time.
export async function getStaticPaths() {
return {
// Opt-out of the described fallback behavior
fallback: false,
paths: [
// This renders /blog/hello-world to HTML at build time
{ params: { slug: "hello-world" } }
]
};
}
getServerSideProps
When using getServerSideProps
, the page is not statically generated (SSG) and instead renders on-demand on every request to the server (SSR).
Next.js will also automatically expose an API endpoint that returns the result of calling getServerSideProps
. This is being used for client-side routing.
When client-side routing through next/link
or next/router
, Next.js will fetch this exposed API endpoint to get the JSON data that is turned into the props needed to render the page client-side.
This method is the most similar to the current getInitialProps
, with the main difference being getServerSideProps
is always executed server-side instead of in the browser. Either on server-side rendering or the API fetch when client-side routing.
Similarly to getStaticProps
the properties are returned under a props
key.
// pages/index.js
// getServerSideProps is only called server-side
// In theory you could do direct database queries
export async function getServerSideProps(context) {
return {
// Unlike `getInitialProps` the props are returned under a props key
// The reasoning behind this is that there's potentially more options
// that will be introduced in the future.
// For example to allow you to further control behavior per-page.
props: {}
};
}
The context
will contain:
params
- The parameters on a dynamic routereq
- The HTTP request objectres
- The HTTP response objectquery
- The query string (not entirely sure about this one, but probably needed)Authored by @timneutkens, @Timer, @ijjk, @lfades. Collaborated with @rauchg, @jescalan and others 🚀
export async function getStaticProps(context) { return { // Unlike `getInitialProps` the props are returned under a props key // The reasoning behind this is that there's potentially more options // that will be introduced in the future. // For example to allow you to further control behavior per-page. props: {} }; }
I'm interested in seeing what circumstance we would need to return additional data other than what can be contained within props
. I found the in-line explanation "to further control behavior per-page" a bit vague.
Looks very interesting! Would his be a replacement for getInitialProps
or along side? For eg, for our use case, the data fetching API is a public service. So on client side navigation, we expect the client to directly call the API layer, whereas on SSR the server calls it. Going forward, would this use case continue to be solved by the prior method?
I'm interested in seeing what circumstance we would need to return additional data other than what can be contained within
props
. I found the in-line explanation "to further control behavior per-page" a bit vague.
It's more so about future proofing the method so that it allows us to extend it later on if needed.
Looks very interesting! Would his be a replacement for
getInitialProps
or along side? For eg, for our use case, the data fetching API is a public service. So on client side navigation, we expect the client to directly call the API layer, whereas on SSR the server calls it. Going forward, would this use case continue to be solved by the prior method?
In general that behavior has some downsides, for example waterfall fetches that could be slow from certain areas around the world. The getServerProps
approach allows for caching the response more efficiently.
This looks really interesting! Cool idea!
I have concerns about deployment though...
Let's imagine I'm hosting on Now.
For the first deployment, it's obvious that the whole applications gets built on deployment.
Then, I change some content in CMS and am looking to trigger rebuild of SSG pages only, but the application code has not changed.
Immediately alarm goes off, that in this case if I trigger the build, there are two possible solutions:
1) Nothing gets rebuilt, as everything is cached - no code has changed and blabla.
2) I --force
it, and now "everything" gets rebuilt, but I only required the SSG pages to be rebuilt.
_These are just hypotheses, as that depends on build systems themselves - how aware are they of Next_
This would probably affect any other hosting solution.
Next itself has a .next/cache
... how would this play around that?
@joltmode that's basically the case for every static site generator currently. .next/cache
is preserved between deployments on Now and reused. Keep in mind that you're currently probably using getInitialProps for this case with caching (potentially https://zeit.co/blog/serverless-pre-rendering), which dynamically renders in a serverless function and then caches on our CDN, this behavior is still totally fine and will continue to work if you use getServerProps
.
Really awesome, would fit nicely into how we are using Next for customer projects, and would remove some boilerplate code we copy around.
One thing to consider is the naming of getStaticProps and getServerProps, if they return a { props } and potential other options in the future, would the *Props not be confusing? Maybe getStaticConfiguration, getStaticSetup, getStaticOptions would be more generic?
@kibs the return values would always relate to how the props are handled. So the naming is fine imo.
This is simply awesome! This is solving every use case and need I've had recently or could think of while developing both private and professional web apps. You just prevented me from starting my own hybrid site generator, thanks!
I can also relate to the new methods being better than the previous getInitialProps()
and exportPathMap()
, which sounded a bit confusing to me at first when I started using Next.js and digged into SSR / SSG. The per-page approach makes more sense to me too.
Can't wait to try this out!
Just a side note : in the last example I think
getServerProps()
is missing acontext
param.
Just a side note : in the last example I think getServerProps() is missing a context param.
Fixed!
This sounds great! I just wonder from a TypeScript user perspective if having getStaticProps
, getStaticPaths
and getServerProps
as static methods on the page component (like getInitialProps
at the moment) would be easier to type/use correctly.
const Page: NextPage<Props> = (props) => ...
// Explicit types needed here
export const getStaticPaths: NextGetStaticPaths<Params> = () => ...
export const getStaticProps: NextGetStaticProps<Props, Params> = (context) => ...
export const getServerProps: NextGetServerProps<Props> = (context) => ...
export default Page
// vs.
const Page: NextPage<Props, Params> = (props) => ...
// Static method types come from NextPage<Props, Params>
Page.getStaticPaths = () => ...
Page.getStaticProps = (context) => ...
Page.getServerProps = (context) => ..
export default Page
@herrstucki the problem with that approach is that it becomes significantly harder to tree shake (read: close to impossible). Which would mean unnecessary code would be shipped to the browser.
@timneutkens good point … but would then a separate file not make even more sense? Or is something like this _reliably_ tree-shakable?
// This should all be removed in client-side code …
import {fetchQuery, queryTag} from 'big-data-fetching-lib';
const query = queryTag`...`
export const getStaticProps = async () => ({ props: await fetchQuery(query) })
// Only this should be included client-side
export default (props) => ...
@herrstucki we can reliably tree shake that, but we're also still discussing having a separate file. Personally I prefer the single file approach though.
Looks very interesting! Would his be a replacement for
getInitialProps
or along side? For eg, for our use case, the data fetching API is a public service. So on client side navigation, we expect the client to directly call the API layer, whereas on SSR the server calls it. Going forward, would this use case continue to be solved by the prior method?In general that behavior has some downsides, for example waterfall fetches that could be slow from certain areas around the world. The
getServerProps
approach allows for caching the response more efficiently.
Sure, but I'm talking about avoiding the RTT to the react server at all. Consider the case where the SSR output from the server is cached at CDN / cache server proxy. Couple that with data fetching for client navigation directly calling a different API layer (common to web / apps / all clients), means that the Next.js server layer doesn't have to be scaled up as much in a high traffic scenario.
I understand your point of waterfall fetches, but giving consumers the ability to treat the Next server as a SSR layer vs a data source would allow for much better scaling setups.
Looks very interesting! Would his be a replacement for
getInitialProps
or along side? For eg, for our use case, the data fetching API is a public service. So on client side navigation, we expect the client to directly call the API layer, whereas on SSR the server calls it. Going forward, would this use case continue to be solved by the prior method?In general that behavior has some downsides, for example waterfall fetches that could be slow from certain areas around the world. The
getServerProps
approach allows for caching the response more efficiently.Sure, but I'm talking about avoiding the RTT to the react server at all. Consider the case where the SSR output from the server is cached at CDN / cache server proxy. Couple that with data fetching for client navigation directly calling a different API layer (common to web / apps / all clients), means that the Next.js server layer doesn't have to be scaled up as much in a high traffic scenario.
I understand your point of waterfall fetches, but giving consumers the ability to treat the Next server as a SSR layer vs a data source would allow for much better scaling setups.
I think you're misunderstanding that this new behavior means you can actually cache the full results on a CDN given the CDN supports dynamic responses. This was previously not reliably possible with getInitialProps.
@timneutkens I played around with canary, trying to port some babel-plugin-preval
code to getStaticProps
. I am ran into an issue with fs
.
I am trying to read the .md files of my ./pages/blog/
directory and loop through them so I can make a blog index page with all my posts
import React from 'react';
import Link from 'next/link';
import fs from 'fs-extra';
const Index = ({ posts }) => (
<div>
Hello World. <Thing msg="hello" />
<Link href="/thing">
<a>About</a>
</Link>
{posts.map(p => (
<div key={p.title}>{p.title}</div>
))}
</div>
);
Index.getStaticProps = async () => {
const items = await fs.readdir('./pages/blog');
items.forEach(path => /* .... do some stuff ... */ )
return { props: { posts: items } };
};
export default Index;
This code leads to this error:
Module not found: Can't resolve 'fs' in '/Users/jared/Downloads/nextjs-typescript-template/node_modules/fs-extra/lib'
IIRC from Razzle, this error has to do with webpack's filesystem stubs (or lack thereof). I think I once fixed this with Razzle by adding this to the webpack config.
node: {
fs: "empty";
}
I tried this next.config.js, but it just makes the error go away. It appears though that fs
/fs-extra
doesn't actually work, or it does and perhaps paths don't (unclear to me). Any thoughts on that?
My other question, more generally, is what you imagine best practices will be for using import vs. require in getStaticProps
. If I'm not mistaken, my above snippet will attempt to import fs-extra
in React isomorphically??. Would it thus be better to change the import to an inline require like this?
js
Index.getStaticProps = async () => {
const fs = require('fs-extra'); // only require when needed at SSG
const props = await fs.readdir('./pages/blog');
return { props: { posts } };
};
I think you're misunderstanding that this new behavior means you can actually cache the full results on a CDN given the CDN supports dynamic responses. This was previously not reliably possible with getInitialProps.
Ah, I think I get what you mean. Would that mean that getServerProps
on the first SSR generation would create a unique endpoint, in a content addressable hash maybe in the URL maybe that we can then cache on the CDN? The only downside of this would be that said cache would not be shareable between non Next apps (android / ios) and Next apps. Additionally, with an external data source, the cache control directives are upstream, but here since Next would assume responsibility of serving up the data, we need APIs or props to specify those for the generated data endpoints.
@jaredpalmer I assume https://github.com/zeit/next.js/issues/9524#issuecomment-558628066 (including my concern about reliable tree-shakeability) would be resolved by having a separate file that would be compiled completely separately from client bundle code? E.g.
pages/
foo.js
foo.data.js (<- exports getStaticProps etc.)
or:
pages/
foo.js
pages-data/
foo.js (<- exports getStaticProps etc.)
@jaredpalmer tree shaking wasn't implemented yet on canary.
As always, thank you for everything y'all do. Next.js has been an absolute joy to work with, and as I've said before, just about every feature release lets us _reduce_ the size of the codebases I manage. It's amazing.
It's hard to be critical of this RFC since, as written, it is immediately useful for a LOT of applications. I do, however, want to address one line that I'm not sure I agree with:
"
getStaticPaths
replaces the need for having aexportPathMap
and works per-page."
In some applications, it is either impractical or impossible to know the routes at build time. A few examples would be:
Routes for pages like this will probably be in the form /entity-name/entity-id
and Next's dynamic routes work really really well since you can do things like router.push('/customers/[customerId]', '/customers/baer')
. There is still a catch. If you plan to serve these files statically with something like Serve, Netlify, NGINX, etc, you'll need to generate a set of redirects so that users won't get a 404 on page-refresh and, to do that, you still need exportPathMap
.
The following is copied, almost as-is, from a codebase I work on regularly:
const buildServeConfig = redirects => {
const config = {
public: `dist`,
trailingSlash: true,
rewrites: redirects
};
const outputPath = `${__dirname}/serve.json`;
fs.writeFile(outputPath, JSON.stringify(config, null, 2), err => {
if (err) {
throw err;
}
// eslint-disable-next-line no-console
console.log(`Generated: ${outputPath}`);
});
};
...
exportPathMap: function(defaultPathMap, { dev, outDir }) {
const redirects = Object.entries(defaultPathMap)
// No need to create a redirect rule for `/dirname/` or `/dirname/index.html`
.filter(([url]) => url !== `/` && url !== `/index`)
.map(([url, { page }]) => ({
// Replaces /[customerId] with /:customerId
source: url.replace(/]/g, ``).replace(/\[/g, `:`),
destination: `${page}/index.html`
}));
// By default, the routes are sorted such that a route like `/order/:orderId`
// comes before `/order/new`. Since the `:orderId` portion of `/order/:orderId`
// is a wildcard, the route `/order/new` will be a match and consider `new`
// as a value for `:orderId`. To get past this, we sort the redirects by the
// number of parameters in ascending order.
const sortedRedirects = [...redirects].sort(
(currentRedirect, nextRedirect) =>
currentRedirect.source.split(`:`).length >
nextRedirect.source.split(`:`).length
);
buildServeConfig(sortedRedirects);
return defaultPathMap;
}
I understand that this RFC does not deprecate or remove any APIs and I also recognize that it is possible to build these redirects by traversing the build directory so even if it were deprecated, I've got a nice ecape hatch. But, it doesn't quite "remove the need for getStaticPaths
."
Again, thank you for your thoughtfulness in how you run this project
Are
getStaticProps
/getStaticPaths
andgetServerProps
mutually exclusive? i.e. would it be possible to have a part prerendered and a part dynamic at the same time?
Yeah they are as one is static generation and one is server-side rendering.
This fixes one of the big things I miss from Gatsby before we migrated to Next:
We have a monolithic (100s of kbs) JSON file that we pull data from to render our pages that never changes. In Gatsby we loaded the JSON file into the GraphQL schema and queried against that, only grabbing the data that we needed to render a given page. With Next, the easiest/cleanest way we found to do this is import monolith from './monolith.json'
, which requires the user download the entire JSON file.
This RFC 100% addresses this use case and brings Next one step closer to being on-par with Gatsby in the areas Gatsby shines (obviously, Gatsby can't do runtime SSR, so I'm only talking about static buildtime renders)
@timneutkens, thank you for the RFC!
I have a use case for Next.js that I recently discussed with @rauchg.
Next.js delivers very smooth DX and some reasonable defaults. So, I'm interested in using Next.js for a client-side only rendered application, a Smart TV app.
Smart TV apps are almost classic web apps that are run by TV’s browser engine:
The thing is that the bundle is statically hosted by the TV device itself and not loaded from the server. Thus, no SSR option is possible (Node.js isn’t exposed to developers for these purposes). But the app itself is dynamic (say, Netflix).
So, we need to run an SPA that is hosted by a static web server.
As I understand opting-out of getServerProps
(or getInitialProps
) completely will help to avoid SSR. But what happens with dynamic rendering on the client? And what about routing in this case? According to this RFC the problem hasn’t been addressed yet. @timneutkens, could you, please, suggest the best way to enable client-side only rendering in Next.js? And whether it fits Next.js in the first place? Thanks!
P.S. I can create an issue for this use case if you think it's better to discuss it separately.
@grushetsky can you create a different issue. This is a completely different question from what is being discussed in the RFC 👍
@timneutkens The promise of this RFC is one of the things that got me super excited about Next! Just to clarify though, getInitialProps
would still exist too, right?
Correct @outdooricon -- getInitialProps
will remain around for the foreseeable future.
Per the RFC:
This RFC exclusively discusses API additions. All new functionality is completely backwards compatible and can be incrementally adopted. This RFC introduces no deprecations.
Great RFC, super excited for this!
I've been thinking about the getServerProps
in relation to a specific use case, putting the results in a cache. Since this gets turned into a API-endpoint and the result delivered to the component as props, is there a prescribed way of putting the result into an external cache like Redux, GraphQL-caches etc, etc client side?
If I understand getInitialProps
correctly, since it's static and async, Next has the opportunity to wait for it to complete before ever rendering the component a first time. This lets us put things into an external cache there. This won't be the case with getServerProps
since it runs on the server, and putting things in a cache in the component lifecycle seems to mean we have to have a render where the data is not available in the cache yet, even if it is available in props?
This might be intentional of course and I might be missing an approach, but I thought I'd ask if it's something that's been considered?
Edit: I guess this also applies to getStaticProps
. 😄
Maybe I've missed it somewhere, but how do we handle situations when content is cached, but it is updated in db or new blog post is created? There is need to do new build automatically? I guess so.
First of all! Great proposal, it's a massive improvement over exportPathMaps
on most people's use case. It's really appreciated. With that said, I'm struggling to understand how would we will be able to make it work with route internationalisation.
Is there any suggestions on how to handle i18n prefixed routes? My specific use case requires to build a few thousands on pages with different country-lang prefixes and urls.
/nl/brillen
/gb/glasses
/es/gafas
...
It seems that getStaticPaths
will be really helpful when the prefix for the url is well known, as in your example (using /blog/[id].js
). But how do you think a getStaticPaths
implementation will look if it needs to generate paths at root level, with both a dynamic prefix (country-lang) and a dynamic path?
@reaktivo pages/[lang]/blog/[id].js
-> in getStaticPaths
provide all urls to statically render.
@timneutkens Any idea when this will be available / testable?
In general we don't give out ETAs because we extensively test features against production apps to make sure the solution is right.
This improvements will totally make me deprecate my "not that maintained" phenomic project (react ssg that nobody uses except me). Awesome to see Next.js adding this missings parts!
I would like to clarify a doubt. Considering the use of a CMS like wordpress. As I understand it, with the getStaticPaths method I would fetch all posts and pass a list like:
export async function getStaticPaths () {
return [
// This renders / blog / hello-world to HTML at build time
{params: {slug: "hello-world"}}
];
}
The slug of each post would be used in the getStaticProps method to fetch the content.
This would happen in npm build.
My question is about new posts that will be added after the build.
Would getStaticProps method be used to fetch this new post by slug?
Will this new post have a .html file like the one in the previous build?
I love to work with next and in several projects I have this would be very good.
Nothing directly related, but the support is unable to give me an answer that matches my question.
What you suggest here could be the solution, but in the meantime, I'm unable to make nextJS to build a JAMSTACK based on webhooks changes.
if I had getInitialProps I'm going to be server-rendered.
If I don't, I'm just CDNized, but without pre-rendering isn't? And the page will be without content as long as XHR haven't returned (bye-bye SEO)
Do you have any running example with now of Jamstack with nextJS and we could do on netlify.
Thanks,
Andréas
Hey @ScreamZ - this change is, I think, what enables a fully static site to be built with nextjs. We have been able to compile out a nextjs site to static using next export
for a long time, but it would still fetch data on client-side route transitions using getInitialProps
. With the ability to use getStaticProps
, you can run client-side transitions without any additional data being fetched -- all fetched data in getStaticProps
is fetched once, at build time, and not updated on your live site unless you rebuild again. This is the classic architecture of data-driven static sites, link your data source to your host via webhook and when the data source changes, you tell the host to rebuild your site.
There are plenty of existing examples of fully static nextjs websites, and its trivial to run a nextjs site on netlify. My company's website is currently running on nextjs, and hosted by netlify, hopefully this serves as a good example.
It's very much worth noting that zeit's hosting service is also something worth being strongly considered. The pricing is quite similar, and their integration with nextjs sites is second to none - you literally don't even need to configure anything at all, you just link github and zeit's hosting will recognize that you're running nextjs and automatically configure and deploy everything.
This is not an advertisement by any means, I do not work for zeit, just a genuine endorsement. You can absolutely make it work with netlify, and I have personally for several sites as proof. But you will need to understand thoroughly how nextjs works, and you will need to make sure everything is configured correctly to get it running smoothly on netlify. If you're looking for the simplest, most foolproof hosting for a nextjs site, I would give zeit's hosting a try.
@jescalan Thank you for this great sharing 🙏🏻
I've no issue using NextJS with netlify, because you can use Publish directory
to specify the out
folder. But on zeit Now, there is no way to say, please don't use SSR but go full on static with next export
.
@ScreamZ this is sort of true, but it depends on how exactly you define a "full static" site. If you use getStaticProps
for all your pages with zeit's hosting service, what you will get is effectively equal to a static site, even if it doesn't run next export
, since all pages with getStaticProps
are built only when the site is deployed, and are served directly from the CDN after that.
The main difference is that as far as I know there isn't a way to force all pages to be static on zeit's hosting (edit: zeit recently changed it so that any site with a config that contains exportPathMap
will run a fully static site, so this is no longer true). Pages with getStaticProps
behave exactly the same as pages generated by next export
-- a single static copy of the page is served directly from the CDN on every hit. But you could also run some pages with getServerProps
or getInitialProps
and they would behave as server rendered pages. Personally I see this as a benefit -- if there's a need for a SSR route you can simply use a different data fetching method and that single route is now SSR, while all your other routes can remain static.
@jescalan Thanks,
So just need to wait to have this being implemented, in the meantime gonna use netlify for static
Is there a story around SSG configuration? Specifically we would like to use shared build artifacts but run next export
with different configurations for QA/prod. These config values would only be read in getStaticProps
. Would this use the serverRuntimeConfig
or publicRuntimeConfig
or process.env
directly?
@ScreamZ @jescalan I've landed zero-config next export
support on Now today together with @Timer (he deserves all the credits). You can do:
"build": "next build && next export"
And it'll work automatically.
Let me know how it goes 🙏
Yeah, I was the guy that asked on support and they told me this has been implemented just yet 😅 As far as I can see, you'll need to define an export map in config?
@ScreamZ no you can just add next build && next export
as shown above and it'll work.
@timneutkens If I replace getInitialProps
with getServerProps
, do I still need to add target: 'serverless'
to the config file to enable Server Pre Rendering
? Thanks.
How can we try these?
How can we try these?
I guess all these methods currently need unstable_
prefix to get recognized.
e.g unstable_getStaticProps
@timneutkens
@ScreamZ @jescalan I've landed zero-config
next export
support on Now today together with @Timer (he deserves all the credits). You can do:"build": "next build && next export"
And it'll work automatically.
Let me know how it goes 🙏
My build script is doing a bit more things but it looks like it works like a charm:
"build": "graphql codegen && next build && npm run export",
Besides, it's great! It was exactly what I was looking for 😅 (Goodbye GatsbyJS, my favorite framework is now strong as you!)
Thanks a lot for such reactivity.
I also upgraded to 9.1.6
and I surprisely saw that
I thought that thread was an RFC, it looks like it's already opened to us ahah, isn't ?
However, Typescript types are not enabled in 9.1.6.
Damn, I'm so hyped for that now! 🤣
Last questions:
getInitialProps
will be deprecated in the future? Or is it still relevant in some cases? An example?next export
can also be deprecated in favor of pages with getStaticProps
and next build
only?Thanks for that great tool 🙏🏻
If I get it, getInitialProps will be deprecated in the future? Or is it still relevant in some cases? An example?
As said in the initial RFC:
This RFC exclusively discusses API additions. All new functionality is completely backwards compatible and can be incrementally adopted. This RFC introduces no deprecations.
I thought that thread was an RFC, it looks like it's already opened to us ahah, isn't ?
It's not, we're trying it out on ZEIT applications and some of the visibility surfacing has already landed (for example the pages tree you saw).
next export can also be deprecated in favor of pages with getStaticProps and next build only?
Correct, in general you'll end up just not using next export
. It'll be kept around for backwards compat reason but in general you'll want to create a hybrid app as it gives you all the benefits of export with support for other features like API routes and opting into server-side rendering for some pages.
How can we try these?
I guess all these methods currently need
unstable_
prefix to get recognized.e.g
unstable_getStaticProps
Highly recommend not using it yet, it's experimental and can break between releases.
So I've been playing with this feature and I've observed that the JSON file containing the page data is always fetched after accessing the SSG page from another page.
Do you guys plan on any preloading optimization for the JSON file?
Perhaps preloading it when user is about to navigate to the page (i.e: user is hovering a SSG Link) or preloading just like you're preloading other js pages that are referenced from a Link component.
Loving that feataure by the way!
Do you guys plan on any preloading optimization for the JSON file?
yes.
For what it's worth, I'm all for tree-shakable exports of these funcs rather than separate files.
What's the status of this feature? What are its blockers?
@mikestopcontinues this RFC is currently being heavily tested internally by our team, and a few select partners. You can opt into its highly experimental behavior by using the unstable_
prefixes, as mentioned above! 😄
Please do not migrate production workloads to the new methods though, as we still may update the APIs in breaking ways.
Personally, I use it for the generation of static sites from 8 to 20K pages (with the possibility to have some dynamic requests on some pages). It works very well (except for the 10K files limit on Now), the only thing I find a shame is that without the getStaticPaths method, getStaticProps is called at each reload. One behavior that could be good is that the first call creates the json file and the next one uses it.
Are Incremental Builds planned? So only new / changed content is rebuild?
You can opt into its highly experimental behavior by using the
unstable_
prefixes, as mentioned above!
I'd like to test out the unstable_getServerProps
method, but it looks like it's ignored at the moment, and I'm unable to find it anywhere in the zeit/next.js
repo. Is it not implemented yet, or am I just doing it wrong?
Are Incremental Builds planned? So only new / changed content is rebuild?
The implementation was designed with incremental rebuilds in mind, but it's not supported yet (nor covered in this RFC).
Rest assured, the architecture is ready and we'll be exploring this after these features land stable.
This is why getStaticProps
is defined per-page, and not once for the entire application!
I'd like to test out the unstable_getServerProps method, but it looks like it's ignored at the moment [...]
getServerProps
is not available in preview yet, sorry!
getServerProps
is not available in preview yet, sorry!
Thanks for the heads up. I will definitely be watching this thread, because when that lands I've got a _bunch_ of code that can be replaced by renaming a single function! 😍
Please clarify, I am not 100% certain if getServerProps
/ getStaticProps
are currently available to use or not.
Based on this thread: No
But if that's the case, then I'm wondering why did my terminal allude to it when I ran next build
if they aren't available yet? Seeing the message left me with the initial working assumption that these methods were in production, and it took me a while to discover they were not. Just curious about the reasoning or if there's something I'm misunderstanding.
λ (Server) server-side renders at runtime (uses getInitialProps or getServerProps)
○ (Static) automatically rendered as static HTML (uses no initial props)
● (SSG) automatically generated as static HTML + JSON (uses getStaticProps)
(on next version 9.1.6)
Thanks
@stevenjchang they're available using the following syntax in pages/**/*.js
:
export function unstable_getStaticPaths() {} // return [{params: {...}}, ...]
export function unstable_getStaticProps({params: {...}) {} // return {props: {...}}
And I should also add, they're wonderful, though they're still a bit rough around the edges when using the dev server.
though they're still a bit rough around the edges when using the dev server.
@mikestopcontinues
Could you please elaborate on this? No one else has given us negative feedback about the dev server experience, and we'd love to get it resolved!
@Timer I really like the new api. My main issue during dev is that the json is re-requested at every load. This slows testing down, but it also misrepresents the user's experience when actually browsing the site.
By “at every load” do you mean page load? Or rebuild? Or...?
@mmmeff Every time you navigate to the same path, it re-requests the json. So if you click back and forth between two pages, you spend a lot of time waiting for data.
@mikestopcontinues this is the intended behavior, as the most up-to-date data is often preferable in development. Would be open to discussing some better heuristics in a new issue!
@timneutkens This RFC looks very promising. I have a few questions/concerns about security, and how it works exactly.
Let's take a generic business case that relies on both SSR and SSG.
We want to display some information on a website (AKA "app").
Those information are stored in a BDD that's accessible through a GraphQL API.
Some of those information are public, some are private (ie: user emails/password).
The app uses two stages:
In this scenario, we use both SSR and SSG:
This scenario should be generic enough, and should be (IMHO) one of the major use case of SSG usage.
The production app is nothing more than a snapshot of the staging app.
When do you plan to release this? Is it gonna be a major update (v10), or a backward-compatible update?
Hey,
have you anyone tried this solution with custom server and get it working?
Example:
// server.js
const express = require('express');
const next = require('next');
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.get('/blog/:id', (req, res) => {
console.log('My params needed be passed to page:', req.params);
return app.render(req, res, '/blogDetail', { id: req.params.id });
});
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
});
// blogDetail.js
export async function unstable_getStaticProps(props) {
console.log('What is passed', props);
return {};
}
const BlogPostPage = ({ post }) => {
return <div>Hey</div>;
}
export default BlogPostPage;
# Terminal output
My params needed be passed to page: { id: 'test' }
What is passed { params: undefined }
Why can't getStaticProps
include the query string? I currently have a page that I have to SSR simply to get the query params without re-renders. Using the useRouter
hook causes multiple re-renders, since query is initially an empty object. This is a page that is used for conversion tracking, so obviously, that's a non-starter.
@pjaws The RFC specifically mentions getStaticProps
is for static generation. Static HTML can't receive a querystring.
Then why can it receive dynamic URL parameters? How is that any different?
On Tue, Jan 14, 2020 at 1:30 AM Tim Neutkens notifications@github.com
wrote:
@pjaws https://github.com/pjaws The RFC it specifically mentions
getStaticProps is for static generation. Static HTML can't receive a
querystring.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/zeit/next.js/issues/9524?email_source=notifications&email_token=AMVRRIQCKDJNF4MPWSLYNV3Q5WA2NA5CNFSM4JRPBEL2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEI35G2I#issuecomment-574083945,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AMVRRIRJXLYC4MC4U7DH7NDQ5WA2NANCNFSM4JRPBELQ
.
Because in getStaticPaths
you have to return the pages that will be rendered at build time.
These changes look very promising, great work as always! 👍
I wonder about the use case of having getInitialProps
in _app.js
to satisfy data needs shared across the pages (e.g. setting up context providers). Do I understand correctly that it's impossible to use getStaticProps
in the same manner? It's only possible to define it in individual pages?
I wonder about the use case of having getInitialProps in _app.js to satisfy data needs shared across the pages (e.g. setting up context providers). Do I understand correctly that it's impossible to use getStaticProps in the same manner? It's only possible to define it in individual pages?
Correct, initially it'll just be for individual pages. Might reconsider later on. The getInitialProps of _app will still be called when exporting to static HTML so you can incrementally move to getStaticProps.
hi guys, one related question - how will assets be treated ? because im seeing right now that if i use a headless CMS (even wordpress or graphcms or whatever), the asset url is used in the static html.
There are two preferences here - that asset links be used as such.
But more likely - download the asset, build the html (link to it locally) and then layer a CDN in front. This is the far more acceptable practice.
This also ties in very well with using deployment systems like Netlify - which have a far, far more suitable globally available infrastructure than something like DatoCMS or Graphcms. So if im using Netlify as deployment, i would want everything to be served from Netlify domain and let it work its magic.
@sandys If I understand correctly in https://github.com/zeit/next.js/issues/9054#issuecomment-570427085 you're supposed to download the assets, store them under .next/static
and build a link yourself in getStaticProps
.
There's also the idea of having static api routes, but I'm not sure exactly how you'd control browser caching behavior with that.
@Janpot thanks for linking it. The comments there seem to indicate that this stuff has to be roll-your-own.
Please add my request to having this built-in. Perhaps #9054 is more generic, but im thinking from the perspective of SSG and this is EXTREMELY essential.
I forgot to mention, but asset hashing will also be essential for SSG.
@homoky, Have not been able to get that working, did you make any progress in the meantime?
@homoky, Have not been able to get that working, did you make any progress in the meantime?
It is not possible and it is not planned as well: #10071
😢
@sandys actually the solution is much simpler when you use https://github.com/zeit/next.js/issues/9081 to add a rewrite from eg /images
to the CMS. Eg on ZEIT Now it would already cache the result when the correct headers are added, no need for additional downloading (massive overhead on build).
@timneutkens thanks for replying.
Not entirely sure what you mean. So we use netlify - are you suggesting that we keep the CMS urls as such and front a layer of CDN over it ?
im not very sure if netlify (cloudfront which we are planning to use) can work seamlessly with all these services.
If the images get downloaded and made part of the deployment, then this whole problem gets massively simplified. Because i setup CDN to cache from the base url (which in my case will get served from s3).
Not entirely sure if your solution is predicated on me using Zeit NOW
If the images get downloaded and made part of the deployment, then this whole problem gets massively simplified. Because i setup CDN to cache from the base url (which in my case will get served from s3).
This actually makes the build process much more complex and 10x slower, definitely not simpler.
Not entirely sure if your solution is predicated on me using Zeit NOW
Works with every proxy in the world. Including cloudfront.
@timneutkens we are agnostic to the build process time actually. doesnt matter if it takes longer. but for many reasons (including all assets being served from a known base url), it would be highly preferable to have this baked in the build.
I'm certainly not advocating that you turn this on for everyone. Many people will be happy deeplinking to a CMS. But we run a high traffic site and this is definitely something sites like us need.
Also, forgive me, but i didnt understand your solution. how should we configure this ? i dont have control over which url a CMS uses. For examples, Datocms starts serving from www.datocms-assets.com/ . How do we use the solution in #9081 ?
we are agnostic to the build process time actually. doesnt matter if it takes longer
This might be true for your application, but that's not the case for the majority of applications.
but for many reasons (including all assets being served from a known base url), it would be highly preferable to have this baked in the build.
It really doesn't have to be as said, you can use a rewrite that proxies /images/*
to the cms url, for example www.datocms-asset.com/*
or similar. And then just link all images using /images
.
Note that this is starting to get off-topic.
@sandys actually the solution is much simpler when you use #9081 to add a rewrite from eg /images to the CMS. Eg on ZEIT Now it would already cache the result when the correct headers are added, no need for additional downloading (massive overhead on build).
@timneutkens Just to make things clear for me. In the ideal situation you'd hash the image and cache it forever in the browser under a unique url, and content creators can update the file whenever they want under the same name in the CMS. So that means in the setup you propose the CMS would have to be responsible for:
getStaticProps
to remap the image urls to their immutable counterpart on the CMSWhich, I guess, is not impossible. Just want to make sure that this is the proposed setup.
@Janpot CMS providers already handle this by giving a unique url for images etc.
This might be true for your application, but that's not the case for the majority of applications.
Again, im not alone here. There are tons of similar requests. I do request you to consider this.
on gatsby side as well - https://github.com/gatsbyjs/gatsby/issues/14076
https://github.com/njosefbeck/gatsby-source-stripe/#downloading-files
@sandys this is unrelated to the SSG RFC so feel free to create a new issue when it's released.
however, just wanted to mention that in all our minds, this is closely tied to SSG. Since the ideal case is for the SSG export command to do this. This is not needed in other cases generally.
Best case is for this to be an optional feature during next export.
But, as you wish - respect your decision.
But it's something that next export
doesn't even do currently. Hence why it's a completely new thing and unrelated to this RFC.
It also wouldn't with getServerProps
and on-demand rendering.
@Janpot CMS providers already handle this by giving a unique url for images etc.
👍 yes, that makes sense. But that also means that if you use images in your project and you want them optimized and cached, you have 2 choices:
edit:
And if I understand correctly, file-loader
is already included for CSS. Isn't it a matter of enabling it for JS as well?
@Janpot the specific point Sandeep mentioned is that the urls would come from an external source, not the project itself. Including file-loader by default is a different feature request.
I've noticed that for sites deployed to ZEIT Now, when I have a page with a dynamic URL using the new static APIs, for pages which haven't been statically generated using unstable_getStaticPaths
, the function unstable_getStaticProps
runs on the server at runtime, rather than returning a 404.
E.g. I have a page /blog/[slug].js
, whose getStaticPaths
returns the array:
[{ params: { slug: 'hello' } }]
and my getStaticProps
has some logic to read a file based on the slug. When I visit /blog/hello
the page is prerendered as expected, but when I visit an invalid page like /blog/doesnt-exist
, then getStaticProps
runs at runtime and I get an error 500, rather than a 404. Or if I add error handling, then the page renders, rather than a 404, despite not being listed in the output from getStaticPaths
.
Is this logic intentional?
This is a great improvement. We were just about to write some pre-build scripts to do just this.
I just tested moving one of our sites to unstable_getStaticPaths
and unstable_getStaticProps
on Next 9.2, and it worked well.
We have one regression compared to exportPathMap
: when building a path using exportPathMap
, you can specify something like this:
{
"/path/to/page": {page: "/index", query: { pageId: 123 } }
}
and the static build will build
/path
/to
/page
index.html
When you return the equivalent fromunstable_getStaticPaths
in template [slug].jsx
,
[{ slug: '/path/to/page' }]
Next 9.2 generates '%2Fpath%2Fto%2Fpage` instead of the nested directories.
/%2Fpath%2Fto%2F
index.html
Building out directories (matching existing exportPathMap behaviour) is important for how we're building out pages. We use a single template file but the published path may be arbitrarily nested.
@dpfavand in that case you'll want to use a catch-all route: https://nextjs.org/blog/next-9-2#catch-all-dynamic-routes
Potentially we can warn when you try to return a path including slashes, but the behavior is correct when using [slug].js
, in your case you want [...slug].js
.
When is this expected to land? Will it be in a patch of 9.2 or it's own minor version?
We really appreciate all the excitement around this feature. As mentioned elsewhere we generally don't share timelines for features as we want to ensure they have the right developer experience, constraints and future proof-ness.
As it's a new feature it'll be a minor.
Yeah, I’d understand that normally but the 9.1.7 blog gave the impression
it was already out in the wild.
On Fri, Jan 17, 2020 at 5:05 PM Tim Neutkens notifications@github.com
wrote:
We really appreciate all the excitement around this feature. As mentioned
elsewhere we generally don't share timelines for features as we want to
ensure they have the right developer experience, constraints and future
proof-ness.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/zeit/next.js/issues/9524?email_source=notifications&email_token=ADKINGF724256WCEFHBFIH3Q6ITRXA5CNFSM4JRPBEL2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEJJDN5Q#issuecomment-575813366,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ADKINGBVCG6MFMOG5U2FGMDQ6ITRXANCNFSM4JRPBELQ
.>
Lassiter Gregg
[email protected] lassitergregg@gmail.com
cell (832) 495-9903
Is there anything like getStaticProps
but that runs only once for the whole app instead of per page?
My use case is that I have a React Context (PricingPlansContext
) that is used by multiple pages and I want the data (pricing plans) to be retrieved from my external server only once, at build time (next export
). Never at runtime and without having to add to the getStaticProps
from every page.
EDIT: Found a related comment above: https://github.com/zeit/next.js/issues/9524#issuecomment-574179540. Hopefully it gets considered.
I use babel
plugin-preval` for that, though I've also seen people write a
json file within exportPathMa() with next.config.js, which they then import
within their code.
I ended up writing a json file using a npm script for now, but thanks for suggesting exportPathMap, maybe that’s a better place.
@dpfavand in that case you'll want to use a catch-all route: https://nextjs.org/blog/next-9-2#catch-all-dynamic-routes
Potentially we can warn when you try to return a path including slashes, but the behavior is correct when using
[slug].js
, in your case you want[...slug].js
.
@timneutkens thanks for the follow-up. I've tried two methods without success. Basically when specifying the slug value as a string in getStaticPaths
, it isn't passed through to getStaticProps
at all. When returning the slug value as an array, the build fails as the value must be a string.
Case 1, Assuming a file pages/[...slug].jsx
, slug as string:
export async function unstable_getStaticPaths() {
return [{ params: { slug: 'en/about' } }];
}
export async function unstable_getStaticProps({ params }) {
console.log('params', params);
return { slug: params.slug };
}
In the above case, params
in getStaticProps
is an empty object - no slug
key.
Case 2, pages/[...slug].jsx
, slug as array,
export async function unstable_getStaticPaths() {
const allPaths = Object.keys(pathMap).map(slug => ({ params: { slug } }));
return [{ params: { slug: ['en', 'about'] } }];
}
export async function unstable_getStaticProps({ params }) {
console.log('params', params);
return { slug: params.slug };
}
In case 2, the build fails with
> Build error occurred
{ Error: A required parameter (slug) was not provided as a string.
at _validParamKeys.forEach.validParamKey (/project/node_modules/next/dist/build/utils.js:21:569)
at Array.forEach (<anonymous>)
at toPrerender.forEach.entry (/project/node_modules/next/dist/build/utils.js:21:495)
at Array.forEach (<anonymous>)
at Object.isPageStatic (/project/node_modules/next/dist/build/utils.js:17:122)
at process._tickCallback (internal/process/next_tick.js:68:7) type: 'Error' }
I only see path params in the getStaticPaths
examples above. Will it be possible to SSG paths that include query params? For example:
/store/widgets/circles-n-squares?sort=price&minWeight=2&color=black
I'm especially thinking from the perspective of an e-commerce site, where it'd be difficult to cover every single facet of product search in the pathname
of a url.
I posted a message here recently and haven't heard back - essentially, getStaticProps
is behaving like getServerProps
when a site is deployed to ZEIT Now (i.e. ignoring getStaticPaths
and handling requests dynamically) - I think this is a bug?
@dpfavand i'm experiencing the exact thing as well! Trying to build a starter site for agilitycms and nextjs with dynamic page routing based on pages in the CMS.
@timneutkens thanks for the follow-up. I've tried two methods without success. Basically when specifying the slug value as a string in
getStaticPaths
, it isn't passed through togetStaticProps
at all.Case 1, Assuming a file
pages/[...slug].jsx
, slug as string:export async function unstable_getStaticPaths() { return [{ params: { slug: 'en/about' } }]; } export async function unstable_getStaticProps({ params }) { console.log('params', params); return { slug: params.slug }; }
In the above case,
params
ingetStaticProps
is an empty object - noslug
key.
BTW, small world! Thanks again for speaking at fastr_conf.
Hi @timneutkens,
I am very excited about the idea of making next.js behave like a static site generator.
I would like to ask how getStaticProps
and getStaticPaths
methods can be used in case when large chunk of data is requested once and then used to generate different pages.
For example, I am using a JavaScript SDK client of an API-based CMS that has a method to fetch all available objects. Some of these objects represent site pages.
const entries = await cmsSdkCient.getEntries();
Up until now, I've been using exportPathMap
method to fetch all the entries from CMS at once and generate a map between paths of these page and their data. The exportPathMap
function does two things:
ssr: true
that is consumed by getInitialProps
at export timessr: false
, to init-props.json
files, placed in the folder matching the path of every page. Then, when getInitialProps
is called from client, the needed data is loaded from init-props.json
of matched page.
next.config.js using
exportPathMap
module.exports = {
exportTrailingSlash: true,
exportPathMap: (defaultPathMap, { outDir }) => {
// load data from CMS
const objects = await cmsSdkCient.getEntries();
// create map between page paths and page data
return objects.reduce((accum, object) => {
// if the object does not have a slug, it is not a page
if (!object.slug) return accum;
const pagePath = '/' + object.slug;
const ssrQueryData = Object.assign({ ssr: true }, object);
const clientQueryData = Object.assign({ ssr: false }, object);
// generate the map for export phase with {ssr: true}
accum[pagePath] = {
// using additional fields from the page object,
// the pageFromPagePath() computes which page file should
// be used to render the page object
page: pageFromPagePath(object),
query: ssrQueryData
};
// write json files that will be loaded by client
if (outDir) {
const jsonFilePath = path.join(outDir, _.trim(pagePath, '/'), 'init-props.json');
fse.outputFileSync(jsonFilePath, JSON.stringify(clientQueryData));
}
return accum;
}, {});
}
}
pages/my_page.js using
getInitialProps
Index.getInitialProps = async (context) => {
const ssr = _.get(context, 'query.ssr', false);
if (ssr) {
// we are on server, return the data
return _.get(context, 'query', {});
} else {
// we are on client side, request the data through /init-props.json endpoint
const url = context.asPath + '/init-props.json';
return fetch(url).then(response => {
return response.json();
});
}
};
I can see the huge advantage of using getStaticProps
and getStaticPaths
methods that will reduce much of my code related to saving JSON files and loading them from client.
// pages/my_page.js
export async function getStaticProps(context) {
const objects = await cmsSdkCient.getEntries();
const props = _.find(object, { type: 'my_page' })
return { props };
}
// pages/blog/[slug].js
export async function getStaticProps(context) {
const objects = await cmsSdkCient.getEntries();
const props = _.find(object, { type: 'post', slug: context.params.slug })
return { props };
}
export async function getStaticPaths() {
const objects = await cmsSdkCient.getEntries();
return objects
.filter(object => object.type === 'post')
.map(object => ({ params: { slug: object.slug } }))
}
What troubles me is the question how can I optimize the workflow to bring all the entries once, rather than fetching them every time when getStaticProps
or getStaticPaths
are called?
Another question, might not be necessarily related to this issue, but because we are in the world of SSGs and remote data sources, it is worth asking. Assuming next.js runs in dev mode, how can one notify next.js to re-execute these methods in order to refetch the remote data and rebuild the site.
@smnh Since it’s “just JavaScript”, you can fetch your entries once and cache the results in your data fetching method. When it’s invoked again in some other page’s getStatic* methods, the network won’t be hit again.
As for your second question, it does so automatically. Run next dev
and you’re good to go.
I only see path params in the
getStaticPaths
examples above. Will it be possible to SSG paths that include query params? For example:/store/widgets/circles-n-squares?sort=price&minWeight=2&color=black
I'm especially thinking from the perspective of an e-commerce site, where it'd be difficult to cover every single facet of product search in the
pathname
of a url.
I don't think this makes sense in the context of ssg. SSG outputs a file for every entry - query params aren't part of the filename so you'd need a server layer to rewrite the requests to an actual file. (What would your static file name be in the above example?) I would suggest considering prerendering the default view (what you get if you visit the page with no facets) and updating on client side if there are query params on the request. But that becomes an issue beyond this SSG RFC.
@dpfavand i'm experiencing the exact thing as well! Trying to build a starter site for agilitycms and nextjs with dynamic page routing based on pages in the CMS.
@timneutkens thanks for the follow-up. I've tried two methods without success. Basically when specifying the slug value as a string in
getStaticPaths
, it isn't passed through togetStaticProps
at all.
Case 1, Assuming a filepages/[...slug].jsx
, slug as string:export async function unstable_getStaticPaths() { return [{ params: { slug: 'en/about' } }]; } export async function unstable_getStaticProps({ params }) { console.log('params', params); return { slug: params.slug }; }
In the above case,
params
ingetStaticProps
is an empty object - noslug
key.BTW, small world! Thanks again for speaking at fastr_conf.
Hey! The Nextjs team started to address this, there is a ticket open to address some additional issues with the current canary implementation: https://github.com/zeit/next.js/issues/10190
@smnh what I end up doing is having a script that prefetches the shared content and saves it to JSON before running the build + export. Then you just import that JSON directly in the page as a module.
For rebuilds, I have webhooks set up in the CMS to trigger Netlify build hooks when relevant content changes. GetStaticProps can then just fetch page specific content.
Thanks @zeusdeux
Re:
As for your second question, it does so automatically. Run next dev and you’re good to go.
If I cache them in a module and then change the data in CMS, how the cache will be invalidated and re run by dev
, but without stopping next.js and running it again :)
If I cache them in a module and then change the data in CMS, how the cache will be invalidated and re run by
dev
, but without stopping next.js and running it again :)
getStaticPaths
is only invoked in a production build, so you can only tell the fetching method to cache in module state when called from that function.
Hey, I haven't seen if anyone run in to same issue as I did.
Let's say I have same page on multiple routes with unstable_getStaticProps
:
1. /providers/[category]/[city]
2. /providers/[category]
The source code is the same for both pages so there is no need to duplicated. So for first file contains source code with logic, the second one only imports the first one like export { default } from './[city]';
.
But it throws an error that data from getStaticProps are undefined. If I hardcopy same code to both files it works.
@homoky you need to re-export the methods:
export { default, unstable_getStaticProps } from './[city]';
I have been trying SSG, but without luck.
Should below code with v9.2.1 result in SSG?
function Page({ stars }) {
return <div>Next stars: {stars}</div>
}
Page.unstable_getStaticProps = async ctx => {
return { props: { stars: 5 } }
}
export default Page
My console output from next build
shows:
Page Size First Load
┌ ○ / 354 B 72.1 kB
...
λ (Server) server-side renders at runtime (uses getInitialProps or getServerProps)
○ (Static) automatically rendered as static HTML (uses no initial props)
● (SSG) automatically generated as static HTML + JSON (uses getStaticProps)
@joostmeijles unstable_getStaticProps
needs to be exported instead of attached to the page component, e.g.
export const unstable_getStaticProps = async () => {
return {
props: { stars: 5 }
}
}
@joostmeijles
unstable_getStaticProps
needs to be exported instead of attached to the page component, e.g.export const unstable_getStaticProps = async () => { return { props: { stars: 5 } } }
Thanks, that solves it.
If anyone wants to see an end-to-end working example of this, creating dynamic pages (from a CMS) with a catch-all route and SSG check out https://github.com/agility/agilitycms-next-starter-ssg.
I got stumped a couple of times and figured this could be helpful for others.
How can I access the next API routes during build with getStaticProps
when deploying on zeit.co/now? Isomorphic-fetch requires an absolute URL; locally it works with http://localhost:3000 but not with now deployment (or I did it wrong 🤷♂️). Any ideas?
If I'm correct, the API routes are going to be deployed as serverless functions and I guess that they are not ready during the build process?
You’ll want to call the function of your api route directly as that’s much less overhead than going over http.
You’ll want to call the function of your api route directly as that’s much less overhead than going over http.
Any resources that I can read in the docs about that topic? I'm in the middle of the migration to zeit.co/now :)
Taken quite literally, import and call the function:
import MyFunction from '../lib/somewhere'
export async function /* unstable_ */getStaticProps() {
const result = await MyFunction()
}
Another question: Will it be possible to use getStaticProps
/getStaticPaths
and getServerProps
side-by-side? For example if I've prerendered some pages with SSG, but if one isn't found in the CDN cache, then it will fallback to SSR to generate the page on-demand?
getStaticProps
will fallback to SSR and add the result to the cache,
getStaticProps
will fallback to SSR and add the result to the cache,
@lfades, if I understand you correctly, then I'm super 😍 about it, because it means I can pre-render a few of the popular pages, instead of looking up and generating several thousand pages ahead of time.
But just to make sure I understand... Let's say I have a /products/[productId].js
dynamic path page. If I supply a getStaticProps
, and a limited number of results from getStaticPaths
, then you're saying if /products/123
isn't found in the CDN cache (because it wasn't in getStaticPaths
), it will drop back to SSR, run getStaticProps
, and then cache the result as a static page?
Followup question: will that also work if I don't supply a getStaticPaths
at all?
@flintinatux Yes and yes 👍
getStaticProps will fallback to SSR and add the result to the cache
This is a problem because there's no way to do 404s, since getStaticProps
doesn't allow changing the res
object - either it will 200, or 500 if there's an error during the function call.
Is this planned to change?
@davidbailey00 when creating static websites 404 pages already don't have the 404 status code.
Of course if I do a full static export there's no way to do status codes, since everything is just a file. I'm talking about deploying hybrid sites using getStaticProps
to ZEIT Now - it seems like it should respect getStaticPaths
and serve 404 pages, rather than force rendering all pages matching a dynamic path regardless of this.
That's not just how it works on Now though, same on next start
.
I'll repeat as said earlier though: This is experimental and anything can still change in behavior.
But it's possible to serve 404 pages with getServerProps
or getInitialProps
- if getStaticProps
ignores getStaticPaths
when considering response code then it's completely unviable for any site which cares about good SEO.
We'll probably introduce more ways of handling status codes, but keep in mind that most static sites (eg CRA) route /*
to index.html
where 404 is still a 200.
Hi guys, I have a straight question, I'm building a simple website using the new [unstable_]getStaticProps
to SSG some of the pages. All it's working fine so far, with the exception of amp.
If a page contain [unstable_]getStaticProps
, then amp
is disabled. Here a simple example working with next v9.2.1 where you can check that:
import React from "react";
import { useAmp } from "next/amp";
export const config = { amp: `hybrid` };
const AmpExample = ({ date }) => {
const isAmp = useAmp();
return (
<>
<p>
Welcome to the {isAmp ? `AMP` : `normal`} version of the Index page!!
</p>
<p>date: {date}</p>
</>
);
};
/**
* If I get the dynamic data from getStaticProps,
* page is SSG render but AMP is disabled when accessing
* with `/ampExample?amp=1`
*/
export async function unstable_getStaticProps() {
return {
props: {
date: new Date().toISOString(),
},
};
}
/**
* If I get the dynamic data from getInitialProps,
* page is SSR render but AMP is disabled when accessing
* with `/ampExample?amp=1`
*/
// AmpExample.getInitialProps = () => {
// return { date: new Date().toISOString() }
// }
export default AmpExample;
Any help to understand how to have pages SSG
with data and amp
working?
Hi, how about to support getStaticProps
for App
component (_app.tsx
) i.e. for cases like fetching common data for all page components during the build stage ?
Hi, how about to support
getStaticProps
forApp
component (_app.tsx
) i.e. for cases like fetching common data for all page components during the build stage ?
@pkral78 I can tell you how I resolve with the actual state of development.
I created a Layout with the approach "Layout as a Higher Order Component (HOC)" (no longer in the learning docs 🤷♂️).
Anyway, I created a Layout like the following (just an example):
import React from "react";
import Head from "next/head";
const withSSGLayout = Page => {
const WithSSGLayout = props => {
return (
<>
<Head>
<title>My Web Page</title>
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap"
rel="stylesheet"
/>
</Head>
<Page {...props} />
</>
);
};
WithSSGLayout.unstable_getStaticProps = async () => {
const pageStaticProps = Page.unstable_getStaticProps
? await Page.unstable_getStaticProps()
: {};
// Here you can make parent level queries too
return {
props: {
...pageStaticProps.props,
parentProp: `dynamic prop-${new Date().toISOString()}`,
},
};
};
return WithSSGLayout;
};
export default withSSGLayout;
And then in the page you want to use this approach you can simple add the HOC (you have to explicitly export the [unstable_]getStaticProps
and amp not working together), but I found a "nice way" to have high level request and per page SSG queries.
import React from "react";
import withSSGLayout from "../hocs/withSSGLayout";
export const config = { amp: `true` };
const Index = props => {
const { date, parentProp } = props;
return (
<div>
<h1>Example</h1>
<h3>Local Prop?: {date}</h3>
<h3>Parent Prop?: {parentProp}</h3>
</div>
);
};
// In theory you could do direct database queries
Index.unstable_getStaticProps = async () => {
// Here you can make page level queries
return {
props: {
date: new Date().toISOString(),
},
};
};
const IndexHOC = withSSGLayout(Index);
export const { unstable_getStaticProps } = IndexHOC;
export default IndexHOC;
Would like to underhand if it's a good approach. In my case, I'm using this technique to query the links in the parent and per page content in the pages ones. I hope it helps.
@robertovg You have to export at the module level as the code is tree-shaken. The way you modeled it causes more code to be shipped to the client-side.
@timneutkens Could you maybe propose a better solution for this small example? I was just trying to have both "Layout level SSG query" and "Page Level SSG query" in some way and I thought about this HOC Layout approach.
The main constraint for me was to explicitly "export [unstable_]getStaticProps" you need to have on each page to mark as SSG page.
I would really also appreciate some more info on if amp + SSG will be compatible, I asked earlier.
Thanks 🙏
@robertovg First, Separate the Layout from the data, so for the shared Layout you would have something simple like this:
import Layout from '../components/layout'
const Page = () => (
<Layout>
<h1>Hello World!</h1>
</Layout>
)
export default Page
And then for getStaticProps
fetch the shared data using a method from another module, so the full example could look like:
import fetchSharedData from '../lib/fetch-shared-data'
import Layout from '../components/layout'
export const unstable_getStaticProps = async () => {
const sharedData = await fetchSharedData()
const pageProps = {...}
return { props: { ...sharedData, ...pageProps } }
}
const Page = () => (
<Layout>
<h1>Hello World!</h1>
</Layout>
)
export default Page
@robertovg First, Separate the Layout from the data, so for the shared Layout you would have something simple like this:
import Layout from '../components/layout' const Page = () => ( <Layout> <h1>Hello World!</h1> </Layout> ) export default Page
And then for
getStaticProps
fetch the shared data using a method from another module, so the full example could look like:import fetchSharedData from '../lib/fetch-shared-data' import Layout from '../components/layout' export const unstable_getStaticProps = async () => { const sharedData = await fetchSharedData() const pageProps = {...} return { props: { ...sharedData, ...pageProps } } } const Page = () => ( <Layout> <h1>Hello World!</h1> </Layout> ) export default Page
I see and I understand this solution but the problem I was trying to rise was how to scale the usage of shared data.
For example, if you have a <Header />
which uses the sharedData
to get the links and those are coming from a Headless CMS. You have to inject the <Header />
as a child of the <Layout />
with props or another solution. And you need to repeat the <Header />
injection into all the pages you want to use it.
With the HOC approach you would just add the <Header />
once in the HOC.
That's why I thought it was a good point the one raised by @pkral78 , to avoid code duplication if possible.
That's why I thought it was a good point the one raised by @pkral78 , to avoid code duplication if possible.
It was on my mind. The _app page should has its getStaticProps
that is called once during first page render and then pass saved props
to next rendered pages. But I'm still thinking if it is proper concept at all.
Not sure if this sort of thing is an intended use-case, but it doesn't seem to work:
// /pages/[...slug].jsx
import ReactDOMServer from "react-dom/server";
export async function unstable_getStaticProps({ params: { slug } }) {
const filePath = "../content/" + slug.join("/") + ".mdx";
const { default: Component } = await import(filePath);
const content = ReactDOMServer.renderToStaticMarkup(<Component />);
return {
props: { title: slug.join(" "), content }
};
}
export default function Page({ title, content }) {
return (
<div>
<h1>{title}</h1>
<div dangerouslySetInnerHTML={{ __html: content }} />
</div>
);
}
Even if it's not an intended use-case, it does log an error that seems a bit suspicious:
[ warn ] ./pages/[...slug].jsx
Critical dependency: the request of a dependency is an expression
Edit:
Oh, ok, it resolves when I do
const { default: Component } = await import(`../content/${slug.join("/")}.mdx`);
This is complaining about your import file path being dynamic
On Thu, 30 Jan 2020 at 00:29, Jan Potoms notifications@github.com wrote:
Not sure if this sort of thing
https://codesandbox.io/s/nifty-cache-jspqr is an intended use-case, but
it doesn't seem to work:// /pages/[...slug].jsximport ReactDOMServer from "react-dom/server";
export async function unstable_getStaticProps({ params: { slug } }) {
// how safe is this even?
const filePath = "../content/" + slug.join("/") + ".mdx";
const { default: Component } = await import(filePath);
const content = ReactDOMServer.renderToStaticMarkup(Component);
return {
props: { title: slug.join(" "), content }
};
}
export default function Page({ title, content }) {
return (
{title}
);
}Even if it's not an intended use-case, it does log an error that seems a
bit suspicious:[ warn ] ./pages/[...slug].jsx
Critical dependency: the request of a dependency is an expression—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/zeit/next.js/issues/9524?email_source=notifications&email_token=AAADKRKOL34WKTG7J5QFRJ3RAIGPBA5CNFSM4JRPBEL2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKJESJY#issuecomment-580012327,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAADKRIWNA2DSMWFRGD453DRAIGPBANCNFSM4JRPBELQ
.
That's why I thought it was a good point the one raised by @pkral78 , to avoid code duplication if possible.
It was on my mind. The _app page should have its
getStaticProps
that is called once during the first page render and then pass savedprops
to next rendered pages. But I'm still thinking if it is a proper concept at all.
@pkral78 , It could be because in most of SSG sites I imagine implemented with Next, I would like to have a "common piece" (Header, Footer, Side Bars...). And why not just made the query for that common piece in the _app if you need to, and have it available in child pages without having to manually on each page.
My only concern is that if you put it in the _app.js
, we couldn't be able to have more than one "common piece" depending on the page. With the idea I was prototyping, I wanted to be able to have it in the Layout because it would allow us to have multiple Layouts depending on the type of page you want to render, "that's why I called withSSGLayout
to my HOC because I was planning to have not only SSG pages but SSR and fully client base ones, or even more than one SSGLayout. I this could be done if Layouts could also be responsible for a parent getStaticProps
method.
Anyway, having SSG in Next will make it the tool for any kind of web site 🙌
@Janpot with regards to https://github.com/zeit/next.js/issues/9524#issuecomment-580012327
Can highly recommend to never use dynamic paths in import()
. It'll bundle every possible file under the path into the JS bundle and greatly reduce build performance in doing so.
@timneutkens Sure, makes sense. Is getStaticProps
only meant to query external APIs, not the file system?
@Janpot you can read from the filesystem, often you'll end up querying some external API though.
@timneutkens Ok, better to use @mdx-js/runtime
then, instead of relying on @next/mdx
I guess.
import ReactDOMServer from "react-dom/server";
import { promises as fs } from "fs";
import MDX from "@mdx-js/runtime";
export async function unstable_getStaticProps({ params: { slug } }) {
const mdxContent = await fs.readFile(`./content/${slug.join('/')}.mdx`, {
encoding: "utf-8"
});
const content = ReactDOMServer.renderToStaticMarkup(<MDX>{mdxContent}</MDX>);
return {
props: { title: slug.join(" "), content }
};
}
export default function Page({ title, content }) {
return (
<div>
<h1>{title}</h1>
<div dangerouslySetInnerHTML={{ __html: content }} />
</div>
);
}
@Janpot yep! you could also use plain markdown, that's what we do for nextjs.org/docs.
Regarding https://github.com/zeit/next.js/issues/9524#issuecomment-580207073, it's exactly as I currently use Next with SSR. I have a GraphQL request that's performed at the Layout level, and its content is shared with the common components of the app (Navbar, Footer, and the dynamic children). Then, the dynamic children usually makes another GraphQL request for page-specific content.
Thus, having a way of re-using this seems important, I wouldn't want to have to duplicate code on each page to fetch those common data.
Hey!
I'm quite new here. Just started working on migrating the app to NextJS.
There is a basic use case that would greatly benefit from this feature - multiple language versions. The web app I'm working on has like 16 language versions with 100.000+ page views a day and being able to just statically generate for example landing page would be fantastic but the issue is the routing.
With server side rendering I can read request headers or cookies and render proper language version but without it, is the only solution to create paths for every version like /en, /de, /fr and on "/" make NextJS do just redirect?
After learning about ReactDOMServer.renderToStaticMarkup
I added it to my unstable_getStaticProps
function and I found it improved my (mobile) PageSpeed score from 96 to 100 thanks to drastically improving the Time to Interactive and Max Potential First Input Delay.
I can visit the page without JavaScript and it loads fine, so it appears that React is doing work on page load, despite using SSG.
Maybe this is a lack of my understanding around React, but I would expect that performance with and without JavaScript to be the same, and I wouldn't expect pre-rendering the components to help (I thought that's what SSG was doing).
Is the expected, a bug, or something I'm doing wrong?
Pre-commit: https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2F5e310826bcf5030008a91209--josephduffynextjs.netlify.com%2Fposts%2Fgathered-1-0-1&tab=mobile
Commit: https://github.com/JosephDuffy/josephduffy.co.uk/pull/54/commits/d23898b874e5088ebcfabf577ee396b476ed97e4
Post-commit: https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2F5e3371beda1b8f0009368ef9--josephduffynextjs.netlify.com%2Fposts%2Fgathered-1-0-1&tab=mobile
@JosephDuffy
so it appears that React is doing work on page load, despite using SSG.
It's hydrating the DOM. Basically:
If your content is truly static, as in no side effects or event handlers, then step 2. and 3. are kind of unnecessary. With your method you basically reduce your component tree to 1 component with 1 attribute, which is very quick for React to render and hydrate. (+ dangerouslySetInnerHTM
is ignored during hydration)
<div dangerouslySetInnerHTML={{ __html: props.htmlContent }} />
Keep in mind that event handlers and side effects won't work with this method.
Edit:
One idea could be to allow for omitting the default export on a page if getStaticProps
returns static html. i.e.
export async function unstable_getStaticProps() {
// ...
return {
props: { dangerouslySetInnerHTML: { __html: '<div>static content</div>' } }
};
}
Since nothing needs to be rendered client side, next.js can exclude its runtime from the page and just inline the html that getStaticProps
returned. And it would just work the same way as if dangerouslySetInnerHTML
was used on the next.js root node.
I guess it would be easier to implement than partial hydration, albeit less powerful. Reusing the terminology of React itself here could reduce the confusion on how this feature would work.
I am trying to migrate a static site to Next.js and I would like to redirect all the .html variants of blog posts to versions not ending in .html. It seems like getStaticProps
doesn't currently get context so I can't perform a check for incoming slug and redirect. It would be helpful if getStaticProps
got full context so I could do some conditional things with it.
@nodabladam it sounds like you're looking for the Custom Routes RFC: #9081.
That RFC would allow you to define something like this:
// next.config.js
module.exports = {
redirects() {
return [
// Redirect from the old HTML version of a blog post
{
source: "/blog/:post.html",
destination: "/blog/:post",
permanent: true
}
];
}
};
You can currently try this feature under the experimental
key:
// next.config.js
module.exports = {
experimental: {
redirects() {
// ...
}
}
};
I’ve implemented getStaticProps and getStaticPathNames on a project of mine (around 8K pages).
However output files are counted towards the 10K limit of files per deploy. With 8K pages you get 16K of output files since each page also gets a json file.
Are there plans to increase this limit? Or can I work around this limit?
I have the same problem.
I understand they're looking to lift that limit, but I don't know when it's going to be deployed.
So I use getStaticProps on all pages and getStaticPaths only on some of them and it works (my product page generates 70% of the total pages so I didn't put any getStaticPaths in it). I stay under the limit but it's not perfect, first load is quite long and difficult to handle 404 errors.
I have the same problem.
I understand they're looking to lift that limit, but I don't know when it's going to be deployed.So I use getStaticProps on all pages and getStaticPaths only on some of them and it works (my product page generates 70% of the total pages so I didn't put any getStaticPaths in it). I stay under the limit but it's not perfect, first load is quite long and difficult to handle 404 errors.
I hope they raise the limit soon, however I hope it won’t be 20K.. that won’t be enough for me in the long run.
I want to avoid the first load times with getStaticPaths.. I might have to look for other solutions besides Zeit Now
Next.js will also automatically expose an API endpoint that returns the result of calling getServerProps. [...] Next.js will fetch this exposed API endpoint to get the JSON data that is turned into the props needed to render the page client-side.
Next.js will fetch data from this endpoint before doing the actual route change and rendering the page component (it can't, at least by default, do it any other way). So the user may experience an extremely snappy site due to certain pages being statically generated, but if they click a link to an SSR page, suddenly the site will "hang" a little while before the route changes.
Is there a recommended way to load the component _first_ so it can be populated with loading indicators, animated placeholders etc? (Instead of adding them to the current page.) If not, could it be relevant to the newly proposed features? I achieved it using a combination of getInitialProps and hooks inside the render method, but it feels messy.
I would think this UX pattern (instant page switch) is preferred by many (most?), but I haven't seen any examples of it using Next.js yet. I've only used the framework for a couple of days, so please correct me if I'm wrong.
Really excited about the new features! Thanks for your work.
@nicoqh, your concerns about page transitions aren't specific to SSG, since the hang occurs with the current getInitialProps
. I use nprogress
to at least show a progress bar at top while the next page is loading, but I also see this example of having legit page transitions that sound closer to what you're describing. I haven't tried it myself, but I hope it helps with what you need:
https://github.com/zeit/next.js/tree/canary/examples/with-next-page-transitions
It looks like the json file /_next/data/BUILD_ID/<file>.json
that is returned doesn't honor assetPrefix. This causes the file to 404 for me in my production environment since I have a setup that expect everything _next to be an asset that goes through CDN. These json files should ultimately be routing through the assetPrefix (CDN) right?
I have the same problem.
I understand they're looking to lift that limit, but I don't know when it's going to be deployed.
So I use getStaticProps on all pages and getStaticPaths only on some of them and it works (my product page generates 70% of the total pages so I didn't put any getStaticPaths in it). I stay under the limit but it's not perfect, first load is quite long and difficult to handle 404 errors.I hope they raise the limit soon, however I hope it won’t be 20K.. that won’t be enough for me in the long run.
I want to avoid the first load times with getStaticPaths.. I might have to look for other solutions besides Zeit Now
@erhankaradeniz and @ziltosh we should be rolling that out generally very very soon. If you'd like to get help with that ASAP, you can ping me directly or [email protected] and they'll sort you out.
I have the same problem.
I understand they're looking to lift that limit, but I don't know when it's going to be deployed.
So I use getStaticProps on all pages and getStaticPaths only on some of them and it works (my product page generates 70% of the total pages so I didn't put any getStaticPaths in it). I stay under the limit but it's not perfect, first load is quite long and difficult to handle 404 errors.I hope they raise the limit soon, however I hope it won’t be 20K.. that won’t be enough for me in the long run.
I want to avoid the first load times with getStaticPaths.. I might have to look for other solutions besides Zeit Now@erhankaradeniz and @Ziltosh we should be rolling that out generally very very soon. If you'd like to get help with that ASAP, you can ping me directly or [email protected] and they'll sort you out.
Thanks @kvangundy
I've contacted you on Twitter regarding this issue ;-)
@erhankaradeniz Can you email [email protected] instead? That way it ends up in our system correctly.
@flintinatux, thanks for the tip. I've seen the example, and it doesn't help with loading the page component before loading the data, so in-page placeholders etc. aren't possible. It's an interesting example, though, thanks!
I guess it's not going to be addressed in this issue, which means it's off topic, so I'll find somewhere else to discuss it :)
I think the approach of splitting up getInitialProps into getStaticProps
& getServerProps
is much cleaner! I do have a question regarding how this affects our use-case:
We want to create 2 separate builds: one static version for our prod site, and one version using SSR for an editing environment.
I was thinking I could conditionally attach getStaticProps
vs getServerProps
as static methods depending on the build (similar to https://github.com/zeit/next.js/issues/9524#issuecomment-558617056), but I'm not sure if this will be possible to conditionally export them as is. Any ideas if this will be possible to support dynamic/static depending on the build?
With regards to:
RFC will be updated to reflect changes later, still iterating on real-world use in our apps.
I wonder if there's is a way to use some kind of wildcard route to catch routes that are unknown at build time. It's awesome that I can render static pages from for example CMS data, but what if someone adds a new item? I don't have a static page for that. This issue scratches my head for a long time.
I have set up dynamic route to render static pages _pages/[slug].js_. _getStaticPaths_ is getting all the pages I want to render statically. I have _getStaticProps_ to query the data and pass it to the render function. All the pages given in _getStaticPaths_ are rendered as HTML files inside _.next/server/static_ on build. Great!
Now I run npm run start
and these pages for as they should. But requesting a missing url (like _/foo_) generates new static HTML and JSON files inside _.next/server/static_. This is not good. How can I make the server to redirect all the other urls to _pages/_error.js_?
https://github.com/zeit/next.js/issues/9524#issuecomment-582777067
We're covering that too.
Now I run npm run start and these pages for as they should. But requesting a missing url (like /foo) generates new static HTML and JSON files inside .next/server/static. This is not good. How can I make the server to redirect all the other urls to pages/_error.js?
This is still in-flight and not unexpected behavior as of right now.
Again a reminder that you're using an experimental feature and behavior can change at any time. Things will change and potentially break in between all versions while you use this when it's not stable.
@timneutkens Thanks! I understand the unstability. Have you any idea how to manage this? Went through the code and noticed that throwing an error inside _unstable_getStaticProps_ renders the error page. This could be a nice way to go. I would just need a way to pass the error forward as it is to the _pages/_error.js_. I would like to send it 404. Now it goes as 500.
I've posted this a bunch of times before in other threads, but "going to _error" is unexpected behavior, as of right now your page should render a 404 state. Simply said if(!data.something) { return <My404Component /> }
, and then My404Component
should set noindex
meta tags.
Really? Documentation clearly instructs to use _pages/_error.js_ for 404s.
See: https://nextjs.org/docs/advanced-features/custom-error-page
@jiv-e that's for 404s caused by:
If you have dynamic routes you have to handle the "404" case like I said, eg like https://nextjs.org/docs/advanced-features/custom-error-page#reusing-the-built-in-error-page
Got it! Thanks!
I'd like to use getStaticProps
to fetch translation / language keys on build time because they will most likely change 1-2 times month or even per year. Also also don't need them as JSON/props within the DOM. The problem is that I don't want to pass keys down the tree to the component where I actually use them - What approaches are suitable for my use case?
useTranslation() hook (or HOC) with context?
It would be nice if the AppTree
would be part of the NextGetStaticProps Context (getStaticProps({ AppTree })
). Otherwise it won't be possible run things like apollos getDataFromTree
on ssg.
At this point we're not planning to allow AppTree traversal in getStaticProps as it's really bad for performance (consistent feedback from companies). When you add getStaticProps to a page it still goes through getInitialProps of _app to allow incremental adoption, so it'd still work with Apollo really.
It would be nice if we could have amp: 'hybrid'
and SSG functionality at the same time.
This could be achieved by creating two files for a page like this i.e.:
This would allow proxies to resolve to an amp document based on the ?amp=1
query parameter.
It would be nice if we could have
amp: 'hybrid'
and SSG functionality at the same time.
This could be achieved by creating two files for a page like this i.e.:
- (SSG) index.html
- (AMP) index.amp.html
This would allow proxies to resolve to an amp document based on the
?amp=1
query parameter.
Exactly @Dacturne , this is the only downside I see to start using SSG already on projects as I was commenting in this thread time ago.
🤞
@jansedlon I've made a blog post anwsering your question:
I wonder if there's is a way to use some kind of wildcard route to catch routes that are unknown at build time. It's awesome that I can render static pages from for example CMS data, but what if someone adds a new item? I don't have a static page for that. This issue scratches my head for a long time.
https://paqmind.com/en/blog/ssr-is-not-the-future
(not posting here because it's too big)
@ivan-kleshnin I've taken a quick look and it looks super exciting! You just might have saved me hundreds of hours! Thank you so much, I'll take a more in-depth look later today.
https://github.com/zeit/next.js/issues/9524#issuecomment-582799948
@jansedlon as said earlier we're working on something with regards to this that isn't covered in @ivan-kleshnin's blogpost. Hopefully will be able to share more on this very soon.
@timneutkens Love the changes so far 🙏 Do you have any plans to improve/support full static+internationalization?
We've been using the new getStaticProps
/getStaticPaths
APIs in our migration of tinacms.org from Gatsby to Next.js, and so far it's been great!
One stumbling block we've had is in generating an RSS feed. Ideally we'd like to generate it statically, since the content it references is statically generated. I don't see a way to do this currently, so instead we're just handling it server-side by querying the content and writing XML to the response.
Has there been any discussion about supporting static generation for non-HTML content types?
FYI We started using getStaticProps
on zeit now and releases using the --prod
flag and the cache was not being cleared for the json files on new releases. Switching our production release back to using the alias feature worked and cache was cleared.
We've been using the new
getStaticProps
/getStaticPaths
APIs in our migration of tinacms.org from Gatsby to Next.js, and so far it's been great!One stumbling block we've had is in generating an RSS feed. Ideally we'd like to generate it statically, since the content it references is statically generated. I don't see a way to do this currently, so instead we're just handling it server-side by querying the content and writing XML to the response.
Has there been any discussion about supporting static generation for non-HTML content types?
I was thinking it for myself and I just found out this. Here is my scripts:
"scripts": {
"dev": " next",
"build": "yarn sitemap && next build",
"start": "next start",
"sitemap": "ts-node --project ./cli/tsconfig.spec.json ./cli/generateSitemap.ts"
},
Before next build
is called yarn sitemap
that generates statically sitemap. You could use same technique, to cache all data to json for example, that you will need in getStaticProps
and you can reuse it on multiple pages.
Updated the RFC, changed getStaticPaths
behavior a bit (you need to return a paths
key now, this mirrors getStaticProps
where props
have to be returned. This change hasn't landed in Next.js yet.
Also added an explanation for the fallback
behavior (on-demand background generation of pages that weren't exported at build time).
Did another update to the RFC, added explanation for changes in client navigation with regards to a Loading
state.
We might want to add a way for users to know if the loading state is being rendered through a React hook 🤔
Great stuff! I was just wondering, would there be a way for statically generated pages to share data between multiple routes using a single JSON file (like code-splitting but for data)?
I bumped up to the latest canary
build and immediately got bit by the new Loading
state. In the past, it's been nice to safely assume I've already got the right data before the view layer starts rendering. The forced asynchronous loading is a big departure from that. I've really enjoyed ripping out all the boilerplate endpoints that the new auto-generated SSR endpoints will replace, but I wasn't planning to redesign every page to include new Loading
states.
I understand the desire for a quicker TTFB, and in the future that might be a nice-to-have for my app. But would it be possible to make the Loading
state an opt-in or opt-out feature, similar to the fallback: false
for getStaticPaths
? Perhaps an export const enableLoadingState = false
on the page, or site-wide in the next.config.js
.
https://github.com/zeit/next.js/issues/9524#issuecomment-583962425
Again a reminder that you're using an experimental feature and that we're experimenting with the behavior currently.
I deployed my (experimental) SSG website to Now (using a default setup). It works fine, but I see 404 errors in the network tab when browsing the site. All 404 errors point to _next/static/pages/[slug].js
.
Is this expected behavior while its experimental? Or should I change some settings?
@joostmeijles it sounds like you aren't providing the correct href
and as
to next/link
. For dynamic pages href
needs to be the page href='/[slug]'
and as
needs to be the URL as='/slug-1'
I'm getting 3 logs in the console during build, is this a bug?
// Page is showing three logs despite static path only having 2 entries and output generating only two files as intended
export default function Page(props){
console.log("Page - should only show twice", props);
return <><h1>Page</h1></>
}
export async function unstable_getStaticProps(props) {
console.log("unstable_getStaticProps - should only show twice", props);
return {
props
};
}
export async function unstable_getStaticPaths() {
console.log("show once")
return {
paths: [
{ params: { year: "1901" } },
{ params: { year: "1902" } },
]
}
}
No that's expected as per fallback
in the RFC.
No that's expected as per
fallback
in the RFC.
export async function unstable_getStaticPaths() {
console.log("show once")
return {
fallback: false,
paths: [
// This renders /blog/hello-world to HTML at build time
{ params: { year: "1901" } },
{ params: { year: "1902" } },
]
}
}
I tried opting out but i'm getting this error.
Error: Extra keys returned from unstable_getStaticPaths in /[year] (fallback) The only field allowed currently is
paths
Again a reminder that you're using an experimental feature and that we're experimenting with the behavior currently and not everything is implemented.
Will this feature getStaticProps
only be available for pages?
Would be interesting for app/document also, for example fetch some global config for the application?
I’ve ‘succesfully’ implemented this and I’m happy with the results so far.. but I’m wondering is there any way to make subsequent builds ‘faster’? For example check if SSG generated pages have not changed and don’t re-generate those? (Probably wishful thinking from me)
@timneutkens Do have any plans to add a sitemap.xml generator for SSG pages? I'm not even talking about dynamic routes since I reckon it's easier to implement it only for static pages for now.
@timneutkens Do have any plans to add a sitemap.xml generator for SSG pages? I'm not even talking about dynamic routes since I reckon it's easier to implement it only for static pages for now.
Yeah this would be a great option. Currently generating one myself with SSR. (but sitemap.xml file takes long to load)
https://github.com/zeit/next.js/issues/9524#issuecomment-585293270
Initially only for pages because there'll be other work that impacts getStaticProps after it lands.
https://github.com/zeit/next.js/issues/9524#issuecomment-586957539
Yes but not as part of this RFC. There'll be a follow-up after this lands.
@timneutkens I think the implementation for SSG pages is easy because you can push a URI into an array every time Next builds a static page and then, when it ends, just map the array into each XML tag, join and insert it in the middle of a <sitemapindex>
tag. The getStaticProps
could have another key in the return object named excludeFromSitemap
so the default would be for all pages to be included in the sitemap.xml
but with an option to opt out.
If that were the case, the developers would have fine control over which static page would go into the sitemap (for example: if page [foo]
's getStaticPaths
function returned paths with foo
params 'abc'
and 'xyz'
but only the 'abc'
file should be in the sitemap, the developer would be able to set excludeFromSitemap
to true
if the parameter ==='xyz'
in getStaticProps
.
Also, for SSR and static pages, it could be possible to export a constant (ie. export const excludeFromSitemap = true;
) from the page file, just like getServerProps
, getStaticPaths
and getStaticProps
are exported.
In SSG pages if there is an exported excludeFromSitemap
constant (page default) and that key is also in the object returned from the getStaticProps
function (path specific), the exported value should act as a default value for all the paths in that page and the path specific excludeFromSitemap
, when present in the getStaticProps
object, should override the default of the page (so a page could do export cosnt excludeFromSitemap = true
and then add the excludeFromSitemap
key to the object returned from getStaticProps
with value false
to exclude all paths from the sitemap except for that specific one).
The code for appending to the array would be something like this (I calculated the truth table and got the minimum boolean expression with a Karnaugh map):
//...somewhere else
const validExcludeFromSitemapTypes = ['boolean','undefined'];
//...for each path
const isSSG = !!getStaticPropsReturnedObj && typeof getStaticPropsReturnedObj === "object";
if(
validExcludeFromSitemapTypes.indexOf(typeof pageExports.excludeFromSitemap)<0 ||
(isSSG && validExcludeFromSitemapTypes.indexOf(typeof getStaticPropsReturnedObj.excludeFromSitemap)<0)
) {
throw new Error("'excludeFromSitemap' can either be ommited (undefined) or be a boolean");
}
const defaultExcludedValue = !!pageExports.excludeFromSitemap;
const hasSpecificExcluded = isSSG && typeof getStaticPropsReturnedObj.excludeFromSitemap !== "undefined";
const specificExcludedValue = isSSG ? !!getStaticPropsReturnedObj.excludeFromSitemap : false;
if(!specificExcludedValue && (!defaultExcludedValue || hasSpecificExcluded))
sitemapURIs.push(correctlyEncodedURI);
Turning the array into the sitemap would be as easy as doing this (assuming the URIs in the array are already encoded and filtered by !excludeFromSitemap
):
function createSitemap(sitemapURIs: string[]): string {
return `<sitemapindex>${sitemapURIs.map(u=>`<sitemap><loc>u/loc></sitemap>`).join('')}</sitemapindex>`;
}
I think this feature would sit in nicely in Next.JS because part of its mission is to give the users the 100 SEO score and having a sitemap.xml
would greatly help! (robots.txt
could potentially also be generated adding a else
to the condition that adds the paths to the sitemap array to append that path into another array of disallowed pages)
In the current release version, when using the unstable_getStaticPaths
together with unstable_getStaticProps
function, you can not make api calls to functions living in /api/
.
As the server is not running, it is impossible to make the corresponding requests and generate the static props this way.
You either have to not supply the paths functions (which basically makes this SSR with a cache, which is still nice!) or rely on SSR instead of SSG.
Maybe this would be a good addition for this feature? I am uncertain what the best way here would be, I've read a proposal somewhere else, that suggested shortcutting the http request, with SSR and /api
routes, this would come handy here as well.
But all of this would of course mean running code in the build environment, that would make calls to other services / db calls or similar. This should be made clear when this is implemented, but it would be a cool addition for this feature.
@reckter Yep, I just did something similar myself. I had to connect to my db for every single separate page request while they were being statically generated. Felt very strange...
I hope that is not the final use case
It would be nice to have some kind of initialization script you can setup from the next.config or something...
@reckter A way for shortcutting HTTP requests to API routes from SSG/SSR would be so good! It feels strange making a network request to myself on either one of those scenarios.
Anyway, a possible solution for accessing API routes during SSG would be to have a local server only running the /api
routes before compiling the static pages! So the build steps would be:
/api
routesunstable_getStaticPaths
unstable_getStaticProps
@reckter basically you don't have to call API routes, you can call the function it implements directly, this also avoids a lot of the overhead going over http causes.
Basically if you currently have an API route that looks like this:
import myDb from 'mydatabaseprovider'
const db = myDb()
export default async (req, res) => {
cont myData = await db.query('posts')
res.json(myData)
}
You would change it to:
import myDb from 'mydatabaseprovider'
const db = myDb()
export async function getData() {
const myData = await db.query('posts')
return myData
}
export default (req, res) => {
const myData = await getData()
res.json(myData)
}
And then in your page:
import {getData} from './api/myfunction'
export async function getStaticProps() {
const myData = await getData()
return {
props: {
myData
}
}
}
It would be tricky to do the same for GraphQL APIs. And also for most REST.
API call != fetching from DB (in general)
There's almost always some business logic in the API layer like field renaming, data reformatting, etc.
I'm sure you have reasons to disallow pages/api
calls... but the bypass of real API won't be easy or cheap. And a couple of spared milliseconds won't outweigh the fees for extra code/complexity IMO.
Also it feels strange that requests to any API will be allowed. Except your own 🤷♂
using unstable_getStaticPaths
causes the page to reload, losing current state in redux for example. Will this behaviour be changed in the future?
edit: seems this behaviour can be circumvented using by using the as
option in links or router
<Link
href='/item/[key]'
as={`/item/${itemName}`}
>
router.push(
'/item/[key]',
`/item/${itemName}`
);
@meesvandongen it was always like that. If your <Link>
is invalid, it takes you to the backend part, basically working as an <a>
. Dynamic fragments like [key]
have to be paired with corresponding values.
@reaktivo
pages/[lang]/blog/[id].js
-> ingetStaticPaths
provide all urls to statically render.
https://github.com/zeit/next.js/issues/9524#issuecomment-562625858
in this case it needs to add getStaticPaths
and getStaticProps
function for every page except index.js.
If there are some mdx pages, the project is more difficult to maintain
consider change to or compatible with static getStaticPaths
getStaticProps
methods. https://github.com/zeit/next.js/issues/9524#issuecomment-558617056
If so, page can be wrapped by higher-order function or higher-order component(HOC).
This way the code is more maintainable and more convenient for typesscript.
tree-shaking vs dynamic. What a headache trade-off.😂
With 9.2.3-canary.13
I tried using fallback: false
in getStaticPaths like this:
return {
fallback: false,
paths: slugs.map(slug => ({params: {slug: slug}}))
}
but it fails with the following error:
Error: Extra keys returned from unstable_getStaticPaths in /blog/[slug] (fallback) Expected: { paths: [] }
With
9.2.3-canary.13
I tried usingfallback: false
in getStaticPaths like this:return { fallback: false, paths: slugs.map(slug => ({params: {slug: slug}})) }
but it fails with the following error:
Error: Extra keys returned from unstable_getStaticPaths in /blog/[slug] (fallback) Expected: { paths: [] }
I think you need the map a level higher, so map returns the object you currently have, but with a unique slug. instead of mapping in the paths.
I have not updated my version on nextjs yet, but it should be similiar:
return data.map(item => {
return {
params: {
slug: item.slug,
},
}
})
@jorngeorg it's an open PR: https://github.com/zeit/next.js/pull/10701
Fantastic contribution! It really improves the static rendering process.
I recommend adding to the docs that on dynamic routes, the "fallback" will be generated without any call to getStaticProps
- meaning you must code your component to account for the case where props is empty.
Alternatively you could change the behaviour to call getStaticProps
with no context when creating the fallback. This would be consistent with how next export
currently works (e.g. /p/[id].js
is exported to /p/[id].html
by running its getInitialProps
without context).
getStaticProps
- Opt-in to static generation (SSG) atnext build
time.getServerProps
- Opt-in to server-side rendering (SSR) which renders on-demand.
Rename getServerProps to getServerSideProps.
I recommend adding to the docs that on dynamic routes, the "fallback" will be generated without any call to
getStaticProps
- meaning you must code your component to account for the case where props is empty.
Good point to mention it! I also had some build/deployment errors because I have missed that.
Updated the RFC to reflect the changes
@timneutkens
- Subsequent request to the same path will serve the generated page
I assume this means that Next.js will cache the generated page? Is this an in-memory cache? Is this cache bounded by limits or can this result in memory leaks?
When you use next start
it uses lru-cache similar to the current caching example, currently the default limit is 50MB, we might make it configurable later on: https://github.com/zeit/next.js/blob/canary/packages/next/next-server/server/spr-cache.ts#L90
When you host on ZEIT Now the generation and caching happens on the CDN/Proxy so it works slightly different and you never have to worry about memory leaks or if you're going over the lru limit.
👍 ok, seems reasonable. That's more or less what I had in mind as a sensible default behavior.
getStaticProps
- Opt-in to static generation (SSG) atnext build
time.getServerProps
- Opt-in to server-side rendering (SSR) which renders on-demand.10722
Rename getServerProps to getServerSideProps.
Why the rename though? IMHO getServerProps is accurate enough and shorter to type, adding Side feels redundant to me.
I was wondering if there are any changes made to getStaticPaths method? My dynamic pages are not generated as static pages anymore, they are exported as lambda functions now?
Am I correct when the default behaviour now is that the pages are first rendered as lambda's and only after visiting a specific page the page is generated to a static page? (just like mentioned in the fallback)
@erhankaradeniz No changes have been made to getStaticPaths
that would result in your page(s) being Lambdas. This is likely an error in usage.
Can you please show your code so we can identify the issue?
@Timer for now I have reverted back to [email protected] where I still can use params, until I figure out why it's not working with paths.
this is how I currently generated my paths:
return cityData.map(city => {
return {
params: {
country: city.countrySlug,
city: city.slug,
},
}
})
and in an other page I do:
return cityData.map(city => {
return {
params: {
country: city.countrySlug,
city: city.slug,
},
}
})
haven't managed to convert it to the new canary release with the paths. I must be doing something wrong, because console.logs are not even triggered within getStaticPath
I have troubles with nested path prerendering and SSG:
// pages/[lang]/[...slugs].js
export async function getStaticPaths() {
let knex = await import("knex/client").then(m => m.default)
let pages = await knex("page").select(["lang", "url"])
return {
fallback: true,
paths: pages.map(page => {
return {
params: {
lang: page.lang,
slugs: page.url == "/" ? [] : page.url.slice(1).split("/"),
}
}
}),
}
}
leads to
Error occurred prerendering page "/en/". Read more: https://err.sh/next.js/prerender-error:
Error: The provided export path '/en/' doesn't match the '/[lang]/[...slugs]' page.
for the Home page. For some reason NextJS fails to match
{lang: "en", slugs: []}
to
/[lang]/[...slugs]
If I provide {lang: "en", slugs: ["/"]}
it builds but with a wrong URL:
├ ● /[lang]/[...slugs] 875 B 204 kB
├ ├ /en/credits
├ ├ /en/%2F
For the record, getServerSideProps
works fine with a similar setup.
I know it's experimental but this thread is to give feedback, right?
pages/[lang]/[...slugs].js
matches /en/abcdef
and not /en
, for that you currently have to create pages/[lang]/index.js
.
There's a feature request open for this: https://github.com/zeit/next.js/issues/10488
First of all, this is awesome. I've been hoping to have something like this in Next.js so I could finally move away from Gatsby.js and have a hybrid app (static + dynamic).
🚀 I tried the canary and half baked complex app version worked fine. I confess I haven't read all the comments here but not sure if the tree-shaking is implemented yet.
🤔 getStaticPaths
feels a lot more like setStaticPaths
where we are defining the static path for the SSG behavior. That kind of confused me a little.
🧐 I wonder if we can improve the build times by having build categories? I know this would complicate the setup but it will be well worth it. Let me explain:
What if we have something like setBuildCategory
that sets it to blog
or pages
or whatever someone wants 2020-content
. Then the SSG builder looks for the category of the page that was changed and only tries to rebuild that category from a combination of cache + new render. Something like this can help us make SSG fast and avoid huge build times for things that are not prone to change a lot but could still change so can't be archived.
If that makes some sense; am happy to jump on a call and chat about this.
How to handle getServerSideProps
with custom server implementation?
if (pathname === '/a') {
app.render(req, res, '/b', query)
}
In the example above, visiting /a
will render the page pages/b.js
. But a client-side redirection to /a
attempts to download a.json
file, that does not exist in this case.
Are we supposed to have similar conditions for requests to /_next/data/{BUILD_ID}/{PAGE}.json
to render different JSON files?
For using fallback: true
in getStaticPaths, how do I get the req object? It appears currently that I cannot. The reason I need it is to grab some cookies from the browser to authenticate a route
@tylermcrobert how do you imagine grabbing cookies when there's no request at all?!
Routes with backend depending on real visitor requests can't be made static by definitions of "static" and "dynamic". Not to say you can't combine static and auth... it's just auth part will belong to API and client code instead of pages.
How to handle
getServerSideProps
with custom server implementation?if (pathname === '/a') { app.render(req, res, '/b', query) }
In the example above, visiting
/a
will render the pagepages/b.js
. But a client-side redirection to/a
attempts to downloada.json
file, that does not exist in this case.Are we supposed to have similar conditions for requests to
/_next/data/{BUILD_ID}/{PAGE}.json
to render different JSON files?
Next.js supports dynamic route parameters, so remapping in a custom server is rarely needed anymore: https://nextjs.org/docs/routing/dynamic-routes
The approach you outlined already doesn't work with <Link>
(would cause a full page transition) so getServerSideProps works already.
@tylermcrobert how do you imagine grabbing cookies when there's no request at all?!
Routes with backend depending on real visitor requests can't be made static by definitions of "static" and "dynamic". Not to say you can't combine static and auth... it's just auth part will belong to API and client code instead of pages.
Maybe I'm misunderstanding the fallback option in that case. What you're saying totally makes sense in the build-time context.
Isn't fallback: true
for when there isn't a predefined route? In that case, a fallback would be reached from the browser, no?
@tylermcrobert yes fallback: true
case has a request but the API has to be unified by the "lowest common denominator". I can't imagine a working system where everything is built with one set of premises and then it's incrementally updated with a totally different set of premises. It will be a disaster to support.
I think you miss the point that those incremental builds will still be cached between builds. So the role of the first visitor will influence the build result for all the consequent users! Sounds like a bad idea.
@ivan-kleshnin I understand & certainly agree. The reason I ask is because of my specific use case.
I am using a headless CMS that allows previewing functionality so the pages that will need to be preview will not be included at build time (Because the entry being previewed will not have existed at this point). I figured this was a case where the fallback option would come in.
To access that preview, I need access to the api preview ref which is given via cookie.
Is this a case where I should just scrap useStaticProps
entirely? I would hate to lose the benefit of static builds because I cannot preview my documents.
The attractiveness of this RFC over something like gatsby is it gives us “hybrid control” with static site generation that makes it less of a pain to work with headless CMSs
I am using a headless CMS that allows previewing functionality so the pages that will need to be preview will not be included at build time (Because the entry being previewed will not have existed at this point). I figured this was a case where the fallback option would come in.
Stay tuned, more soon 🕵
So if I understand this correct, we are able to use fallback true when for example in my case a user registers (no static page is generated since it’s a new page/user) but when the profile gets a visit it’s generated automatically?
Erhan Karadeniz
http://www.erhankaradeniz.com
On 4 Mar 2020, at 20:25, Tim Neutkens notifications@github.com wrote:
I am using a headless CMS that allows previewing functionality so the pages that will need to be preview will not be included at build time (Because the entry being previewed will not have existed at this point). I figured this was a case where the fallback option would come in.Stay tuned, more soon 🕵
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
User data is a bad example as you'd want to fetch that client-side. Fallback is there for on-demand statically generating pages that haven't been generated at build time. Eg you might want to generate the top 100 blogposts at build time and not generate others with less traffic.
Docs will be landed for it soon.
Yeah what I meant was a placeholder page.. I’d fetch userdata on client-side indeed.
@timneutkens Will there be any way of deleting or rebuilding specific statically generated pages?
Hi!!! Sound like the optimal application. I do love both React and Next!!! Made everything so elegant and simple for us to use!! But the example includes the notion blog. I would like to see an example of a an implementation when querying an Headless CMS and make the fetch done per page/post as an export as a static item.
// cheers, since it's near friday !!!
@timneutkens this is exciting 👌
One scenario we frequently hit and I don't have a perfect solution yet with next.js or gatsby except dynamic routes or generating projects in a loop:
For historical reasons we have to deal with multiple domains (and there's no appetite to change this) that serve the same/exact pages with the exception for pricing, currency, support phone numbers and language selectors. By nature most of those marketing pages are pretty static and it would be sufficient to build them daily or weekly (vs having them to render on every request).
My question/thought: do you see a way (in the future?) the getStaticPaths
could generate pages based on something that is not a route param but could be used on a request level to switch between them (eg serverless function returns static, pre-built result based on locale
)
Concrete this would mean https://mysite.com/my-product
and https://mysite.co.uk/my-product
would serve two different static pages but without us having to generate our next app 50x times or having to hit a CMS on every request😅
Thanks in advance and keen to hear your thoughts, especially if that's something for the future that could be solved/worked around ❤️
I‘m thinking about a use case where I want to use SSG for high-traffic landing pages for SEO and for reducing the server load, but still want current data to be used after hydration, and on client side routing to this page. Would that be possible?
So basically on client side routing to this page, the behavior should be like getInitialProps
(current data is fetched before the page becomes visible). And on server side routing to this page, the static html should be served and hydrated, and then (optionally) some api responses fetched to update some data on the page.
I just played with unstable_getStaticProps
just to try it out and I ran into a fun conflict: it is hard to use API routes with getStaticProps
.
Don't pay attention about the semantic of the code, but just the data fetching flow:
// pages/api/healthcheck.ts
import { NextApiResponse, NextApiRequest } from 'next';
export type ApiHealthCheckResponse = {
message: 'ok';
};
const healthCheckHandler = (
req: NextApiRequest,
res: NextApiResponse<ApiHealthCheckResponse | ''>,
) => {
if (req.method === 'GET') {
return res.status(200).json({ message: 'ok' });
}
return res.status(405).send('');
};
export default healthCheckHandler;
// pages/index.js
// ...
export async function unstable_getStaticProps() {
return {
props: {
healthcheck: (await fetch('localhost:3000/api/healthcheck').json())
},
};
}
The page build will crash at build time because the server is not running. I am not sure if this is a valid usecase, as getStaticProps
should not be used with anything too dynamic, but I thought it was an interesting edgecase to share (I can totally imagine an Route API endpoint in charge of getting data from another API and re-format it.
@martpie You might want to check out this comment: https://github.com/zeit/next.js/issues/9524#issuecomment-589772756
Next-gen Static Site Generation (SSG) support has been released as stable in Next.js 9.3!
This release also includes support for "Preview Mode", or the ability to bypass the statically prerendered page and render the page on-demand for authorized users.
You can read more about it in our blog post. If you're more hands on, jump right into our docs!
Please post any questions to the Next.js GitHub Community!
This is so cool! Thanks for the hard work!
This new feature doesn't seem to work with saga and redux now
Most helpful comment
Next-gen Static Site Generation (SSG) support has been released as stable in Next.js 9.3!
This release also includes support for "Preview Mode", or the ability to bypass the statically prerendered page and render the page on-demand for authorized users.
You can read more about it in our blog post. If you're more hands on, jump right into our docs!