Skip to content

Commit 5c45d63

Browse files
committed
WIP
1 parent 2291cff commit 5c45d63

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

packages/runtime/docs/runtime.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ This is a description how the runtime internally works.
66

77
## Next.js milestones
88

9+
This contains a list of milestones where functionality in Next.js was changed that affects the runtime.
10+
11+
### [11.1.3-canary.96](https://github.com/vercel/next.js/releases/tag/v11.1.3-canary.96) - 23 Oct 2021
12+
13+
With this release a new manifest (`*.nft.json`) was introduced, so that each SSR page also contains the files it requires from third-party libraries.
14+
This basically runs a version of [`@vercel/nft`](https://www.npmjs.com/package/@vercel/nft) in Next.js instead of this builder.
15+
Therefore no file-tracing is required after this release.
16+
917
### [10.0.9-canary.4](https://github.com/vercel/next.js/releases/tag/v10.0.9-canary.4) - 09 Mar 2021
1018

1119
Beginning with this version the builder no longer sets the environment variable `NEXT_PRIVATE_TARGET=experimental-serverless-trace` and uses the default `target: server`.
@@ -19,6 +27,13 @@ The path of the server output folder also changed from `.serverless` to `.server
1927
### [9.0.4-canary.1](https://github.com/vercel/next.js/releases/tag/v9.0.4-canary.1) - 06 Aug 2019
2028

2129
Beginning with with this version, the builder uses `target: experimental-serverless-trace` instead of `target: serverless` when building Next.js.
30+
This means that instead of including the whole content of `node-modules` in the Lambda, only files that are actually used in code are included in the Lambda package (File-tracing).
31+
This is done via the [`@vercel/nft`](https://www.npmjs.com/package/@vercel/nft) package
32+
33+
### [7.0.3-alpha.0](https://github.com/vercel/next.js/releases/tag/v7.0.3-alpha.0) - 30 Oct 2018
34+
35+
All versions prior to this released are considered as legacy versions by the build tool.
36+
Legacy means that no file-tracing is active and everything from the `node_modules` is included in the Lambda.
2237

2338
## Procedure
2439

@@ -81,3 +96,83 @@ module.exports = function (...args) {
8196
return finalConfig;
8297
};
8398
```
99+
100+
### 3. Build Next.js
101+
102+
Building Next.js is simply running `next build` which produces a bunch of files that are written to the `.next` folder.
103+
104+
The following files are then used in the further process:
105+
106+
- Routes manifest
107+
- Images manifest
108+
- prerender manifest
109+
Prerendered routes emit a `.html` file but should not be treated as a static page.
110+
Lazily prerendered routes have a fallback `.html` file on newer Next.js versions so we need to also not treat it as a static page here.
111+
112+
### 4. Building Routes
113+
114+
The following things are extracted from the routes manifest:
115+
116+
- redirects
117+
- rewrites
118+
- dataroutes (available at `/_next/data`) for both dynamic SSG and SSP pages.
119+
- Can also have a nextLocale
120+
121+
### 5. Create image config
122+
123+
The image config is created from the Images manifest.
124+
125+
### 6. Build Lambdas
126+
127+
#### Important variables
128+
129+
- `pagesDir`
130+
Path to the server (or serverless) directory inside the `.next folder`
131+
- `pages`
132+
Contains a list of all `.js` files exported in the `pagesDir`.
133+
Has at least 1 entry (`_error.js`).
134+
- `staticPageFiles`
135+
Container a list of all `.html` files exported in the `pagesDir`
136+
- `staticPages`
137+
- `dynamicPages`
138+
Contains all SSR pages that have a dynamic pattern in its path (e.g. `[someId].js`)
139+
- `pseudoLayers`
140+
- `apiPseudoLayers`
141+
- `nonLambdaSsgPages`
142+
- `apiLambdaGroups`
143+
- `pageLambdaGroups`
144+
145+
First the static output (prerendered HTML pages `.html`) is analyzed.
146+
They are categorized into static routes (e.g. `/test`) and dynamic pages (`/[slug]`).
147+
148+
Then it is determined if the 404 page is static (prerendered) or dynamic (SSR).
149+
150+
Each static route from the prerender manifest is then checked if it can be added to `nonLambdaSsgPages`.
151+
152+
#### 6.x Tracing
153+
154+
> Tracing is only executed for Node.js versions `>9.0.4-canary.1`
155+
156+
Then the tracing is executed.
157+
158+
For this every page from `pages` is categorized into `apiPages` or `nonApiPages`.
159+
Only pages that are not already in `nonLambdaSsgPages` are added to `nonApiPages`.
160+
161+
Then nft is executed for both the `apiPages` and `nonApiPages`.
162+
163+
From that the traced files are collected into `tracedFiles` and `apiTracedFiles`.
164+
Then a pseudoLayer is created from `tracedFiles` and `apiTracedFiles`, which contain the dependencies of the pages and apiPages.
165+
166+
A pseudoLayer is an object that contains for each filePath the compressed buffer of the original file (PseudoFile) or the information about the symlink of the file (PseudoSymbolicLink).
167+
The created pseudoLayers are then pushed to `pseudoLayers` and `apiPseudoLayers`
168+
169+
#### 6.x Creating serverless functions
170+
171+
- **Shared Lambdas**
172+
Every page in `pages` (that is not `_app.js` or `_document.js`) is assigned to a LambdaGroup.
173+
If the page is already in `nonLambdaSsgPages` it is not added to the Lambda.
174+
A LambdaGroup is a collection of multiple pages or ApiPages that can be combined into a single Lambda (Which reduces the total number of Lambdas needed for serving the app.)
175+
A LambdaGroup has the name of the form `__NEXT_PAGE_LAMBDA_<GroupIndex>` for pages and `__NEXT_API_LAMBDA_<GroupIndex>` for apiPages.
176+
The aim is that each LambdaGroup stays below 50mb (Compressed code size limit from AWS Lambda), so when a LambdaGroup exceeds this limit, a new group is crated.
177+
178+
For each page is then a new route is added to `dynamicPageLambdaRoutes`

packages/runtime/src/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,10 @@ export async function build({
471471
env.NEXT_PRIVATE_TARGET = 'experimental-serverless-trace';
472472
}
473473

474+
/* ---------------------------------------------------------------------------
475+
* Build Next.js
476+
* -------------------------------------------------------------------------*/
477+
474478
if (buildCommand) {
475479
// Add `node_modules/.bin` to PATH
476480
const nodeBinPath = await getNodeBinPath({ cwd: entryPath });
@@ -575,6 +579,10 @@ export async function build({
575579
.replace(/\/+$/, '');
576580
}
577581

582+
/* ---------------------------------------------------------------------
583+
* DataRoutes
584+
* -------------------------------------------------------------------*/
585+
578586
if (routesManifest.dataRoutes) {
579587
// Load the /_next/data routes for both dynamic SSG and SSP pages.
580588
// These must be combined and sorted to prevent conflicts
@@ -673,6 +681,10 @@ export async function build({
673681
}
674682
}
675683

684+
/* ---------------------------------------------------------------------------
685+
* Image Config
686+
* -------------------------------------------------------------------------*/
687+
676688
if (imagesManifest) {
677689
switch (imagesManifest.version) {
678690
case 1: {
@@ -733,6 +745,10 @@ export async function build({
733745

734746
const userExport = await getExportStatus(entryPath);
735747

748+
/* ---------------------------------------------------------------------------
749+
* Build next export (Statically exported Next.js app)
750+
* -------------------------------------------------------------------------*/
751+
736752
if (userExport) {
737753
const exportIntent = await getExportIntent(entryPath);
738754
const { trailingSlash = false } = exportIntent || {};
@@ -889,7 +905,14 @@ export async function build({
889905
let static404Page: string | undefined;
890906
let page404Path = '';
891907

908+
/* ---------------------------------------------------------------------------
909+
* Build with SSR
910+
* -------------------------------------------------------------------------*/
911+
892912
if (isLegacy) {
913+
/* -------------------------------------------------------------------------
914+
* Build Legacy
915+
* -----------------------------------------------------------------------*/
893916
const filesAfterBuild = await glob('**', entryPath);
894917

895918
debug('Preparing serverless function files...');
@@ -983,6 +1006,10 @@ export async function build({
9831006
})
9841007
);
9851008
} else {
1009+
/* -------------------------------------------------------------------------
1010+
* Build serverless
1011+
* -----------------------------------------------------------------------*/
1012+
9861013
debug('Preparing serverless function files...');
9871014
const pagesDir = path.join(
9881015
entryPath,

0 commit comments

Comments
 (0)