Next.js is the fastest-growing framework. Since its creation in 2016, 12 updates have already been released, each of which the company has called “the biggest.” On October 25, Vercel (the company that owns Next.js) will unveil a new, 13th release, which, of course, will once again be “the biggest.” However, this article isn’t specifically about that release, but rather about a truly new process for the company.
In May of this year, Next.js unexpectedly published an RFC (request for comments) on its blog. It primarily discusses a new abstraction - layouts - as well as a host of related changes aimed at speeding up development, improving DX, and standardizing through the creation of new conventions. This working proposal definitely deserves attention, both because of its complexity for the framework and because it literally describes what it will look like in the future.
Background
A Request for Comments (RFC) is an official document developed by the Internet Engineering Task Force (IETF) that describes specifications for a specific technology. When an RFC is ratified, it becomes an official standards document [source].
Many libraries have similar RFCs, including React (https://github.com/reactjs/rfcs/), though full-fledged press releases are rarely written for them. Next.js outlined its vision by publishing a blog post five months ago and updating it in September. A discussion was also created on GitHub, where developers were invited to share their wishes and feedback.
This request is being called the biggest update to Next.js. And that’s probably true. The proposal is to change the application structure and introduce new abstractions, but let’s take it one step at a time.
Structure
It is proposed that all pages be stored in the “app” folder. Previously, they were stored in the “pages” directory; this folder will continue to function, but with some limitations. Initially, Next.js will process pages from both directories to maintain backward compatibility and allow for a gradual migration of pages. There is some debate regarding the folder name, as this name may already be in use within the application. It is quite likely that it will be renamed by the time of release.
Another change in naming concerns page names and their placement rules. Previously, there were two options: inside a folder with an index file (/about/index.js) or as a standalone file (/about.js). However, regardless of the option chosen, the page was always rendered as a file (/about.html). The new standard proposes creating a new folder for each page containing a page.js file (/about/page.js).
Layout
Next.js uses a number of abstractions that are automatically bound to the application - these are _app, _document, and _middleware. Middleware was added in version 12 as a test API, and in recent minor releases it was modified and renamed to middleware (without the underscore at the beginning). It is proposed to remove _app and _document, which are used for document and template rendering for all pages. Their role will be taken over by a new abstraction, which is the primary focus of this proposal: layout.
The difference between layout and _document is that styles do not currently work in layout. This issue will be partially resolved by another RFC dedicated to adding support for global styles.
Layouts are divided into root layouts, stored at the top level of the app directory, and additional layouts, stored in subdirectories. The root layout will describe the main markup - html, head, and body - effectively replacing _document. Additional layouts will describe templates within the body for nested pages.
A nice feature of layouts is that you can call getStaticProps and getServerSideProps (to retrieve data during the build phase or when rendering the page on the server) and pass the necessary data to each nested page. Previously, you could only call getInitialProps in _app, though this was not recommended.
Loaders
Rendering some pages, especially in server-side rendering mode and when fetching data, can take a long time. By default, the user sees a blank white screen during this time. This ruins the user experience, and if it takes too long (more than 3 seconds), it often leads to user churn. To make the user experience more pleasant in such cases, it’s worth using loaders and skeletons, which will create the appearance of activity and site availability.
In React, all lazy-loaded elements can be wrapped in Suspense. In Next.js, it’s recommended to create a loading.js file containing the loading component. Ultimately, this will be rendered using Suspense as well, but the page code won’t be cluttered with multiple wrappers.
It will be interesting to see how this functionality works for search engine crawlers (after all, without this, Next.js would immediately serve the static content, and the crawler could scan the site without any issues).
Error Pages
Currently, in Next.js, you can create 404.js, 502.js, and _error.js files for errors in the root directory of the pages. That is, in the static version, there is only one error page for the entire application. This was a problem, among other things, for multilingual sites, where this page needed to be localized in some way. There were also limitations on creating different error pages for sections (for example, for a blog with recent posts and a button to return to the blog’s homepage).
Going forward, it is proposed to create an error.js file for any directory, which will apply to all nested pages.
Grouping Pages
It is not uncommon for pages at the same level to use two different templates or error pages, for example, one set for the application’s functionality and another for product pages. This issue will be resolved in the future through page groups. Pages are grouped into a new subdirectory, and the group name is enclosed in parentheses “(product)”.
If you create groups at the top level of the application, you can use different root layouts within them.
Intercepting Routes
This functionality is based on how social networks work, where clicking on a news item opens a modal window, and when you share a link, the post opens in full-screen mode. This functionality works by intercepting transitions within the directory.
The names of such routes begin with “(..)”; the number of such parentheses at the beginning of the file indicates how far up the directory tree you need to go to reach the desired route. For example, to intercept photos (/photo/) when opening them from an article page (/blog/post-name/), you need to create a directory named(..)(..)photo within the article’s directory. You can define a modal window there, and when navigating from the article page, that modal will open. If you share a link or reload the page, the photo will open as a regular page.
Parallel Routes
Such routes can be used for pages consisting of two complex and unrelated segments. For example, if a page consists of a blog in the top half and an FAQ in the bottom half.
For such a page, you’ll need to create a directory containing layout.js and the segments it will consist of. To create segments, create a subdirectory whose name starts with “@” (e.g., @posts and @faq). Then, these segments will be available as props in the layout and can be embedded into the appropriate parts of the markup.
There can be subpages within segments, and when navigating to them, the segment to which they belong will be replaced in the layout. That is, for example, you can create an article page (/blog/@posts/some-post), and when navigating to it, the @posts segment will be replaced by this page, while the @faq segment will remain unchanged.
However, upon reloading, only the current page is displayed (the @faq segment disappears). This is likely a bug, but we won’t know for sure until the full release of the product.
React.js Features
The Next.js team always prepares for future React.js releases in advance. For example, support for React v18 was added even before the official release of the version, and server components began testing even before their final design was finalized. In the new proposal, in addition to Next.js functionality, server components are also described, which will now be fully integrated into the process.
By default, all pages will be rendered as server components. It is also proposed to name client-side and server-side files with the extensions .client.js and .server.js. That said, React has not yet finalized exactly how server-side and client-side components will be distinguished, but this approach was the most popular, and Next decided to standardize on it with the caveat that, in the event of changes, it will be adjusted according to accepted conventions.
Conclusions
The Next.js team decided to completely overhaul the application architecture by introducing a range of new abstractions and phasing out the old ones. These bold changes have the potential to solve many of the challenges developers face. If all these changes are adopted and work as described, this will mark another major update to the framework and open up significant potential for further development.
A basic example of the functionality described in this article can be found on the article’s website; the code is available on GitHub. A much more illustrative (and high-quality) example is shown in a tweet from Vercel.
On October 25 at 7:30 PM CET (8:30 PM Moscow Time), the Vercel team will host a conference to present the new Next.js release. This RFC will certainly be discussed there, but whether it will be included in the upcoming 13th version as ready-to-use functionality remains to be seen.