From 2d0fd341a3be4091a379f1498817c1c781157e52 Mon Sep 17 00:00:00 2001 From: kaykdm <34934746+kaykdm@users.noreply.github.com> Date: Wed, 12 Jan 2022 04:46:18 +0900 Subject: [PATCH 01/12] Fix broken yarn pnp (#32867) x-ref [#31552 ](https://github.com/vercel/next.js/issues/31552) x-ref https://github.com/vercel/next.js/issues/32115 x-ref https://github.com/vercel/next.js/issues/32546 x-ref https://github.com/vercel/next.js/issues/32721 Since this PR https://github.com/vercel/next.js/pull/31455 is merged, `enhanced-resolve` dependency's resolved field is changed which caused broken yarn pnp. I am not sure how this field has been changed or this is intentional or not When I install webpack locally, `enhanced-resolve`'s resolved field in lock file is always `registry.yarnpkg.com` not `codeload.github.com` ## Bug - [x] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `yarn lint` Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com> Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com> --- packages/next/compiled/webpack/bundle5.js | 290 ++---------------- .../with-google/manifest-snapshot.json | 4 +- yarn.lock | 3 +- 3 files changed, 25 insertions(+), 272 deletions(-) diff --git a/packages/next/compiled/webpack/bundle5.js b/packages/next/compiled/webpack/bundle5.js index 1ed5d251ff7af..8b99e94c26a0b 100644 --- a/packages/next/compiled/webpack/bundle5.js +++ b/packages/next/compiled/webpack/bundle5.js @@ -129584,56 +129584,44 @@ class OperationMergerBackend { * @param {any} providerContext call context for the provider methods */ constructor(provider, syncProvider, providerContext) { - const activeAsyncOperations = new Map(); + this._provider = provider; + this._syncProvider = syncProvider; + this._providerContext = providerContext; + this._activeAsyncOperations = new Map(); - this.provide = provider + this.provide = this._provider ? (path, options, callback) => { if (typeof options === "function") { callback = options; options = undefined; } if (options) { - return provider.call(providerContext, path, options, callback); + return this._provider.call( + this._providerContext, + path, + options, + callback + ); } if (typeof path !== "string") { callback(new TypeError("path must be a string")); return; } - let callbacks = activeAsyncOperations.get(path); + let callbacks = this._activeAsyncOperations.get(path); if (callbacks) { callbacks.push(callback); return; } - activeAsyncOperations.set(path, (callbacks = [callback])); - provider.call(providerContext, path, (err, result) => { - activeAsyncOperations.delete(path); + this._activeAsyncOperations.set(path, (callbacks = [callback])); + provider(path, (err, result) => { + this._activeAsyncOperations.delete(path); runCallbacks(callbacks, err, result); }); } : null; - this.provideSync = syncProvider + this.provideSync = this._syncProvider ? (path, options) => { - return syncProvider.call(providerContext, path, options); - } - : null; - - this.provideCustom = provider - ? (provider, providerContext, path, callback) => { - let callbacks = activeAsyncOperations.get(path); - if (callbacks) { - callbacks.push(callback); - return; - } - activeAsyncOperations.set(path, (callbacks = [callback])); - provider.call(providerContext, path, (err, result) => { - activeAsyncOperations.delete(path); - runCallbacks(callbacks, err, result); - }); - } - : null; - this.provideCustomSync = syncProvider - ? (syncProvider, providerContext, path) => { - return syncProvider.call(providerContext, path); + return this._syncProvider.call(this._providerContext, path, options); } : null; } @@ -129698,11 +129686,6 @@ class CacheBackend { this.provide = provider ? this.provide.bind(this) : null; this.provideSync = syncProvider ? this.provideSync.bind(this) : null; - - this.provideCustom = provider ? this.provideCustom.bind(this) : null; - this.provideCustomSync = syncProvider - ? this.provideCustomSync.bind(this) - : null; } provide(path, options, callback) { @@ -129797,74 +129780,6 @@ class CacheBackend { return result; } - provideCustom(provider, providerContext, path, callback) { - // When in sync mode we can move to async mode - if (this._mode === STORAGE_MODE_SYNC) { - this._enterAsyncMode(); - } - - // Check in cache - let cacheEntry = this._data.get(path); - if (cacheEntry !== undefined) { - if (cacheEntry.err) return nextTick(callback, cacheEntry.err); - return nextTick(callback, null, cacheEntry.result); - } - - // Check if there is already the same operation running - let callbacks = this._activeAsyncOperations.get(path); - if (callbacks !== undefined) { - callbacks.push(callback); - return; - } - this._activeAsyncOperations.set(path, (callbacks = [callback])); - - // Run the operation - provider.call(providerContext, path, (err, result) => { - this._activeAsyncOperations.delete(path); - this._storeResult(path, err, result); - - // Enter async mode if not yet done - this._enterAsyncMode(); - - runCallbacks(callbacks, err, result); - }); - } - - provideCustomSync(provider, providerContext, path) { - // In sync mode we may have to decay some cache items - if (this._mode === STORAGE_MODE_SYNC) { - this._runDecays(); - } - - // Check in cache - let cacheEntry = this._data.get(path); - if (cacheEntry !== undefined) { - if (cacheEntry.err) throw cacheEntry.err; - return cacheEntry.result; - } - - // Get all active async operations - // This sync operation will also complete them - const callbacks = this._activeAsyncOperations.get(path); - this._activeAsyncOperations.delete(path); - - // Run the operation - // When in idle mode, we will enter sync mode - let result; - try { - result = provider.call(providerContext, path); - } catch (err) { - this._storeResult(path, err, undefined); - this._enterSyncModeWhenIdle(); - if (callbacks) runCallbacks(callbacks, err, undefined); - throw err; - } - this._storeResult(path, undefined, result); - this._enterSyncModeWhenIdle(); - if (callbacks) runCallbacks(callbacks, undefined, result); - return result; - } - purge(what) { if (!what) { if (this._mode !== STORAGE_MODE_IDLE) { @@ -130017,10 +129932,8 @@ module.exports = class CachedInputFileSystem { this.fileSystem ); const stat = this._statBackend.provide; - const customStat = this._statBackend.provideCustom; this.stat = /** @type {FileSystem["stat"]} */ (stat); const statSync = this._statBackend.provideSync; - const customStatSync = this._statBackend.provideCustomSync; this.statSync = /** @type {SyncFileSystem["statSync"]} */ (statSync); this._readdirBackend = createBackend( @@ -130036,161 +129949,8 @@ module.exports = class CachedInputFileSystem { this._readFileBackend = createBackend( duration, - this.fileSystem.readFile && - this.fileSystem.fstat && - this.fileSystem.read && - this.fileSystem.open && - this.fileSystem.close && - customStat - ? /** - * @this {{ fstat: NonNullable, readFile: NonNullable, open: NonNullable, read: NonNullable, close: NonNullable }} - */ - function (path, options, callback) { - if (typeof options === "function") { - callback = options; - options = undefined; - } - if (typeof options === "object") - return this.readFile(path, options, callback); - this.open(path, "r", (err, fd) => { - if (err) return callback(err); - if (typeof fd !== "number") - return callback(new Error("fd must be a number")); - customStat( - (path, callback) => this.fstat(fd, callback), - null, - path, - (err, stats) => { - if (err) return callback(err); - if (stats.size > 0 && stats.size < 128 * 1024) { - let remaining = stats.size + 1; - const buffer = Buffer.allocUnsafe(remaining); - const afterRead = (err, bytesRead) => { - if (err) { - return this.close(fd, () => { - callback(err); - }); - } - remaining -= bytesRead; - if (bytesRead === 0 || remaining === 1) { - this.close(fd, err => { - if (err) return callback(err); - return callback( - null, - buffer.slice(0, buffer.length - remaining) - ); - }); - } else if (remaining === 0) { - // The file size has changed from the cached info - // We keep reading until the end is found - let buf = Buffer.allocUnsafe(16 * 1024); - let bufPos = 0; - const buffers = [buffer]; - const afterUnknownRead = (err, bytesRead) => { - if (err) { - return this.close(fd, () => { - callback(err); - }); - } - bufPos += bytesRead; - if (bytesRead === 0) { - if (bufPos > 0) buffers.push(buf.slice(0, bufPos)); - this.close(fd, err => { - if (err) return callback(err); - return callback(null, Buffer.concat(buffers)); - }); - } else { - if (bufPos === buf.length) { - buffers.push(buf); - buf = Buffer.allocUnsafe(16 * 1024); - bufPos = 0; - } - this.read( - fd, - buf, - bufPos, - buf.length - bufPos, - -1, - afterUnknownRead - ); - } - }; - this.read( - fd, - buf, - bufPos, - buf.length - bufPos, - -1, - afterUnknownRead - ); - } else { - this.read( - fd, - buffer, - stats.size - remaining, - remaining + 1, - -1, - afterRead - ); - } - }; - this.read(fd, buffer, 0, remaining, -1, afterRead); - } else { - this.readFile(fd, options, (err, buffer) => { - this.close(fd, closeErr => { - if (err) return callback(err); - if (closeErr) return callback(closeErr); - callback(null, buffer); - }); - }); - } - } - ); - }); - } - : this.fileSystem.readFile, - this.fileSystem.readFileSync && - this.fileSystem.fstatSync && - this.fileSystem.readSync && - this.fileSystem.openSync && - this.fileSystem.closeSync && - customStatSync - ? /** - * @this {{ fstatSync: NonNullable, readFileSync: NonNullable, openSync: NonNullable, readSync: NonNullable, closeSync: NonNullable }} - */ - function (path, options) { - if (typeof options === "object") - return this.readFileSync(path, options); - const fd = this.openSync(path, "r"); - if (typeof fd !== "number") throw new Error("fd must be a number"); - const stats = customStatSync(() => this.fstatSync(fd), null, path); - if (stats.size > 0 && stats.size < 128 * 1024) { - let remaining = stats.size; - const buffer = Buffer.allocUnsafe(remaining); - try { - let bytesRead = this.readSync(fd, buffer, 0, remaining, -1); - remaining -= bytesRead; - while (bytesRead !== 0 && remaining !== 0) { - bytesRead = this.readSync( - fd, - buffer, - stats.size - remaining, - remaining, - -1 - ); - remaining -= bytesRead; - } - return buffer; - } finally { - this.closeSync(fd); - } - } else { - const buffer = this.readFileSync(fd); - this.closeSync(fd); - return buffer; - } - } - : this.fileSystem.readFileSync, + this.fileSystem.readFile, + this.fileSystem.readFileSync, this.fileSystem ); const readFile = this._readFileBackend.provide; @@ -131829,11 +131589,7 @@ const { /** * @typedef {Object} FileSystem - * @property {(function(string | number, FileSystemCallback): void) & function(string | number, object, FileSystemCallback): void} readFile - * @property {(function(string, string | number, FileSystemCallback): void) & function(string, string | number, string | number, FileSystemCallback): void=} open - * @property {(function(number, FileSystemCallback): void) & function(number, object, FileSystemCallback): void=} fstat - * @property {function(number, Buffer | Uint8Array, number, number, number, function(PossibleFileSystemError & Error | null | undefined, number=): void): void=} read - * @property {function(number, function(PossibleFileSystemError & Error | null | undefined): void): void=} close + * @property {(function(string, FileSystemCallback): void) & function(string, object, FileSystemCallback): void} readFile * @property {(function(string, FileSystemCallback<(Buffer | string)[] | FileSystemDirent[]>): void) & function(string, object, FileSystemCallback<(Buffer | string)[] | FileSystemDirent[]>): void} readdir * @property {((function(string, FileSystemCallback): void) & function(string, object, FileSystemCallback): void)=} readJson * @property {(function(string, FileSystemCallback): void) & function(string, object, FileSystemCallback): void} readlink @@ -131843,11 +131599,7 @@ const { /** * @typedef {Object} SyncFileSystem - * @property {function(string | number, object=): Buffer | string} readFileSync - * @property {function(string, string | number, string | number=): number=} openSync - * @property {function(number, object=): FileSystemStats=} fstatSync - * @property {function(number, Buffer | Uint8Array, number, number, number): number=} readSync - * @property {function(number): void=} closeSync + * @property {function(string, object=): Buffer | string} readFileSync * @property {function(string, object=): (Buffer | string)[] | FileSystemDirent[]} readdirSync * @property {(function(string, object=): object)=} readJsonSync * @property {function(string, object=): Buffer | string} readlinkSync diff --git a/test/integration/font-optimization/fixtures/with-google/manifest-snapshot.json b/test/integration/font-optimization/fixtures/with-google/manifest-snapshot.json index c0ffadb9fa779..0ccaf464125cb 100644 --- a/test/integration/font-optimization/fixtures/with-google/manifest-snapshot.json +++ b/test/integration/font-optimization/fixtures/with-google/manifest-snapshot.json @@ -1,11 +1,11 @@ [ { "url": "https://fonts.googleapis.com/css?family=Voces", - "content": "@font-face{font-family:'Voces';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/voces/v15/-F6_fjJyLyU8d7PGDmk.woff) format('woff')}@font-face{font-family:'Voces';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/voces/v15/-F6_fjJyLyU8d7PIDm_6pClI_ik.woff2) format('woff2');unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:'Voces';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/voces/v15/-F6_fjJyLyU8d7PGDm_6pClI.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}" + "content": "@font-face{font-family:'Voces';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/voces/v18/-F6_fjJyLyU8d7PGDmk.woff) format('woff')}@font-face{font-family:'Voces';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/voces/v18/-F6_fjJyLyU8d7PIDm_6pClI_ik.woff2) format('woff2');unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:'Voces';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/voces/v18/-F6_fjJyLyU8d7PGDm_6pClI.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}" }, { "url": "https://fonts.googleapis.com/css2?family=Modak", - "content": "@font-face{font-family:'Modak';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/modak/v8/EJRYQgs1XtIEsnME.woff) format('woff')}@font-face{font-family:'Modak';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/modak/v8/EJRYQgs1XtIEskMB-hR77LKVTy8.woff2) format('woff2');unicode-range:U+0900-097F,U+1CD0-1CF6,U+1CF8-1CF9,U+200C-200D,U+20A8,U+20B9,U+25CC,U+A830-A839,U+A8E0-A8FB}@font-face{font-family:'Modak';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/modak/v8/EJRYQgs1XtIEskMO-hR77LKVTy8.woff2) format('woff2');unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:'Modak';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/modak/v8/EJRYQgs1XtIEskMA-hR77LKV.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}" + "content": "@font-face{font-family:'Modak';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/modak/v16/EJRYQgs1XtIEsnME.woff) format('woff')}@font-face{font-family:'Modak';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/modak/v16/EJRYQgs1XtIEskMB-hR77LKVTy8.woff2) format('woff2');unicode-range:U+0900-097F,U+1CD0-1CF6,U+1CF8-1CF9,U+200C-200D,U+20A8,U+20B9,U+25CC,U+A830-A839,U+A8E0-A8FB}@font-face{font-family:'Modak';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/modak/v16/EJRYQgs1XtIEskMO-hR77LKVTy8.woff2) format('woff2');unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:'Modak';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/s/modak/v16/EJRYQgs1XtIEskMA-hR77LKV.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}" }, { "url": "https://fonts.googleapis.com/css2?family=Roboto:wght@700", diff --git a/yarn.lock b/yarn.lock index e11c7c225f34b..2667122b971e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8809,7 +8809,8 @@ enhanced-resolve@^4.3.0: enhanced-resolve@^5.8.3: version "5.8.3" - resolved "https://codeload.github.com/webpack/enhanced-resolve/tar.gz/a7c161eeb141bfc7fda375df36c13df006a8cf76" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" + integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" From 57a87050e77e9398842a78e43d48b26542642330 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 11 Jan 2022 14:40:03 -0600 Subject: [PATCH 02/12] Add util for normalizing errors (#33159) * JSON.stringify generic errors * Add util for normalizing errors * lint-fix * Add better error for null case as well Co-authored-by: Michael Ozeryansky --- errors/threw-undefined.md | 18 ++- packages/next/client/index.tsx | 6 +- packages/next/lib/eslint/runLintCheck.ts | 4 +- packages/next/lib/is-error.ts | 28 +++++ packages/next/lib/is-plain-object.ts | 12 ++ packages/next/lib/is-serializable-props.ts | 15 +-- packages/next/server/base-server.ts | 27 ++--- packages/next/server/dev/hot-reloader.ts | 7 +- packages/next/server/dev/next-dev-server.ts | 6 +- packages/next/shared/lib/router/router.ts | 4 +- .../acceptance/ReactRefreshLogBox.test.ts | 109 ++++++++++++++++++ .../client-navigation/test/rendering.js | 2 +- 12 files changed, 187 insertions(+), 51 deletions(-) create mode 100644 packages/next/lib/is-plain-object.ts diff --git a/errors/threw-undefined.md b/errors/threw-undefined.md index 0d4129ef4f115..4804488cafc49 100644 --- a/errors/threw-undefined.md +++ b/errors/threw-undefined.md @@ -1,9 +1,21 @@ -# Threw undefined in render +# Threw `undefined`/`null` #### Why This Error Occurred -Somewhere in your code you `throw` an `undefined` value. Since this isn't a valid error there isn't a stack trace. We show this error instead to let you know what to look for. +Somewhere in your code you `throw` an `undefined` or `null` value. Since this isn't a valid error there isn't a stack trace. We show this error instead to let you know what to look for. + +```js +function getData() { + let error + throw error +} + +function Page() { + const error = data?.error || null + throw error +} +``` #### Possible Ways to Fix It -Look in your pages and find where an error could be throwing `undefined` +Look in your pages and find where an error could be throwing `undefined` or `null` values and ensure `new Error()` is used instead. diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 2b5fa798bdc74..0029830836994 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -32,7 +32,7 @@ import PageLoader, { StyleSheetTuple } from './page-loader' import measureWebVitals from './performance-relayer' import { RouteAnnouncer } from './route-announcer' import { createRouter, makePublicRouterInstance } from './router' -import isError from '../lib/is-error' +import { getProperError } from '../lib/is-error' import { trackWebVitalMetric } from './vitals' import { RefreshContext } from './rsc/refresh' @@ -339,7 +339,7 @@ export async function initNext(opts: { webpackHMR?: any } = {}) { } } catch (error) { // This catches errors like throwing in the top level of a module - initialErr = isError(error) ? error : new Error(error + '') + initialErr = getProperError(error) } if (process.env.NODE_ENV === 'development') { @@ -439,7 +439,7 @@ export async function render(renderingProps: RenderRouteInfo): Promise { try { await doRender(renderingProps) } catch (err) { - const renderErr = err instanceof Error ? err : new Error(err + '') + const renderErr = getProperError(err) // bubble up cancelation errors if ((renderErr as Error & { cancelled?: boolean }).cancelled) { throw renderErr diff --git a/packages/next/lib/eslint/runLintCheck.ts b/packages/next/lib/eslint/runLintCheck.ts index a6d25c2e77e18..33b63b9492a2f 100644 --- a/packages/next/lib/eslint/runLintCheck.ts +++ b/packages/next/lib/eslint/runLintCheck.ts @@ -18,7 +18,7 @@ import { isYarn } from '../is-yarn' import * as Log from '../../build/output/log' import { EventLintCheckCompleted } from '../../telemetry/events/build' -import isError from '../is-error' +import isError, { getProperError } from '../is-error' type Config = { plugins: string[] @@ -221,7 +221,7 @@ async function lint( ) return null } else { - throw new Error(err + '') + throw getProperError(err) } } } diff --git a/packages/next/lib/is-error.ts b/packages/next/lib/is-error.ts index a7ef9bf44bc24..4560fa7e928e9 100644 --- a/packages/next/lib/is-error.ts +++ b/packages/next/lib/is-error.ts @@ -1,3 +1,5 @@ +import { isPlainObject } from './is-plain-object' + // We allow some additional attached properties for Errors export interface NextError extends Error { type?: string @@ -11,3 +13,29 @@ export default function isError(err: unknown): err is NextError { typeof err === 'object' && err !== null && 'name' in err && 'message' in err ) } + +export function getProperError(err: unknown): Error { + if (isError(err)) { + return err + } + + if (process.env.NODE_ENV === 'development') { + // provide better error for case where `throw undefined` + // is called in development + if (typeof err === 'undefined') { + return new Error( + 'An undefined error was thrown, ' + + 'see here for more info: https://nextjs.org/docs/messages/threw-undefined' + ) + } + + if (err === null) { + return new Error( + 'A null error was thrown, ' + + 'see here for more info: https://nextjs.org/docs/messages/threw-undefined' + ) + } + } + + return new Error(isPlainObject(err) ? JSON.stringify(err) : err + '') +} diff --git a/packages/next/lib/is-plain-object.ts b/packages/next/lib/is-plain-object.ts new file mode 100644 index 0000000000000..1ab0d87e73919 --- /dev/null +++ b/packages/next/lib/is-plain-object.ts @@ -0,0 +1,12 @@ +export function getObjectClassLabel(value: any): string { + return Object.prototype.toString.call(value) +} + +export function isPlainObject(value: any): boolean { + if (getObjectClassLabel(value) !== '[object Object]') { + return false + } + + const prototype = Object.getPrototypeOf(value) + return prototype === null || prototype === Object.prototype +} diff --git a/packages/next/lib/is-serializable-props.ts b/packages/next/lib/is-serializable-props.ts index 058bfcd386450..1202d4d98882d 100644 --- a/packages/next/lib/is-serializable-props.ts +++ b/packages/next/lib/is-serializable-props.ts @@ -1,17 +1,6 @@ -const regexpPlainIdentifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/ - -function getObjectClassLabel(value: any): string { - return Object.prototype.toString.call(value) -} +import { isPlainObject, getObjectClassLabel } from './is-plain-object' -function isPlainObject(value: any): boolean { - if (getObjectClassLabel(value) !== '[object Object]') { - return false - } - - const prototype = Object.getPrototypeOf(value) - return prototype === null || prototype === Object.prototype -} +const regexpPlainIdentifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/ export function isSerializableProps( page: string, diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index e0feebf06e5b5..655826c9a0141 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -89,7 +89,7 @@ import { getUtils } from '../build/webpack/loaders/next-serverless-loader/utils' import { PreviewData } from 'next/types' import ResponseCache from './response-cache' import { parseNextUrl } from '../shared/lib/router/utils/parse-next-url' -import isError from '../lib/is-error' +import isError, { getProperError } from '../lib/is-error' import { getMiddlewareInfo } from './require' import { MIDDLEWARE_ROUTE } from '../lib/constants' import { run } from './web/sandbox' @@ -567,7 +567,7 @@ export default abstract class Server { if (this.minimalMode || this.renderOpts.dev) { throw err } - this.logError(isError(err) ? err : new Error(err + '')) + this.logError(getProperError(err)) res.statusCode = 500 res.end('Internal Server Error') } @@ -1225,7 +1225,7 @@ export default abstract class Server { return { finished: true } } - const error = isError(err) ? err : new Error(err + '') + const error = getProperError(err) console.error(error) res.statusCode = 500 this.renderError(error, req, res, parsed.pathname || '') @@ -2292,7 +2292,7 @@ export default abstract class Server { } } } catch (error) { - const err = isError(error) ? error : error ? new Error(error + '') : null + const err = getProperError(error) if (err instanceof NoFallbackError && bubbleNoFallback) { throw err } @@ -2313,7 +2313,7 @@ export default abstract class Server { if (isError(err)) err.page = page throw err } - this.logError(err || new Error(error + '')) + this.logError(getProperError(err)) } return response } @@ -2370,16 +2370,9 @@ export default abstract class Server { private async renderErrorToResponse( ctx: RequestContext, - _err: Error | null + err: Error | null ): Promise { const { res, query } = ctx - let err = _err - if (this.renderOpts.dev && !err && res.statusCode === 500) { - err = new Error( - 'An undefined error was thrown sometime during render... ' + - 'See https://nextjs.org/docs/messages/threw-undefined' - ) - } try { let result: null | FindComponentsResult = null @@ -2430,14 +2423,10 @@ export default abstract class Server { throw maybeFallbackError } } catch (error) { - const renderToHtmlError = isError(error) - ? error - : error - ? new Error(error + '') - : null + const renderToHtmlError = getProperError(error) const isWrappedError = renderToHtmlError instanceof WrappedBuildError if (!isWrappedError) { - this.logError(renderToHtmlError || new Error(error + '')) + this.logError(renderToHtmlError) } res.statusCode = 500 const fallbackComponents = await this.getFallbackErrorComponents() diff --git a/packages/next/server/dev/hot-reloader.ts b/packages/next/server/dev/hot-reloader.ts index 3f3ba14a94c4d..ec0d144b88614 100644 --- a/packages/next/server/dev/hot-reloader.ts +++ b/packages/next/server/dev/hot-reloader.ts @@ -39,7 +39,7 @@ import { NextConfigComplete } from '../config-shared' import { CustomRoutes } from '../../lib/load-custom-routes' import { DecodeError } from '../../shared/lib/utils' import { Span, trace } from '../../trace' -import isError from '../../lib/is-error' +import { getProperError } from '../../lib/is-error' import ws from 'next/dist/compiled/ws' const wsServer = new ws.Server({ noServer: true }) @@ -249,10 +249,7 @@ export default class HotReloader { try { await this.ensurePage(page, true) } catch (error) { - await renderScriptError( - pageBundleRes, - isError(error) ? error : new Error(error + '') - ) + await renderScriptError(pageBundleRes, getProperError(error)) return { finished: true } } diff --git a/packages/next/server/dev/next-dev-server.ts b/packages/next/server/dev/next-dev-server.ts index 2b1f95c9517ef..2ab5117a021e1 100644 --- a/packages/next/server/dev/next-dev-server.ts +++ b/packages/next/server/dev/next-dev-server.ts @@ -56,7 +56,7 @@ import { parseStack, } from 'next/dist/compiled/@next/react-dev-overlay/middleware' import * as Log from '../../build/output/log' -import isError from '../../lib/is-error' +import isError, { getProperError } from '../../lib/is-error' import { getMiddlewareRegex } from '../../shared/lib/router/utils/get-middleware-regex' import { isCustomErrorPage, isReservedPage } from '../../build/utils' @@ -538,7 +538,7 @@ export default class DevServer extends Server { return result } catch (error) { this.logErrorWithOriginalStack(error, undefined, 'client') - const err = isError(error) ? error : new Error(error + '') + const err = getProperError(error) ;(err as any).middleware = true const { request, response, parsedUrl } = params this.renderError(err, request, response, parsedUrl.pathname) @@ -591,7 +591,7 @@ export default class DevServer extends Server { return await super.run(req, res, parsedUrl) } catch (error) { res.statusCode = 500 - const err = isError(error) ? error : error ? new Error(error + '') : null + const err = getProperError(error) try { this.logErrorWithOriginalStack(err).catch(() => {}) return await this.renderError(err, req, res, pathname!, { diff --git a/packages/next/shared/lib/router/router.ts b/packages/next/shared/lib/router/router.ts index 0245de4740487..71bcc42d0ba58 100644 --- a/packages/next/shared/lib/router/router.ts +++ b/packages/next/shared/lib/router/router.ts @@ -16,7 +16,7 @@ import { isAssetError, markAssetError, } from '../../../client/route-loader' -import isError from '../../../lib/is-error' +import isError, { getProperError } from '../../../lib/is-error' import { denormalizePagePath } from '../../../server/denormalize-page-path' import { normalizeLocalePath } from '../i18n/normalize-locale-path' import mitt from '../mitt' @@ -1559,7 +1559,7 @@ export default class Router implements BaseRouter { return routeInfo } catch (err) { return this.handleRouteInfoError( - isError(err) ? err : new Error(err + ''), + getProperError(err), pathname, query, as, diff --git a/test/development/acceptance/ReactRefreshLogBox.test.ts b/test/development/acceptance/ReactRefreshLogBox.test.ts index 44ce8d9c6acd5..f730ed3b6113d 100644 --- a/test/development/acceptance/ReactRefreshLogBox.test.ts +++ b/test/development/acceptance/ReactRefreshLogBox.test.ts @@ -903,4 +903,113 @@ describe('ReactRefreshLogBox', () => { await cleanup() }) + + test('non-Error errors are handled properly', async () => { + const { session, cleanup } = await sandbox(next) + + await session.patch( + 'index.js', + ` + export default () => { + throw {'a': 1, 'b': 'x'}; + return ( +
hello
+ ) + } + ` + ) + + expect(await session.hasRedbox(true)).toBe(true) + expect(await session.getRedboxDescription()).toMatchInlineSnapshot( + `"Error: {\\"a\\":1,\\"b\\":\\"x\\"}"` + ) + + // fix previous error + await session.patch( + 'index.js', + ` + export default () => { + return ( +
hello
+ ) + } + ` + ) + expect(await session.hasRedbox(false)).toBe(false) + await session.patch( + 'index.js', + ` + class Hello {} + + export default () => { + throw Hello + return ( +
hello
+ ) + } + ` + ) + expect(await session.hasRedbox(true)).toBe(true) + expect(await session.getRedboxDescription()).toContain( + `Error: class Hello {` + ) + + // fix previous error + await session.patch( + 'index.js', + ` + export default () => { + return ( +
hello
+ ) + } + ` + ) + expect(await session.hasRedbox(false)).toBe(false) + await session.patch( + 'index.js', + ` + export default () => { + throw "string error" + return ( +
hello
+ ) + } + ` + ) + expect(await session.hasRedbox(true)).toBe(true) + expect(await session.getRedboxDescription()).toMatchInlineSnapshot( + `"Error: string error"` + ) + + // fix previous error + await session.patch( + 'index.js', + ` + export default () => { + return ( +
hello
+ ) + } + ` + ) + expect(await session.hasRedbox(false)).toBe(false) + await session.patch( + 'index.js', + ` + export default () => { + throw null + return ( +
hello
+ ) + } + ` + ) + expect(await session.hasRedbox(true)).toBe(true) + expect(await session.getRedboxDescription()).toContain( + `Error: A null error was thrown` + ) + + await cleanup() + }) }) diff --git a/test/integration/client-navigation/test/rendering.js b/test/integration/client-navigation/test/rendering.js index b991454c2fa09..6e1055e4fde46 100644 --- a/test/integration/client-navigation/test/rendering.js +++ b/test/integration/client-navigation/test/rendering.js @@ -425,7 +425,7 @@ export default function (render, fetch, ctx) { const text = await getRedboxHeader(browser) expect(text).toContain( - 'An undefined error was thrown sometime during render...' + 'An undefined error was thrown, see here for more info:' ) }) }) From 0de84472eb565d5ecae1e6b71994f0cd46c8ecb9 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 11 Jan 2022 15:00:27 -0600 Subject: [PATCH 03/12] v12.0.8-canary.21 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- 15 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lerna.json b/lerna.json index fe8305ff972b9..3ca1cb71f6c95 100644 --- a/lerna.json +++ b/lerna.json @@ -17,5 +17,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.0.8-canary.20" + "version": "12.0.8-canary.21" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 70a0929f77458..0127d9a34558f 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 7a9b9a5fb0015..b67348b16aa5f 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.0.8-canary.20", + "@next/eslint-plugin-next": "12.0.8-canary.21", "@rushstack/eslint-patch": "^1.0.8", "@typescript-eslint/parser": "^5.0.0", "eslint-import-resolver-node": "^0.3.4", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index b78d53bf38fd7..a0053881f0761 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 73ae63b55e0ab..d7051cfae395b 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 335d20275d7e9..bdd760b3c2126 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index a1588be372c5a..ca4442879c0a2 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 9f294239f1d80..f349da7d93f0c 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 98725679a5e41..8c132bbf5cdbc 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 210c1a630bc02..9c8e8f754136b 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index b4a88194934a6..67e8bdc03e06f 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index cb0f3e2d570d0..45531e4b2b2b6 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "private": true, "scripts": { "build-native": "napi build --platform --cargo-name next_swc_napi native", diff --git a/packages/next/package.json b/packages/next/package.json index 25b03d27f49c9..9fd4d108fbddb 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -71,8 +71,8 @@ ] }, "dependencies": { - "@next/env": "12.0.8-canary.20", - "@next/react-refresh-utils": "12.0.8-canary.20", + "@next/env": "12.0.8-canary.21", + "@next/react-refresh-utils": "12.0.8-canary.21", "caniuse-lite": "^1.0.30001283", "jest-worker": "27.0.0-next.5", "node-fetch": "2.6.1", @@ -125,10 +125,10 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "1.2.1", "@napi-rs/triples": "1.0.3", - "@next/polyfill-module": "12.0.8-canary.20", - "@next/polyfill-nomodule": "12.0.8-canary.20", - "@next/react-dev-overlay": "12.0.8-canary.20", - "@next/swc": "12.0.8-canary.20", + "@next/polyfill-module": "12.0.8-canary.21", + "@next/polyfill-nomodule": "12.0.8-canary.21", + "@next/react-dev-overlay": "12.0.8-canary.21", + "@next/swc": "12.0.8-canary.21", "@peculiar/webcrypto": "1.1.7", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index fd8942d74e00f..6202691122cce 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 1254bdedf99e2..b31946fd03a29 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.0.8-canary.20", + "version": "12.0.8-canary.21", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", From 36eba95227214437f2d2dc616a0b3129a6e7315f Mon Sep 17 00:00:00 2001 From: Manny Becerra <39503964+mannybecerra@users.noreply.github.com> Date: Tue, 11 Jan 2022 17:55:35 -0800 Subject: [PATCH 04/12] Fixes #33153: Updating cross-references from master to main + canary (#33198) * copy cleanup in env. variables docs * copy cleanup in fast refresh docs * Supplements #33153 - updating existing cross-references to `master` branch to renamed default branch of `main` * Supplements #33153 - updating existing cross-references to `master` branch to renamed default branch of `main` Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- azure-pipelines.yml | 4 ++-- docs/api-reference/create-next-app.md | 2 +- examples/analyze-bundles/README.md | 2 +- examples/gh-pages/README.md | 2 +- examples/progressive-web-app/pages/index.js | 2 +- examples/with-apollo-and-redux/README.md | 2 +- examples/with-cypress/pages/index.js | 2 +- examples/with-docker/pages/index.js | 2 +- examples/with-elasticsearch/pages/index.js | 2 +- .../__tests__/__snapshots__/snapshot.tsx.snap | 8 ++++---- examples/with-jest-babel/pages/index.tsx | 2 +- .../with-jest/__tests__/__snapshots__/snapshot.tsx.snap | 8 ++++---- examples/with-jest/pages/index.tsx | 2 +- examples/with-knex/pages/index.js | 2 +- examples/with-mdbreact/pages/index.js | 2 +- examples/with-mongodb/pages/index.js | 2 +- examples/with-playwright/pages/index.js | 2 +- examples/with-rbx-bulma-pro/pages/index.js | 2 +- examples/with-react-bootstrap/pages/index.jsx | 2 +- examples/with-react-with-styles/README.md | 2 +- examples/with-reactstrap/pages/index.jsx | 2 +- examples/with-redux-persist/README.md | 2 +- examples/with-redux-saga/README.md | 2 +- examples/with-rematch/README.md | 2 +- examples/with-sitemap/pages/index.js | 2 +- examples/with-styled-jsx-postcss/README.md | 2 +- examples/with-supertokens/pages/index.js | 2 +- examples/with-tailwindcss/pages/index.tsx | 2 +- examples/with-typestyle/README.md | 2 +- lerna.json | 1 - packages/create-next-app/README.md | 2 +- packages/create-next-app/templates/default/pages/index.js | 2 +- .../create-next-app/templates/typescript/pages/index.tsx | 2 +- test/development/basic/tailwind-jit/pages/index.js | 2 +- 34 files changed, 40 insertions(+), 41 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 33c391bf3acf6..da56c8d77fc24 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,14 +10,14 @@ trigger: - docs - errors - examples - # Do not run Azure on `canary`, `master`, or release tags. This unnecessarily + # Do not run Azure on `canary`, `main`, or release tags. This unnecessarily # increases the backlog, and the change was already tested on the PR. branches: include: - '*' exclude: - canary - - master + - main - refs/tags/* pr: diff --git a/docs/api-reference/create-next-app.md b/docs/api-reference/create-next-app.md index 3a00e008ac086..f463840b88b91 100644 --- a/docs/api-reference/create-next-app.md +++ b/docs/api-reference/create-next-app.md @@ -25,7 +25,7 @@ yarn create next-app --typescript `create-next-app` comes with the following options: - **--ts, --typescript** - Initialize as a TypeScript project. -- **-e, --example [name]|[github-url]** - An example to bootstrap the app with. You can use an example name from the [Next.js repo](https://github.com/vercel/next.js/tree/master/examples) or a GitHub URL. The URL can use any branch and/or subdirectory. +- **-e, --example [name]|[github-url]** - An example to bootstrap the app with. You can use an example name from the [Next.js repo](https://github.com/vercel/next.js/tree/canary/examples) or a GitHub URL. The URL can use any branch and/or subdirectory. - **--example-path [path-to-example]** - In a rare case, your GitHub URL might contain a branch name with a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar). In this case, you must specify the path to the example separately: `--example-path foo/bar` - **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. To bootstrap using yarn we recommend running `yarn create next-app` diff --git a/examples/analyze-bundles/README.md b/examples/analyze-bundles/README.md index 8aec1e56c79c4..02e1673ccd3b8 100644 --- a/examples/analyze-bundles/README.md +++ b/examples/analyze-bundles/README.md @@ -1,6 +1,6 @@ # Analyzer Bundles example -This example shows how to analyze the output bundles using [@next/bundle-analyzer](https://github.com/vercel/next.js/tree/master/packages/next-bundle-analyzer) +This example shows how to analyze the output bundles using [@next/bundle-analyzer](https://github.com/vercel/next.js/tree/canary/packages/next-bundle-analyzer) ## Preview diff --git a/examples/gh-pages/README.md b/examples/gh-pages/README.md index e9a37206c2bcb..fbd34532847cf 100644 --- a/examples/gh-pages/README.md +++ b/examples/gh-pages/README.md @@ -20,7 +20,7 @@ Edit `next.config.js` and replace `'Next-gh-page-example'` by your project name. 1. Create repository. 2. Link it to your github account. -3. Publish your master branch. +3. Publish your default branch, e.g. `main`. ```bash npm run deploy diff --git a/examples/progressive-web-app/pages/index.js b/examples/progressive-web-app/pages/index.js index dea04e8ac7ec3..c7aef703d4d6b 100644 --- a/examples/progressive-web-app/pages/index.js +++ b/examples/progressive-web-app/pages/index.js @@ -25,7 +25,7 @@ export default function Home() {

Examples →

diff --git a/examples/with-apollo-and-redux/README.md b/examples/with-apollo-and-redux/README.md index 765de3d3d0dd2..f1f55be5d1b98 100644 --- a/examples/with-apollo-and-redux/README.md +++ b/examples/with-apollo-and-redux/README.md @@ -2,7 +2,7 @@ This example serves as a conduit if you were using Apollo 1.X with Redux, and are migrating to Apollo 3.x, however, you have chosen not to manage your entire application state within Apollo (`apollo-link-state`). -In 3.0.0, Apollo serves out-of-the-box support for redux in favor of Apollo's state management. This example aims to be an amalgamation of the [`with-apollo`](https://github.com/vercel/next.js/tree/master/examples/with-apollo) and [`with-redux`](https://github.com/vercel/next.js/tree/master/examples/with-redux) examples. +In 3.0.0, Apollo serves out-of-the-box support for redux in favor of Apollo's state management. This example aims to be an amalgamation of the [`with-apollo`](https://github.com/vercel/next.js/tree/canary/examples/with-apollo) and [`with-redux`](https://github.com/vercel/next.js/tree/canary/examples/with-redux) examples. To inspect the GraphQL API, use its [web IDE](https://nextjs-graphql-with-prisma-simple-foo.vercel.app/api). diff --git a/examples/with-cypress/pages/index.js b/examples/with-cypress/pages/index.js index 7af20bc61f526..36b3381bad611 100644 --- a/examples/with-cypress/pages/index.js +++ b/examples/with-cypress/pages/index.js @@ -41,7 +41,7 @@ export default function Home() {

Examples →

diff --git a/examples/with-docker/pages/index.js b/examples/with-docker/pages/index.js index 16d683b56c084..0a6884b38582b 100644 --- a/examples/with-docker/pages/index.js +++ b/examples/with-docker/pages/index.js @@ -31,7 +31,7 @@ export default function Home() {

Examples →

diff --git a/examples/with-elasticsearch/pages/index.js b/examples/with-elasticsearch/pages/index.js index 2a4a49573b13b..0d2c6e3563e1b 100644 --- a/examples/with-elasticsearch/pages/index.js +++ b/examples/with-elasticsearch/pages/index.js @@ -43,7 +43,7 @@ export default function Home({ isConnected }) {

Examples →

diff --git a/examples/with-jest-babel/__tests__/__snapshots__/snapshot.tsx.snap b/examples/with-jest-babel/__tests__/__snapshots__/snapshot.tsx.snap index c5e6e3478c575..f00d4ea78fd45 100644 --- a/examples/with-jest-babel/__tests__/__snapshots__/snapshot.tsx.snap +++ b/examples/with-jest-babel/__tests__/__snapshots__/snapshot.tsx.snap @@ -9,7 +9,7 @@ exports[`renders homepage unchanged 1`] = `

- Welcome to + Welcome to @@ -19,7 +19,7 @@ exports[`renders homepage unchanged 1`] = `

- Get started by editing + Get started by editing pages/index.js @@ -51,7 +51,7 @@ exports[`renders homepage unchanged 1`] = `

Examples → @@ -82,7 +82,7 @@ exports[`renders homepage unchanged 1`] = ` target="_blank" > Powered by - +

Examples →

diff --git a/examples/with-jest/__tests__/__snapshots__/snapshot.tsx.snap b/examples/with-jest/__tests__/__snapshots__/snapshot.tsx.snap index c5e6e3478c575..f00d4ea78fd45 100644 --- a/examples/with-jest/__tests__/__snapshots__/snapshot.tsx.snap +++ b/examples/with-jest/__tests__/__snapshots__/snapshot.tsx.snap @@ -9,7 +9,7 @@ exports[`renders homepage unchanged 1`] = `

- Welcome to + Welcome to @@ -19,7 +19,7 @@ exports[`renders homepage unchanged 1`] = `

- Get started by editing + Get started by editing pages/index.js @@ -51,7 +51,7 @@ exports[`renders homepage unchanged 1`] = `

Examples → @@ -82,7 +82,7 @@ exports[`renders homepage unchanged 1`] = ` target="_blank" > Powered by - +

Examples →

diff --git a/examples/with-knex/pages/index.js b/examples/with-knex/pages/index.js index a1378001c887b..15b08938f116d 100644 --- a/examples/with-knex/pages/index.js +++ b/examples/with-knex/pages/index.js @@ -51,7 +51,7 @@ export default function Home() {

Examples →

diff --git a/examples/with-mdbreact/pages/index.js b/examples/with-mdbreact/pages/index.js index 2e579d4f1fb67..3b38fae094bac 100644 --- a/examples/with-mdbreact/pages/index.js +++ b/examples/with-mdbreact/pages/index.js @@ -75,7 +75,7 @@ export default function Home() { color="primary" size="sm" className="text-capitalize" - href="https://github.com/vercel/next.js/tree/master/examples" + href="https://github.com/vercel/next.js/tree/canary/examples" > More → diff --git a/examples/with-mongodb/pages/index.js b/examples/with-mongodb/pages/index.js index a57dfe93bfb97..865be76596990 100644 --- a/examples/with-mongodb/pages/index.js +++ b/examples/with-mongodb/pages/index.js @@ -39,7 +39,7 @@ export default function Home({ isConnected }) {

Examples →

diff --git a/examples/with-playwright/pages/index.js b/examples/with-playwright/pages/index.js index 25a4a79171782..07b0717dcf936 100644 --- a/examples/with-playwright/pages/index.js +++ b/examples/with-playwright/pages/index.js @@ -41,7 +41,7 @@ export default function Home() {

Examples →

diff --git a/examples/with-rbx-bulma-pro/pages/index.js b/examples/with-rbx-bulma-pro/pages/index.js index f44638bb94985..a8993e08fabff 100644 --- a/examples/with-rbx-bulma-pro/pages/index.js +++ b/examples/with-rbx-bulma-pro/pages/index.js @@ -20,7 +20,7 @@ const Home = () => ( - +
Examples →

diff --git a/examples/with-react-bootstrap/pages/index.jsx b/examples/with-react-bootstrap/pages/index.jsx index d6cfa992d0614..81073f07b2531 100644 --- a/examples/with-react-bootstrap/pages/index.jsx +++ b/examples/with-react-bootstrap/pages/index.jsx @@ -49,7 +49,7 @@ export default function Home() { diff --git a/examples/with-react-with-styles/README.md b/examples/with-react-with-styles/README.md index 92af40b7ac1ea..7eb93c482bfad 100644 --- a/examples/with-react-with-styles/README.md +++ b/examples/with-react-with-styles/README.md @@ -6,7 +6,7 @@ In this case we are using [react-with-styles](https://github.com/airbnb/react-wi For this purpose we are extending the `` and injecting the server side rendered styles into the ``. -We are using `pages/_index.js` from this example [with-aphrodite](https://github.com/vercel/next.js/tree/master/examples/with-aphrodite). +We are using `pages/_index.js` from this example [with-aphrodite](https://github.com/vercel/next.js/tree/canary/examples/with-aphrodite). ## Preview diff --git a/examples/with-reactstrap/pages/index.jsx b/examples/with-reactstrap/pages/index.jsx index 511632185ffa5..bfe5a5daf9e77 100644 --- a/examples/with-reactstrap/pages/index.jsx +++ b/examples/with-reactstrap/pages/index.jsx @@ -63,7 +63,7 @@ export default function Home() { diff --git a/examples/with-redux-persist/README.md b/examples/with-redux-persist/README.md index 80caf652424b7..de187cb94ea1d 100644 --- a/examples/with-redux-persist/README.md +++ b/examples/with-redux-persist/README.md @@ -30,7 +30,7 @@ Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&ut ## Notes -In this example, we are going to use the Next.js example [with-redux](https://github.com/vercel/next.js/tree/master/examples/with-redux-persist) to see how you can add a layer of persistence for one of the state from global redux state. To know more about how to create a Next.js project with Redux, you can browse the example project [with-redux](https://github.com/vercel/next.js/tree/master/examples/with-redux) to know more about its implementation. +In this example, we are going to use the Next.js example [with-redux](https://github.com/vercel/next.js/tree/canary/examples/with-redux-persist) to see how you can add a layer of persistence for one of the state from global redux state. To know more about how to create a Next.js project with Redux, you can browse the example project [with-redux](https://github.com/vercel/next.js/tree/canary/examples/with-redux) to know more about its implementation. The Redux Persist has been initialized in `store.js`. You can modify the `redux-persist` configuration (In this example, we are persisting only one state termed `exampleData` which is added in the `persist configuration`) if you need something more with `redux-persist` by following their [docs](https://github.com/rt2zz/redux-persist/blob/master/README.md). To wrap out our component in the `Persist Gate` which rehydrates the global state with combining the persisted values and global state values, we'll have to make some modifications in the implementation of Redux in `pages/_app.js`. diff --git a/examples/with-redux-saga/README.md b/examples/with-redux-saga/README.md index 3450a62b3c835..72e28b37c73d3 100644 --- a/examples/with-redux-saga/README.md +++ b/examples/with-redux-saga/README.md @@ -2,7 +2,7 @@ Usually splitting your app state into `pages` feels natural, but sometimes you'll want to have global state for your app. This is an example using `redux` and `redux-saga` that works with universal rendering. This is just one way it can be done. If you have any suggestions or feedback please submit an issue or PR. -> This example and documentation is based on the [with-redux](https://github.com/vercel/next.js/tree/master/examples/with-redux) example. +> This example and documentation is based on the [with-redux](https://github.com/vercel/next.js/tree/canary/examples/with-redux) example. ## Preview diff --git a/examples/with-rematch/README.md b/examples/with-rematch/README.md index e037ef1ea8948..937efa89cf1c9 100644 --- a/examples/with-rematch/README.md +++ b/examples/with-rematch/README.md @@ -2,7 +2,7 @@ This example has two pages. The first page has a counter which can be incremented synchronously or asynchronously. The second page is a page which shows a list of github users. It fetches data from the github api using this [endpoint](api.github.com/users). -Since rematch is utility which uses redux under the hood, some elements like `store.js` and `withRematch` are very similar to the `with-redux` example. Please go through the [`with-redux` example](https://github.com/vercel/next.js/tree/master/examples/with-redux) before reading further if you are not familiar with how redux is integrated with Next.js. Rematch is just an extension for Redux so a lot of elements are the same. +Since rematch is utility which uses redux under the hood, some elements like `store.js` and `withRematch` are very similar to the `with-redux` example. Please go through the [`with-redux` example](https://github.com/vercel/next.js/tree/canary/examples/with-redux) before reading further if you are not familiar with how redux is integrated with Next.js. Rematch is just an extension for Redux so a lot of elements are the same. ## Preview diff --git a/examples/with-sitemap/pages/index.js b/examples/with-sitemap/pages/index.js index 9567794ecd851..801b309119227 100644 --- a/examples/with-sitemap/pages/index.js +++ b/examples/with-sitemap/pages/index.js @@ -29,7 +29,7 @@ export default function Home() {

Examples →

diff --git a/examples/with-styled-jsx-postcss/README.md b/examples/with-styled-jsx-postcss/README.md index 5ef4bfd8b34eb..a7afad09a4849 100644 --- a/examples/with-styled-jsx-postcss/README.md +++ b/examples/with-styled-jsx-postcss/README.md @@ -1 +1 @@ -This examples was moved to [https://github.com/vercel/next.js/tree/master/examples/with-styled-jsx-plugins](https://github.com/vercel/next.js/tree/master/examples/with-styled-jsx-plugins) +This examples was moved to [https://github.com/vercel/next.js/tree/canary/examples/with-styled-jsx-plugins](https://github.com/vercel/next.js/tree/canary/examples/with-styled-jsx-plugins) diff --git a/examples/with-supertokens/pages/index.js b/examples/with-supertokens/pages/index.js index 0629fa410da25..0599974ed0faf 100644 --- a/examples/with-supertokens/pages/index.js +++ b/examples/with-supertokens/pages/index.js @@ -141,7 +141,7 @@ function ProtectedPage({ userId }) {

Examples →

diff --git a/examples/with-tailwindcss/pages/index.tsx b/examples/with-tailwindcss/pages/index.tsx index 828dd6012730d..890e0279e0aec 100644 --- a/examples/with-tailwindcss/pages/index.tsx +++ b/examples/with-tailwindcss/pages/index.tsx @@ -45,7 +45,7 @@ export default function Home() {

Examples →

diff --git a/examples/with-typestyle/README.md b/examples/with-typestyle/README.md index 0491bedc5ee0f..659f51cb767ba 100644 --- a/examples/with-typestyle/README.md +++ b/examples/with-typestyle/README.md @@ -2,7 +2,7 @@ This example features how you use a different styling solution than [styled-jsx](https://github.com/vercel/styled-jsx) that also supports universal styles. That means we can serve the required styles for the first render within the HTML and then load the rest in the client. In this case we are using [typestyle](https://github.com/typestyle/typestyle). -For this purpose we are extending the `` and injecting the server side rendered styles into the ``. Refer to [with-typescript](https://github.com/vercel/next.js/tree/master/examples/with-typescript) to use this with typescript. +For this purpose we are extending the `` and injecting the server side rendered styles into the ``. Refer to [with-typescript](https://github.com/vercel/next.js/tree/canary/examples/with-typescript) to use this with typescript. ## Preview diff --git a/lerna.json b/lerna.json index 3ca1cb71f6c95..c87688c20ca06 100644 --- a/lerna.json +++ b/lerna.json @@ -11,7 +11,6 @@ "publish": { "npmClient": "npm", "allowBranch": [ - "master", "canary" ], "registry": "https://registry.npmjs.org/" diff --git a/packages/create-next-app/README.md b/packages/create-next-app/README.md index 8cf5e7f8c8c3e..16b1687fc885e 100644 --- a/packages/create-next-app/README.md +++ b/packages/create-next-app/README.md @@ -23,7 +23,7 @@ npx create-next-app blog-app `create-next-app` comes with the following options: - **--ts, --typescript** - Initialize as a TypeScript project. -- **-e, --example [name]|[github-url]** - An example to bootstrap the app with. You can use an example name from the [Next.js repo](https://github.com/vercel/next.js/tree/master/examples) or a GitHub URL. The URL can use any branch and/or subdirectory. +- **-e, --example [name]|[github-url]** - An example to bootstrap the app with. You can use an example name from the [Next.js repo](https://github.com/vercel/next.js/tree/canary/examples) or a GitHub URL. The URL can use any branch and/or subdirectory. - **--example-path <path-to-example>** - In a rare case, your GitHub URL might contain a branch name with a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar). In this case, you must specify the path to the example separately: `--example-path foo/bar` - **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. To bootstrap using yarn we recommend to run `yarn create next-app` diff --git a/packages/create-next-app/templates/default/pages/index.js b/packages/create-next-app/templates/default/pages/index.js index 08145bba9a578..dc4b64035213f 100644 --- a/packages/create-next-app/templates/default/pages/index.js +++ b/packages/create-next-app/templates/default/pages/index.js @@ -33,7 +33,7 @@ export default function Home() {

Examples →

diff --git a/packages/create-next-app/templates/typescript/pages/index.tsx b/packages/create-next-app/templates/typescript/pages/index.tsx index 72a4a59053d70..86b5b3b5bf3fd 100644 --- a/packages/create-next-app/templates/typescript/pages/index.tsx +++ b/packages/create-next-app/templates/typescript/pages/index.tsx @@ -34,7 +34,7 @@ const Home: NextPage = () => {

Examples →

diff --git a/test/development/basic/tailwind-jit/pages/index.js b/test/development/basic/tailwind-jit/pages/index.js index a3db606301626..f84ca7fd835f7 100644 --- a/test/development/basic/tailwind-jit/pages/index.js +++ b/test/development/basic/tailwind-jit/pages/index.js @@ -38,7 +38,7 @@ export default function Home() {

Examples →

From b6b7d85f6d42dd04ff5062380887edd16f3a6d0e Mon Sep 17 00:00:00 2001 From: Hiroaki Ogasawara <13391129+xhiroga@users.noreply.github.com> Date: Tue, 11 Jan 2022 17:56:07 -0800 Subject: [PATCH 05/12] Docs: correct ignorance pattern for .env.local (#32647) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Docs: correct ignorance pattern for env.local In order to gitignore `.env.local`, I need to add `.env*.local` instead of `.env.*.local` to `.gitignore`. * Update docs/basic-features/environment-variables.md Co-authored-by: Steven * Update docs/basic-features/environment-variables.md Co-authored-by: Balázs Orbán Co-authored-by: Steven Co-authored-by: Balázs Orbán --- docs/basic-features/environment-variables.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basic-features/environment-variables.md b/docs/basic-features/environment-variables.md index 43ecd315ad971..857f4f488dc0b 100644 --- a/docs/basic-features/environment-variables.md +++ b/docs/basic-features/environment-variables.md @@ -112,7 +112,7 @@ Next.js allows you to set defaults in `.env` (all environments), `.env.developme `.env.local` always overrides the defaults set. -> **Note**: `.env`, `.env.development`, and `.env.production` files should be included in your repository as they define defaults. **`.env.*.local` should be added to `.gitignore`**, as those files are intended to be ignored. `.env.local` is where secrets can be stored. +> **Note**: `.env`, `.env.development`, and `.env.production` files should be included in your repository as they define defaults. **`.env*.local` should be added to `.gitignore`**, as those files are intended to be ignored. `.env.local` is where secrets can be stored. ## Environment Variables on Vercel From d291aa9134ef2be420aa1e0d9467746384367953 Mon Sep 17 00:00:00 2001 From: Rich Haines Date: Wed, 12 Jan 2022 08:56:51 +0100 Subject: [PATCH 06/12] Refactor data fetching API docs (#30615) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lee Robinson Co-authored-by: Balázs Orbán --- .../automatic-static-optimization.md | 4 +- docs/advanced-features/custom-app.md | 6 +- docs/advanced-features/custom-document.md | 4 +- docs/advanced-features/custom-error-page.md | 4 +- docs/advanced-features/i18n-routing.md | 4 +- docs/advanced-features/preview-mode.md | 4 +- docs/advanced-features/static-html-export.md | 20 +- ...etInitialProps.md => get-initial-props.md} | 24 +- .../data-fetching/get-server-side-props.md | 151 +++ .../data-fetching/get-static-paths.md | 212 +++++ .../data-fetching/get-static-props.md | 244 +++++ .../cdn-support-with-asset-prefix.md | 2 +- .../api-reference/next.config.js/redirects.md | 2 +- docs/api-reference/next.config.js/rewrites.md | 2 +- docs/api-reference/next/link.md | 4 +- docs/api-reference/next/router.md | 6 +- docs/authentication.md | 8 +- docs/basic-features/data-fetching.md | 882 ------------------ .../data-fetching/client-side.md | 70 ++ .../data-fetching/get-server-side-props.md | 75 ++ .../data-fetching/get-static-paths.md | 48 + .../data-fetching/get-static-props.md | 103 ++ .../incremental-static-regeneration.md | 88 ++ docs/basic-features/data-fetching/index.md | 87 ++ docs/basic-features/environment-variables.md | 4 +- docs/basic-features/pages.md | 12 +- docs/basic-features/typescript.md | 2 +- docs/faq.md | 2 +- docs/getting-started.md | 2 +- docs/going-to-production.md | 2 +- docs/manifest.json | 50 +- docs/migrating/from-create-react-app.md | 6 +- docs/migrating/from-gatsby.md | 8 +- docs/routing/introduction.md | 2 +- docs/routing/shallow-routing.md | 2 +- ...get-initial-props-as-an-instance-method.md | 2 +- examples/blog/pages/posts/pages.md | 10 +- 37 files changed, 1187 insertions(+), 971 deletions(-) rename docs/api-reference/data-fetching/{getInitialProps.md => get-initial-props.md} (79%) create mode 100644 docs/api-reference/data-fetching/get-server-side-props.md create mode 100644 docs/api-reference/data-fetching/get-static-paths.md create mode 100644 docs/api-reference/data-fetching/get-static-props.md delete mode 100644 docs/basic-features/data-fetching.md create mode 100644 docs/basic-features/data-fetching/client-side.md create mode 100644 docs/basic-features/data-fetching/get-server-side-props.md create mode 100644 docs/basic-features/data-fetching/get-static-paths.md create mode 100644 docs/basic-features/data-fetching/get-static-props.md create mode 100644 docs/basic-features/data-fetching/incremental-static-regeneration.md create mode 100644 docs/basic-features/data-fetching/index.md diff --git a/docs/advanced-features/automatic-static-optimization.md b/docs/advanced-features/automatic-static-optimization.md index 17a3ea787c3b9..abf202aacbd67 100644 --- a/docs/advanced-features/automatic-static-optimization.md +++ b/docs/advanced-features/automatic-static-optimization.md @@ -20,7 +20,7 @@ If the above is not the case, Next.js will **statically optimize** your page aut During prerendering, the router's `query` object will be empty since we do not have `query` information to provide during this phase. After hydration, Next.js will trigger an update to your application to provide the route parameters in the `query` object. -> **Note:** Parameters added with [dynamic routes](/docs/routing/dynamic-routes.md) to a page that's using [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) will always be available inside the `query` object. +> **Note:** Parameters added with [dynamic routes](/docs/routing/dynamic-routes.md) to a page that's using [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) will always be available inside the `query` object. `next build` will emit `.html` files for statically optimized pages. For example, the result for the page `pages/about.js` would be: @@ -36,5 +36,5 @@ And if you add `getServerSideProps` to the page, it will then be JavaScript, lik ## Caveats -- If you have a [custom `App`](/docs/advanced-features/custom-app.md) with `getInitialProps` then this optimization will be turned off in pages without [Static Generation](/docs/basic-features/data-fetching.md#getstaticprops-static-generation). +- If you have a [custom `App`](/docs/advanced-features/custom-app.md) with `getInitialProps` then this optimization will be turned off in pages without [Static Generation](/docs/basic-features/data-fetching/get-static-props.md). - If you have a [custom `Document`](/docs/advanced-features/custom-document.md) with `getInitialProps` be sure you check if `ctx.req` is defined before assuming the page is server-side rendered. `ctx.req` will be `undefined` for pages that are prerendered. diff --git a/docs/advanced-features/custom-app.md b/docs/advanced-features/custom-app.md index 7add6c1d9b0c5..73d65f5666a97 100644 --- a/docs/advanced-features/custom-app.md +++ b/docs/advanced-features/custom-app.md @@ -38,14 +38,14 @@ export default MyApp The `Component` prop is the active `page`, so whenever you navigate between routes, `Component` will change to the new `page`. Therefore, any props you send to `Component` will be received by the `page`. -`pageProps` is an object with the initial props that were preloaded for your page by one of our [data fetching methods](/docs/basic-features/data-fetching.md), otherwise it's an empty object. +`pageProps` is an object with the initial props that were preloaded for your page by one of our [data fetching methods](/docs/basic-features/data-fetching/index.md), otherwise it's an empty object. ### Caveats - If your app is running and you added a custom `App`, you'll need to restart the development server. Only required if `pages/_app.js` didn't exist before. -- Adding a custom [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md) in your `App` will disable [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md) in pages without [Static Generation](/docs/basic-features/data-fetching.md#getstaticprops-static-generation). +- Adding a custom [`getInitialProps`](/docs/api-reference/data-fetching/get-initial-props.md) in your `App` will disable [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md) in pages without [Static Generation](/docs/basic-features/data-fetching/get-static-props.md). - When you add `getInitialProps` in your custom app, you must `import App from "next/app"`, call `App.getInitialProps(appContext)` inside `getInitialProps` and merge the returned object into the return value. -- `App` currently does not support Next.js [Data Fetching methods](/docs/basic-features/data-fetching.md) like [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) or [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering). +- `App` currently does not support Next.js [Data Fetching methods](/docs/basic-features/data-fetching/index.md) like [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) or [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md). ### TypeScript diff --git a/docs/advanced-features/custom-document.md b/docs/advanced-features/custom-document.md index 2c75cca86b376..3ec0e856bee7b 100644 --- a/docs/advanced-features/custom-document.md +++ b/docs/advanced-features/custom-document.md @@ -45,7 +45,7 @@ Custom attributes are allowed as props, like `lang`: The `` component used here is not the same one from [`next/head`](/docs/api-reference/next/head.md). The `` component used here should only be used for any `` code that is common for all pages. For all other cases, such as `` tags, we recommend using [`next/head`](/docs/api-reference/next/head.md) in your pages or components. -The `ctx` object is equivalent to the one received in [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md#context-object), with one addition: +The `ctx` object is equivalent to the one received in [`getInitialProps`](/docs/api-reference/data-fetching/get-initial-props.md#context-object), with one addition: - `renderPage`: `Function` - a callback that runs the actual React rendering logic (synchronously). It's useful to decorate this function in order to support server-rendering wrappers like Aphrodite's [`renderStatic`](https://github.com/Khan/aphrodite#server-side-rendering) @@ -54,7 +54,7 @@ The `ctx` object is equivalent to the one received in [`getInitialProps`](/docs/ - `Document` is only rendered in the server, event handlers like `onClick` won't work. - React components outside of `<Main />` will not be initialized by the browser. Do _not_ add application logic here or custom CSS (like `styled-jsx`). If you need shared components in all your pages (like a menu or a toolbar), take a look at the [`App`](/docs/advanced-features/custom-app.md) component instead. - `Document`'s `getInitialProps` function is not called during client-side transitions, nor when a page is [statically optimized](/docs/advanced-features/automatic-static-optimization.md). -- `Document` currently does not support Next.js [Data Fetching methods](/docs/basic-features/data-fetching.md) like [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) or [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering). +- `Document` currently does not support Next.js [Data Fetching methods](/docs/basic-features/data-fetching/index.md) like [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) or [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md). ## Customizing `renderPage` diff --git a/docs/advanced-features/custom-error-page.md b/docs/advanced-features/custom-error-page.md index 40913ed76eee1..1f79132537733 100644 --- a/docs/advanced-features/custom-error-page.md +++ b/docs/advanced-features/custom-error-page.md @@ -21,7 +21,7 @@ export default function Custom404() { } ``` -> **Note**: You can use [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) inside this page if you need to fetch data at build time. +> **Note**: You can use [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) inside this page if you need to fetch data at build time. ## 500 Page @@ -38,7 +38,7 @@ export default function Custom500() { } ``` -> **Note**: You can use [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) inside this page if you need to fetch data at build time. +> **Note**: You can use [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) inside this page if you need to fetch data at build time. ### More Advanced Error Page Customizing diff --git a/docs/advanced-features/i18n-routing.md b/docs/advanced-features/i18n-routing.md index 8272276b47418..6eb849294e063 100644 --- a/docs/advanced-features/i18n-routing.md +++ b/docs/advanced-features/i18n-routing.md @@ -207,7 +207,7 @@ You can access the locale information via the Next.js router. For example, using - `locales` contains all configured locales. - `defaultLocale` contains the configured default locale. -When [pre-rendering](/docs/basic-features/pages.md#static-generation-recommended) pages with `getStaticProps` or `getServerSideProps`, the locale information is provided in [the context](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) provided to the function. +When [pre-rendering](/docs/basic-features/pages.md#static-generation-recommended) pages with `getStaticProps` or `getServerSideProps`, the locale information is provided in [the context](/docs/basic-features/data-fetching/get-static-props.md) provided to the function. When leveraging `getStaticPaths`, the configured locales are provided in the context parameter of the function under `locales` and the configured defaultLocale under `defaultLocale`. @@ -293,7 +293,7 @@ Next.js doesn't know about variants of a page so it's up to you to add the `href ### Dynamic Routes and `getStaticProps` Pages -For pages using `getStaticProps` with [Dynamic Routes](/docs/routing/dynamic-routes.md), all locale variants of the page desired to be prerendered need to be returned from [`getStaticPaths`](/docs/basic-features/data-fetching.md#getstaticpaths-static-generation). Along with the `params` object returned for `paths`, you can also return a `locale` field specifying which locale you want to render. For example: +For pages using `getStaticProps` with [Dynamic Routes](/docs/routing/dynamic-routes.md), all locale variants of the page desired to be prerendered need to be returned from [`getStaticPaths`](/docs/basic-features/data-fetching/get-static-paths.md). Along with the `params` object returned for `paths`, you can also return a `locale` field specifying which locale you want to render. For example: ```js // pages/blog/[slug].js diff --git a/docs/advanced-features/preview-mode.md b/docs/advanced-features/preview-mode.md index 511974bad4264..a5b7ac69c3e65 100644 --- a/docs/advanced-features/preview-mode.md +++ b/docs/advanced-features/preview-mode.md @@ -27,7 +27,7 @@ description: Next.js has the preview mode for statically generated pages. You ca </ul> </details> -In the [Pages documentation](/docs/basic-features/pages.md) and the [Data Fetching documentation](/docs/basic-features/data-fetching.md), we talked about how to pre-render a page at build time (**Static Generation**) using `getStaticProps` and `getStaticPaths`. +In the [Pages documentation](/docs/basic-features/pages.md) and the [Data Fetching documentation](/docs/basic-features/data-fetching/index.md), we talked about how to pre-render a page at build time (**Static Generation**) using `getStaticProps` and `getStaticPaths`. Static Generation is useful when your pages fetch data from a headless CMS. However, it’s not ideal when you’re writing a draft on your headless CMS and want to **preview** the draft immediately on your page. You’d want Next.js to render these pages at **request time** instead of build time and fetch the draft content instead of the published content. You’d want Next.js to bypass Static Generation only for this specific case. @@ -230,7 +230,7 @@ This ensures that the bypass cookie can’t be guessed. The following pages might also be useful. <div class="card"> - <a href="/docs/basic-features/data-fetching.md"> + <a href="/docs/basic-features/data-fetching/index.md"> <b>Data Fetching:</b> <small>Learn more about data fetching in Next.js.</small> </a> diff --git a/docs/advanced-features/static-html-export.md b/docs/advanced-features/static-html-export.md index e37bd2ababcf4..6408adf0b7c68 100644 --- a/docs/advanced-features/static-html-export.md +++ b/docs/advanced-features/static-html-export.md @@ -13,7 +13,7 @@ description: Export your Next.js app to static HTML, and run it standalone witho `next export` allows you to export your Next.js application to static HTML, which can be run standalone without the need of a Node.js server. It is recommended to only use `next export` if you don't need any of the [unsupported features](#unsupported-features) requiring a server. -If you're looking to build a hybrid site where only _some_ pages are prerendered to static HTML, Next.js already does that automatically. Learn more about [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md) and [Incremental Static Regeneration](/docs/basic-features/data-fetching.md#incremental-static-regeneration). +If you're looking to build a hybrid site where only _some_ pages are prerendered to static HTML, Next.js already does that automatically. Learn more about [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md) and [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md). ## `next export` @@ -27,7 +27,7 @@ Update your build script in `package.json` to use `next export`: Running `npm run build` will generate an `out` directory. -`next export` builds an HTML version of your app. During `next build`, [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) and [`getStaticPaths`](/docs/basic-features/data-fetching.md#getstaticpaths-static-generation) will generate an HTML file for each page in your `pages` directory (or more for [dynamic routes](/docs/routing/dynamic-routes.md). Then, `next export` will copy the already exported files into the correct directory. `getInitialProps` will generate the HTML files during `next export` instead of `next build`. +`next export` builds an HTML version of your app. During `next build`, [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) and [`getStaticPaths`](/docs/basic-features/data-fetching/get-static-paths.md) will generate an HTML file for each page in your `pages` directory (or more for [dynamic routes](/docs/routing/dynamic-routes.md). Then, `next export` will copy the already exported files into the correct directory. `getInitialProps` will generate the HTML files during `next export` instead of `next build`. For more advanced scenarios, you can define a parameter called [`exportPathMap`](/docs/api-reference/next.config.js/exportPathMap.md) in your [`next.config.js`](/docs/api-reference/next.config.js/introduction.md) file to configure exactly which pages will be generated. @@ -40,9 +40,9 @@ The majority of core Next.js features needed to build a static site are supporte - Preloading JavaScript - [Dynamic Imports](/docs/advanced-features/dynamic-import.md) - Any styling options (e.g. CSS Modules, styled-jsx) -- [Client-side data fetching](/docs/basic-features/data-fetching.md#fetching-data-on-the-client-side) -- [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) -- [`getStaticPaths`](/docs/basic-features/data-fetching.md#getstaticpaths-static-generation) +- [Client-side data fetching](/docs/basic-features/data-fetching/client-side.md) +- [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) +- [`getStaticPaths`](/docs/basic-features/data-fetching/get-static-paths.md) - [Image Optimization](/docs/basic-features/image-optimization.md) using a [custom loader](/docs/basic-features/image-optimization.md#loader) ## Unsupported Features @@ -56,16 +56,16 @@ Features that require a Node.js server, or dynamic logic that cannot be computed - [Redirects](/docs/api-reference/next.config.js/redirects.md) - [Headers](/docs/api-reference/next.config.js/headers.md) - [Middleware](/docs/middleware.md) -- [Incremental Static Regeneration](/docs/basic-features/data-fetching.md#incremental-static-regeneration) -- [`fallback: true`](/docs/basic-features/data-fetching.md#fallback-true) -- [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) +- [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md) +- [`fallback: true`](/docs/api-reference/data-fetching/get-static-paths.md#fallback-true) +- [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md) ### `getInitialProps` -It's possible to use the [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md) API instead of `getStaticProps`, but it comes with a few caveats: +It's possible to use the [`getInitialProps`](/docs/api-reference/data-fetching/get-initial-props.md) API instead of `getStaticProps`, but it comes with a few caveats: - `getInitialProps` cannot be used alongside `getStaticProps` or `getStaticPaths` on any given page. If you have dynamic routes, instead of using `getStaticPaths` you'll need to configure the [`exportPathMap`](/docs/api-reference/next.config.js/exportPathMap.md) parameter in your [`next.config.js`](/docs/api-reference/next.config.js/introduction.md) file to let the exporter know which HTML files it should output. -- When `getInitialProps` is called during export, the `req` and `res` fields of its [`context`](/docs/api-reference/data-fetching/getInitialProps.md#context-object) parameter will be empty objects, since during export there is no server running. +- When `getInitialProps` is called during export, the `req` and `res` fields of its [`context`](/docs/api-reference/data-fetching/get-initial-props.md#context-object) parameter will be empty objects, since during export there is no server running. - `getInitialProps` **will be called on every client-side navigation**, if you'd like to only fetch data at build-time, switch to `getStaticProps`. - `getInitialProps` should fetch from an API and cannot use Node.js-specific libraries or the file system like `getStaticProps` can. diff --git a/docs/api-reference/data-fetching/getInitialProps.md b/docs/api-reference/data-fetching/get-initial-props.md similarity index 79% rename from docs/api-reference/data-fetching/getInitialProps.md rename to docs/api-reference/data-fetching/get-initial-props.md index 611533a9b3fc0..f8295dbda52c2 100644 --- a/docs/api-reference/data-fetching/getInitialProps.md +++ b/docs/api-reference/data-fetching/get-initial-props.md @@ -4,15 +4,11 @@ description: Enable Server-Side Rendering in a page and do initial data populati # getInitialProps -> **Recommended: [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) or [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering)**. -> -> If you're using Next.js 9.3 or newer, we recommend that you use `getStaticProps` or `getServerSideProps` instead of `getInitialProps`. -> -> These new data fetching methods allow you to have a granular choice between static generation and server-side rendering. Learn more on the documentation for [Pages](/docs/basic-features/pages.md) and [Data Fetching](/docs/basic-features/data-fetching.md). +**Recommended: [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) or [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md)** instead of `getInitialProps`. These data fetching methods allow you to have a granular choice between static generation and server-side rendering. `getInitialProps` enables [server-side rendering](/docs/basic-features/pages.md#server-side-rendering) in a page and allows you to do **initial data population**, it means sending the [page](/docs/basic-features/pages.md) with the data already populated from the server. This is especially useful for [SEO](https://en.wikipedia.org/wiki/Search_engine_optimization). -> `getInitialProps` will disable [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md). +`getInitialProps` will disable [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md). `getInitialProps` is an [`async`](https://vercel.com/blog/async-and-await) function that can be added to any page as a [`static method`](https://javascript.info/static-properties-methods). Take a look at the following example: @@ -123,22 +119,8 @@ export default class Page extends React.Component<Props> { For more information on what to do next, we recommend the following sections: <div class="card"> - <a href="/docs/basic-features/data-fetching.md"> + <a href="/docs/basic-features/data-fetching/index.md"> <b>Data Fetching:</b> <small>Learn more about data fetching in Next.js.</small> </a> </div> - -<div class="card"> - <a href="/docs/basic-features/pages.md"> - <b>Pages:</b> - <small>Learn more about what pages are in Next.js.</small> - </a> -</div> - -<div class="card"> - <a href="/docs/advanced-features/automatic-static-optimization.md"> - <b>Automatic Static Optimization:</b> - <small>Learn about how Next.js automatically optimizes your pages.</small> - </a> -</div> diff --git a/docs/api-reference/data-fetching/get-server-side-props.md b/docs/api-reference/data-fetching/get-server-side-props.md new file mode 100644 index 0000000000000..582b04db9e7b1 --- /dev/null +++ b/docs/api-reference/data-fetching/get-server-side-props.md @@ -0,0 +1,151 @@ +--- +description: API reference for `getServerSideProps`. Learn how to fetch data on each request with Next.js. +--- + +# `getServerSideProps` + +<details> + <summary><b>Version History</b></summary> + +| Version | Changes | +| --------- | ------------------------------------------------------------------- | +| `v10.0.0` | `locale`, `locales`, `defaultLocale`, and `notFound` options added. | +| `v9.3.0` | `getServerSideProps` introduced. | + +</details> + +When exporting a function called `getServerSideProps` (Server-Side Rendering) from a page, Next.js will pre-render this page on each request using the data returned by `getServerSideProps`. This is useful if you want to fetch data that changes often, and have the page update to show the most current data. + +```js +export async function getServerSideProps(context) { + return { + props: {}, // will be passed to the page component as props + } +} +``` + +You can import modules in top-level scope for use in `getServerSideProps`. Imports used will **not be bundled for the client-side**. This means you can write **server-side code directly in `getServerSideProps`**, including fetching data from your database. + +## Context parameter + +The `context` parameter is an object containing the following keys: + +- `params`: If this page uses a [dynamic route](/docs/routing/dynamic-routes.md), `params` contains the route parameters. If the page name is `[id].js` , then `params` will look like `{ id: ... }`. +- `req`: [The `HTTP` IncomingMessage object](https://nodejs.org/api/http.html#http_class_http_incomingmessage). +- `res`: [The `HTTP` response object](https://nodejs.org/api/http.html#http_class_http_serverresponse). +- `query`: An object representing the query string. +- `preview`: `preview` is `true` if the page is in the [Preview Mode](/docs/advanced-features/preview-mode.md) and `false` otherwise. +- `previewData`: The [preview](/docs/advanced-features/preview-mode.md) data set by `setPreviewData`. +- `resolvedUrl`: A normalized version of the request `URL` that strips the `_next/data` prefix for client transitions and includes original query values. +- `locale` contains the active locale (if enabled). +- `locales` contains all supported locales (if enabled). +- `defaultLocale` contains the configured default locale (if enabled). + +## `getServerSideProps` return values + +The `getServerSideProps` function should return an object with the following **optional** properties: + +### `props` + +The `props` object is a key-value pair, where each value is received by the page component. It should be a [serializable object](https://developer.mozilla.org/en-US/docs/Glossary/Serialization) so that any props passed, could be serialized with [`JSON.stringify`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). + +```jsx +export async function getServerSideProps(context) { + return { + props: { message: `Next.js is awesome` }, // will be passed to the page component as props + } +} +``` + +### `notFound` + +The `notFound` boolean allows the page to return a `404` status and [404 Page](/docs/advanced-features/custom-error-page.md#404-page). With `notFound: true`, the page will return a `404` even if there was a successfully generated page before. This is meant to support use cases like user-generated content getting removed by its author. + +```js +export async function getServerSideProps(context) { + const res = await fetch(`https://.../data`) + const data = await res.json() + + if (!data) { + return { + notFound: true, + } + } + + return { + props: { data }, // will be passed to the page component as props + } +} +``` + +### `redirect` + +The `redirect` object allows redirecting to internal and external resources. It should match the shape of `{ destination: string, permanent: boolean }`. In some rare cases, you might need to assign a custom status code for older `HTTP` clients to properly redirect. In these cases, you can use the `statusCode` property instead of the `permanent` property, but not both. + +```js +export async function getServerSideProps(context) { + const res = await fetch(`https://.../data`) + const data = await res.json() + + if (!data) { + return { + redirect: { + destination: '/', + permanent: false, + }, + } + } + + return { + props: {}, // will be passed to the page component as props + } +} +``` + +### `getServerSideProps` with TypeScript + +For TypeScript, you can use the `GetServerSideProps` type from `next`: + +```ts +import { GetServerSideProps } from 'next' + +export const getServerSideProps: GetServerSideProps = async (context) => { + // ... +} +``` + +If you want to get inferred typings for your props, you can use `InferGetServerSidePropsType<typeof getServerSideProps>`: + +```tsx +import { InferGetServerSidePropsType } from 'next' + +type Data = { ... } + +export const getServerSideProps = async () => { + const res = await fetch('https://.../data') + const data: Data = await res.json() + + return { + props: { + data, + }, + } +} + +function Page({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) { + // will resolve posts to type Data +} + +export default Page +``` + +## Related + +For more information on what to do next, we recommend the following sections: + +<div class="card"> + <a href="/docs/basic-features/data-fetching/index.md"> + <b>Data Fetching:</b> + <small>Learn more about data fetching in Next.js.</small> + </a> +</div> diff --git a/docs/api-reference/data-fetching/get-static-paths.md b/docs/api-reference/data-fetching/get-static-paths.md new file mode 100644 index 0000000000000..d185922fae93d --- /dev/null +++ b/docs/api-reference/data-fetching/get-static-paths.md @@ -0,0 +1,212 @@ +--- +description: API reference for `getStaticPaths`. Learn how to fetch data and generate static pages with `getStaticPaths`. +--- + +# `getStaticPaths` + +<details> + <summary><b>Version History</b></summary> + +| Version | Changes | +| -------- | --------------------------------------------------------------------------------------------------------------- | +| `v9.5.0` | Stable [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md) | +| `v9.3.0` | `getStaticPaths` introduced. | + +</details> + +When exporting a function called `getStaticPaths` from a page that uses [Dynamic Routes](/docs/routing/dynamic-routes.md), Next.js will statically pre-render all the paths specified by `getStaticPaths`. + +```jsx +export async function getStaticPaths() { + return { + paths: [ + { params: { ... } } // See the "paths" section below + ], + fallback: true, false or "blocking" // See the "fallback" section below + }; +} +``` + +## `getStaticPaths` return values + +The `getStaticPaths` function should return an object with the following **required** properties: + +### `paths` + +The `paths` key determines which paths will be pre-rendered. For example, suppose that you have a page that uses [Dynamic Routes](/docs/routing/dynamic-routes.md) named `pages/posts/[id].js`. If you export `getStaticPaths` from this page and return the following for `paths`: + +```js +return { + paths: [ + { params: { id: '1' } }, + { params: { id: '2' } } + ], + fallback: ... +} +``` + +Then, Next.js will statically generate `/posts/1` and `/posts/2` during `next build` using the page component in `pages/posts/[id].js`. + +The value for each `params` object must match the parameters used in the page name: + +- If the page name is `pages/posts/[postId]/[commentId]`, then `params` should contain `postId` and `commentId`. +- If the page name uses [catch-all routes](/docs/routing/dynamic-routes.md#catch-all-routes) like `pages/[...slug]`, then `params` should contain `slug` (which is an array). If this array is `['hello', 'world']`, then Next.js will statically generate the page at `/hello/world`. +- If the page uses an [optional catch-all route](/docs/routing/dynamic-routes.md#optional-catch-all-routes), use `null`, `[]`, `undefined` or `false` to render the root-most route. For example, if you supply `slug: false` for `pages/[[...slug]]`, Next.js will statically generate the page `/`. + +### `fallback: false` + +If `fallback` is `false`, then any paths not returned by `getStaticPaths` will result in a **404 page**. + +When `next build` is run, Next.js will check if `getStaticPaths` returned `fallback: false`, it will then build **only** the paths returned by `getStaticPaths`. This option is useful if you have a small number of paths to create, or new page data is not added often. If you find that you need to add more paths, and you have `fallback: false`, you will need to run `next build` again so that the new paths can be generated. + +The following example pre-renders one blog post per page called `pages/posts/[id].js`. The list of blog posts will be fetched from a CMS and returned by `getStaticPaths`. Then, for each page, it fetches the post data from a CMS using [`getStaticProps`](/docs/api-reference/data-fetching/get-static-props.md). + +```jsx +// pages/posts/[id].js + +function Post({ post }) { + // Render post... +} + +// This function gets called at build time +export async function getStaticPaths() { + // Call an external API endpoint to get posts + const res = await fetch('https://.../posts') + const posts = await res.json() + + // Get the paths we want to pre-render based on posts + const paths = posts.map((post) => ({ + params: { id: post.id }, + })) + + // We'll pre-render only these paths at build time. + // { fallback: false } means other routes should 404. + return { paths, fallback: false } +} + +// This also gets called at build time +export async function getStaticProps({ params }) { + // params contains the post `id`. + // If the route is like /posts/1, then params.id is 1 + const res = await fetch(`https://.../posts/${params.id}`) + const post = await res.json() + + // Pass post data to the page via props + return { props: { post } } +} + +export default Post +``` + +### `fallback: true` + +<details> + <summary><b>Examples</b></summary> + <ul> + <li><a href="https://static-tweet.vercel.app">Static generation of a large number of pages</a></li> + </ul> +</details> + +If `fallback` is `true`, then the behavior of `getStaticProps` changes in the following ways: + +- The paths returned from `getStaticPaths` will be rendered to `HTML` at build time by `getStaticProps`. +- The paths that have not been generated at build time will **not** result in a 404 page. Instead, Next.js will serve a [“fallback”](#fallback-pages) version of the page on the first request to such a path. +- In the background, Next.js will statically generate the requested path `HTML` and `JSON`. This includes running `getStaticProps`. +- When complete, the browser receives the `JSON` for the generated path. This will be used to automatically render the page with the required props. From the user’s perspective, the page will be swapped from the fallback page to the full page. +- At the same time, Next.js adds this path to the list of pre-rendered pages. Subsequent requests to the same path will serve the generated page, like other pages pre-rendered at build time. + +> **Note:** `fallback: true` is not supported when using [`next export`](/docs/advanced-features/static-html-export.md). + +#### When is `fallback: true` useful? + +`fallback: true` is useful if your app has a very large number of static pages that depend on data (such as a very large e-commerce site). If you want to pre-render all product pages, the builds would take a very long time. + +Instead, you may statically generate a small subset of pages and use `fallback: true` for the rest. When someone requests a page that is not generated yet, the user will see the page with a loading indicator or skeleton component. + +Shortly after, `getStaticProps` finishes and the page will be rendered with the requested data. From now on, everyone who requests the same page will get the statically pre-rendered page. + +This ensures that users always have a fast experience while preserving fast builds and the benefits of Static Generation. + +`fallback: true` will not _update_ generated pages, for that take a look at [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md). + +### `fallback: 'blocking'` + +If `fallback` is `'blocking'`, new paths not returned by `getStaticPaths` will wait for the `HTML` to be generated, identical to SSR (hence why _blocking_), and then be cached for future requests so it only happens once per path. + +`getStaticProps` will behave as follows: + +- The paths returned from `getStaticPaths` will be rendered to `HTML` at build time by `getStaticProps`. +- The paths that have not been generated at build time will **not** result in a 404 page. Instead, Next.js will SSR on the first request and return the generated `HTML`. +- When complete, the browser receives the `HTML` for the generated path. From the user’s perspective, it will transition from "the browser is requesting the page" to "the full page is loaded". There is no flash of loading/fallback state. +- At the same time, Next.js adds this path to the list of pre-rendered pages. Subsequent requests to the same path will serve the generated page, like other pages pre-rendered at build time. + +`fallback: 'blocking'` will not _update_ generated pages by default. To update generated pages, use [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md) in conjunction with `fallback: 'blocking'`. + +> **Note:** `fallback: 'blocking'` is not supported when using [`next export`](/docs/advanced-features/static-html-export.md). + +### Fallback pages + +In the “fallback” version of a page: + +- The page’s props will be empty. +- Using the [router](/docs/api-reference/next/router.md), you can detect if the fallback is being rendered, `router.isFallback` will be `true`. + +The following example showcases using `isFallback`: + +```jsx +// pages/posts/[id].js +import { useRouter } from 'next/router' + +function Post({ post }) { + const router = useRouter() + + // If the page is not yet generated, this will be displayed + // initially until getStaticProps() finishes running + if (router.isFallback) { + return <div>Loading...</div> + } + + // Render post... +} + +// This function gets called at build time +export async function getStaticPaths() { + return { + // Only `/posts/1` and `/posts/2` are generated at build time + paths: [{ params: { id: '1' } }, { params: { id: '2' } }], + // Enable statically generating additional pages + // For example: `/posts/3` + fallback: true, + } +} + +// This also gets called at build time +export async function getStaticProps({ params }) { + // params contains the post `id`. + // If the route is like /posts/1, then params.id is 1 + const res = await fetch(`https://.../posts/${params.id}`) + const post = await res.json() + + // Pass post data to the page via props + return { + props: { post }, + // Re-generate the post at most once per second + // if a request comes in + revalidate: 1, + } +} + +export default Post +``` + +## `getStaticProps` with TypeScript + +For TypeScript, you can use the `GetStaticPaths` type from `next`: + +```ts +import { GetStaticPaths } from 'next' + +export const getStaticPaths: GetStaticPaths = async () => { + // ... +} +``` diff --git a/docs/api-reference/data-fetching/get-static-props.md b/docs/api-reference/data-fetching/get-static-props.md new file mode 100644 index 0000000000000..2ab5ddb9f2625 --- /dev/null +++ b/docs/api-reference/data-fetching/get-static-props.md @@ -0,0 +1,244 @@ +--- +description: API reference for `getStaticProps`. Learn how to use `getStaticProps` to generate static pages with Next.js. +--- + +# `getStaticProps` + +<details> + <summary><b>Version History</b></summary> + +| Version | Changes | +| --------- | ----------------------------------------------------------------------------------------------------------------- | +| `v10.0.0` | `locale`, `locales`, `defaultLocale`, and `notFound` options added. | +| `v9.5.0` | Stable [Incremental Static Regeneration](https://nextjs.org/blog/next-9-5#stable-incremental-static-regeneration) | +| `v9.3.0` | `getStaticProps` introduced. | +| `v10.0.0` | `fallback: 'blocking'` return option added. | + +</details> + +Exporting a function called `getStaticProps` will pre-render a page at build time using the props returned from the function: + +```jsx +export async function getStaticProps(context) { + return { + props: {}, // will be passed to the page component as props + } +} +``` + +You can import modules in top-level scope for use in `getStaticProps`. Imports used will **not be bundled for the client-side**. This means you can write **server-side code directly in `getStaticProps`**, including fetching data from your database. + +## Context parameter + +The `context` parameter is an object containing the following keys: + +- `params` contains the route parameters for pages using [dynamic routes](/docs/routing/dynamic-routes.md). For example, if the page name is `[id].js` , then `params` will look like `{ id: ... }`. You should use this together with `getStaticPaths`, which we’ll explain later. +- `preview` is `true` if the page is in the [Preview Mode](/docs/advanced-features/preview-mode.md) and `undefined` otherwise. +- `previewData` contains the [preview](/docs/advanced-features/preview-mode.md) data set by `setPreviewData`. +- `locale` contains the active locale (if enabled). +- `locales` contains all supported locales (if enabled). +- `defaultLocale` contains the configured default locale (if enabled). + +## `getStaticProps` return values + +The `getStaticProps` function should return an object with the following **optional** properties: + +### `props` + +The `props` object is a key-value pair, where each value is received by the page component. It should be a [serializable object](https://developer.mozilla.org/en-US/docs/Glossary/Serialization) so that any props passed, could be serialized with [`JSON.stringify`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). + +```jsx +export async function getStaticProps(context) { + return { + props: { message: `Next.js is awesome` }, // will be passed to the page component as props + } +} +``` + +### `revalidate` + +The `revalidate` property is the amount in seconds after which a page re-generation can occur (defaults to `false` or no revalidation). + +```js +// This function gets called at build time on server-side. +// It may be called again, on a serverless function, if +// revalidation is enabled and a new request comes in +export async function getStaticProps() { + const res = await fetch('https://.../posts') + const posts = await res.json() + + return { + props: { + posts, + }, + // Next.js will attempt to re-generate the page: + // - When a request comes in + // - At most once every 10 seconds + revalidate: 10, // In seconds + } +} +``` + +Learn more about [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md) + +### `notFound` + +The `notFound` boolean allows the page to return a `404` status and [404 Page](/docs/advanced-features/custom-error-page.md#404-page). With `notFound: true`, the page will return a `404` even if there was a successfully generated page before. This is meant to support use cases like user-generated content getting removed by its author. + +```js +export async function getStaticProps(context) { + const res = await fetch(`https://.../data`) + const data = await res.json() + + if (!data) { + return { + notFound: true, + } + } + + return { + props: { data }, // will be passed to the page component as props + } +} +``` + +> **Note**: `notFound` is not needed for [`fallback: false`](/docs/api-reference/data-fetching/get-static-paths#fallback-false) mode as only paths returned from `getStaticPaths` will be pre-rendered. + +### `redirect` + +The `redirect` object allows redirecting to internal or external resources. It should match the shape of `{ destination: string, permanent: boolean }`. + +In some rare cases, you might need to assign a custom status code for older `HTTP` clients to properly redirect. In these cases, you can use the `statusCode` property instead of the `permanent` property, **but not both**. You can also set `basePath: false` similar to redirects in `next.config.js`. + +```js +export async function getStaticProps(context) { + const res = await fetch(`https://...`) + const data = await res.json() + + if (!data) { + return { + redirect: { + destination: '/', + permanent: false, + // statusCode: 301 + }, + } + } + + return { + props: { data }, // will be passed to the page component as props + } +} +``` + +If the redirects are known at build-time, they should be added in [`next.config.js`](/docs/api-reference/next.config.js/redirects.md) instead. + +## Reading files: Use `process.cwd()` + +Files can be read directly from the filesystem in `getStaticProps`. + +In order to do so you have to get the full path to a file. + +Since Next.js compiles your code into a separate directory you can't use `__dirname` as the path it will return will be different from the pages directory. + +Instead you can use `process.cwd()` which gives you the directory where Next.js is being executed. + +```jsx +import { promises as fs } from 'fs' +import path from 'path' + +// posts will be populated at build time by getStaticProps() +function Blog({ posts }) { + return ( + <ul> + {posts.map((post) => ( + <li> + <h3>{post.filename}</h3> + <p>{post.content}</p> + </li> + ))} + </ul> + ) +} + +// This function gets called at build time on server-side. +// It won't be called on client-side, so you can even do +// direct database queries. +export async function getStaticProps() { + const postsDirectory = path.join(process.cwd(), 'posts') + const filenames = await fs.readdir(postsDirectory) + + const posts = filenames.map(async (filename) => { + const filePath = path.join(postsDirectory, filename) + const fileContents = await fs.readFile(filePath, 'utf8') + + // Generally you would parse/transform the contents + // For example you can transform markdown to HTML here + + return { + filename, + content: fileContents, + } + }) + // By returning { props: { posts } }, the Blog component + // will receive `posts` as a prop at build time + return { + props: { + posts: await Promise.all(posts), + }, + } +} + +export default Blog +``` + +## `getStaticProps` with TypeScript + +You can use the `GetStaticProps` type from `next` to type the function: + +```ts +import { GetStaticProps } from 'next' + +export const getStaticProps: GetStaticProps = async (context) => { + // ... +} +``` + +If you want to get inferred typings for your props, you can use `InferGetStaticPropsType<typeof getStaticProps>`: + +```tsx +import { InferGetStaticPropsType } from 'next' + +type Post = { + author: string + content: string +} + +export const getStaticProps = async () => { + const res = await fetch('https://.../posts') + const posts: Post[] = await res.json() + + return { + props: { + posts, + }, + } +} + +function Blog({ posts }: InferGetStaticPropsType<typeof getStaticProps>) { + // will resolve posts to type Post[] +} + +export default Blog +``` + +## Related + +For more information on what to do next, we recommend the following sections: + +<div class="card"> + <a href="/docs/basic-features/data-fetching/index.md"> + <b>Data Fetching:</b> + <small>Learn more about data fetching in Next.js.</small> + </a> +</div> diff --git a/docs/api-reference/next.config.js/cdn-support-with-asset-prefix.md b/docs/api-reference/next.config.js/cdn-support-with-asset-prefix.md index 20056521d6e78..0383f6ee6e6d2 100644 --- a/docs/api-reference/next.config.js/cdn-support-with-asset-prefix.md +++ b/docs/api-reference/next.config.js/cdn-support-with-asset-prefix.md @@ -42,7 +42,7 @@ While `assetPrefix` covers requests to `_next/static`, it does not influence the - Files in the [public](/docs/basic-features/static-file-serving.md) folder; if you want to serve those assets over a CDN, you'll have to introduce the prefix yourself - `/_next/data/` requests for `getServerSideProps` pages. These requests will always be made against the main domain since they're not static. -- `/_next/data/` requests for `getStaticProps` pages. These requests will always be made against the main domain to support [Incremental Static Generation](/docs/basic-features/data-fetching.md#incremental-static-regeneration), even if you're not using it (for consistency). +- `/_next/data/` requests for `getStaticProps` pages. These requests will always be made against the main domain to support [Incremental Static Generation](/docs/basic-features/data-fetching/incremental-static-regeneration.md), even if you're not using it (for consistency). ## Related diff --git a/docs/api-reference/next.config.js/redirects.md b/docs/api-reference/next.config.js/redirects.md index 6a8e110db82f4..15b370c420814 100644 --- a/docs/api-reference/next.config.js/redirects.md +++ b/docs/api-reference/next.config.js/redirects.md @@ -292,4 +292,4 @@ In some rare cases, you might need to assign a custom status code for older HTTP ## Other Redirects - Inside [API Routes](/docs/api-routes/response-helpers.md), you can use `res.redirect()`. -- Inside [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) and [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering), you can redirect specific pages at request-time. +- Inside [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) and [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md), you can redirect specific pages at request-time. diff --git a/docs/api-reference/next.config.js/rewrites.md b/docs/api-reference/next.config.js/rewrites.md index 3a54cf4288ef9..16ae2b533df85 100644 --- a/docs/api-reference/next.config.js/rewrites.md +++ b/docs/api-reference/next.config.js/rewrites.md @@ -148,7 +148,7 @@ module.exports = { } ``` -Note: for static pages from the [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md) or [prerendering](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) params from rewrites will be parsed on the client after hydration and provided in the query. +Note: for static pages from the [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md) or [prerendering](/docs/basic-features/data-fetching/get-static-props.md) params from rewrites will be parsed on the client after hydration and provided in the query. ## Path Matching diff --git a/docs/api-reference/next/link.md b/docs/api-reference/next/link.md index a7ad63ca27047..0525518af91f6 100644 --- a/docs/api-reference/next/link.md +++ b/docs/api-reference/next/link.md @@ -57,10 +57,10 @@ export default Home - `href` - The path or URL to navigate to. This is the only required prop - `as` - Optional decorator for the path that will be shown in the browser URL bar. Before Next.js 9.5.3 this was used for dynamic routes, check our [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) to see how it worked. Note: when this path differs from the one provided in `href` the previous `href`/`as` behavior is used as shown in the [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes). - [`passHref`](#if-the-child-is-a-custom-component-that-wraps-an-a-tag) - Forces `Link` to send the `href` property to its child. Defaults to `false` -- `prefetch` - Prefetch the page in the background. Defaults to `true`. Any `<Link />` that is in the viewport (initially or through scroll) will be preloaded. Prefetch can be disabled by passing `prefetch={false}`. When `prefetch` is set to `false`, prefetching will still occur on hover. Pages using [Static Generation](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) will preload `JSON` files with the data for faster page transitions. Prefetching is only enabled in production. +- `prefetch` - Prefetch the page in the background. Defaults to `true`. Any `<Link />` that is in the viewport (initially or through scroll) will be preloaded. Prefetch can be disabled by passing `prefetch={false}`. When `prefetch` is set to `false`, prefetching will still occur on hover. Pages using [Static Generation](/docs/basic-features/data-fetching/get-static-props.md) will preload `JSON` files with the data for faster page transitions. Prefetching is only enabled in production. - [`replace`](#replace-the-url-instead-of-push) - Replace the current `history` state instead of adding a new url into the stack. Defaults to `false` - [`scroll`](#disable-scrolling-to-the-top-of-the-page) - Scroll to the top of the page after a navigation. Defaults to `true` -- [`shallow`](/docs/routing/shallow-routing.md) - Update the path of the current page without rerunning [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation), [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) or [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md). Defaults to `false` +- [`shallow`](/docs/routing/shallow-routing.md) - Update the path of the current page without rerunning [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md), [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md) or [`getInitialProps`](/docs/api-reference/data-fetching/get-initial-props.md). Defaults to `false` - `locale` - The active locale is automatically prepended. `locale` allows for providing a different locale. When `false` `href` has to include the locale as the default behavior is disabled. ## If the route has dynamic segments diff --git a/docs/api-reference/next/router.md b/docs/api-reference/next/router.md index 4d5356842fa25..d595c3ac54703 100644 --- a/docs/api-reference/next/router.md +++ b/docs/api-reference/next/router.md @@ -42,9 +42,9 @@ export default ActiveLink The following is the definition of the `router` object returned by both [`useRouter`](#useRouter) and [`withRouter`](#withRouter): - `pathname`: `String` - Current route. That is the path of the page in `/pages`, the configured `basePath` or `locale` is not included. -- `query`: `Object` - The query string parsed to an object. It will be an empty object during prerendering if the page doesn't have [data fetching requirements](/docs/basic-features/data-fetching.md). Defaults to `{}` +- `query`: `Object` - The query string parsed to an object. It will be an empty object during prerendering if the page doesn't have [data fetching requirements](/docs/basic-features/data-fetching/index.md). Defaults to `{}` - `asPath`: `String` - The path (including the query) shown in the browser without the configured `basePath` or `locale`. -- `isFallback`: `boolean` - Whether the current page is in [fallback mode](/docs/basic-features/data-fetching.md#fallback-pages). +- `isFallback`: `boolean` - Whether the current page is in [fallback mode](/docs/api-reference/data-fetching/get-static-paths.md#fallback-pages). - `basePath`: `String` - The active [basePath](/docs/api-reference/next.config.js/basepath.md) (if enabled). - `locale`: `String` - The active locale (if enabled). - `locales`: `String[]` - All supported locales (if enabled). @@ -74,7 +74,7 @@ router.push(url, as, options) - `as`: `UrlObject | String` - Optional decorator for the path that will be shown in the browser URL bar. Before Next.js 9.5.3 this was used for dynamic routes, check our [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) to see how it worked. Note: when this path differs from the one provided in `href` the previous `href`/`as` behavior is used as shown in the [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) - `options` - Optional object with the following configuration options: - `scroll` - Optional boolean, controls scrolling to the top of the page after navigation. Defaults to `true` - - [`shallow`](/docs/routing/shallow-routing.md): Update the path of the current page without rerunning [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation), [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) or [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md). Defaults to `false` + - [`shallow`](/docs/routing/shallow-routing.md): Update the path of the current page without rerunning [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md), [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md) or [`getInitialProps`](/docs/api-reference/data-fetching/get-initial-props.md). Defaults to `false` - `locale` - Optional string, indicates locale of the new page > You don't need to use `router.push` for external URLs. [window.location](https://developer.mozilla.org/en-US/docs/Web/API/Window/location) is better suited for those cases. diff --git a/docs/authentication.md b/docs/authentication.md index 2afc9a05f9cf7..45dc5bbe185a4 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -8,14 +8,14 @@ Authentication verifies who a user is, while authorization controls what a user ## Authentication Patterns -The first step to identifying which authentication pattern you need is understanding the [data-fetching strategy](/docs/basic-features/data-fetching.md) you want. We can then determine which authentication providers support this strategy. There are two main patterns: +The first step to identifying which authentication pattern you need is understanding the [data-fetching strategy](/docs/basic-features/data-fetching/index.md) you want. We can then determine which authentication providers support this strategy. There are two main patterns: - Use [static generation](/docs/basic-features/pages.md#static-generation-recommended) to server-render a loading state, followed by fetching user data client-side. - Fetch user data [server-side](/docs/basic-features/pages.md#server-side-rendering) to eliminate a flash of unauthenticated content. ### Authenticating Statically Generated Pages -Next.js automatically determines that a page is static if there are no blocking data requirements. This means the absence of [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) and `getInitialProps` in the page. Instead, your page can render a loading state from the server, followed by fetching the user client-side. +Next.js automatically determines that a page is static if there are no blocking data requirements. This means the absence of [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md) and `getInitialProps` in the page. Instead, your page can render a loading state from the server, followed by fetching the user client-side. One advantage of this pattern is it allows pages to be served from a global CDN and preloaded using [`next/link`](/docs/api-reference/next/link.md). In practice, this results in a faster TTI ([Time to Interactive](https://web.dev/interactive/)). @@ -52,7 +52,7 @@ You can view this [example in action](https://iron-session-example.vercel.app/). ### Authenticating Server-Rendered Pages -If you export an `async` function called [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) from a page, Next.js will pre-render this page on each request using the data returned by `getServerSideProps`. +If you export an `async` function called [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md) from a page, Next.js will pre-render this page on each request using the data returned by `getServerSideProps`. ```jsx export async function getServerSideProps(context) { @@ -154,7 +154,7 @@ For more information on what to do next, we recommend the following sections: </div> <div class="card"> - <a href="/docs/basic-features/data-fetching.md"> + <a href="/docs/basic-features/data-fetching/index.md"> <b>Data Fetching:</b> <small>Learn more about data fetching in Next.js.</small> </a> diff --git a/docs/basic-features/data-fetching.md b/docs/basic-features/data-fetching.md deleted file mode 100644 index d7d2caaa5c1b8..0000000000000 --- a/docs/basic-features/data-fetching.md +++ /dev/null @@ -1,882 +0,0 @@ ---- -description: 'Next.js has 2 pre-rendering modes: Static Generation and Server-side rendering. Learn how they work here.' ---- - -# Data Fetching - -> This document is for Next.js versions 9.3 and up. If you’re using older versions of Next.js, refer to our [previous documentation](https://nextjs.org/docs/tag/v9.2.2/basic-features/data-fetching). - -<details open> - <summary><b>Examples</b></summary> - <ul> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-wordpress">WordPress Example</a> (<a href="https://next-blog-wordpress.vercel.app">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/blog-starter">Blog Starter using markdown files</a> (<a href="https://next-blog-starter.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-datocms">DatoCMS Example</a> (<a href="https://next-blog-datocms.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-takeshape">TakeShape Example</a> (<a href="https://next-blog-takeshape.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-sanity">Sanity Example</a> (<a href="https://next-blog-sanity.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-prismic">Prismic Example</a> (<a href="https://next-blog-prismic.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-contentful">Contentful Example</a> (<a href="https://next-blog-contentful.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-strapi">Strapi Example</a> (<a href="https://next-blog-strapi.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-prepr">Prepr Example</a> (<a href="https://next-blog-prepr.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-agilitycms">Agility CMS Example</a> (<a href="https://next-blog-agilitycms.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-cosmic">Cosmic Example</a> (<a href="https://next-blog-cosmic.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-buttercms">ButterCMS Example</a> (<a href="https://next-blog-buttercms.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-storyblok">Storyblok Example</a> (<a href="https://next-blog-storyblok.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-graphcms">GraphCMS Example</a> (<a href="https://next-blog-graphcms.vercel.app/">Demo</a>)</li> - <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-kontent">Kontent Example</a> (<a href="https://next-blog-kontent.vercel.app/">Demo</a>)</li> - <li><a href="https://static-tweet.vercel.app/">Static Tweet Demo</a></li> - </ul> -</details> - -In the [Pages documentation](/docs/basic-features/pages.md), we’ve explained that Next.js has two forms of pre-rendering: **Static Generation** and **Server-side Rendering**. In this page, we’ll talk in depth about data fetching strategies for each case. We recommend you to [read through the Pages documentation](/docs/basic-features/pages.md) first if you haven’t done so. - -We’ll talk about the three unique Next.js functions you can use to fetch data for pre-rendering: - -- [`getStaticProps`](#getstaticprops-static-generation) (Static Generation): Fetch data at **build time**. -- [`getStaticPaths`](#getstaticpaths-static-generation) (Static Generation): Specify [dynamic routes](/docs/routing/dynamic-routes.md) to pre-render pages based on data. -- [`getServerSideProps`](#getserversideprops-server-side-rendering) (Server-side Rendering): Fetch data on **each request**. - -In addition, we’ll talk briefly about how to fetch data on the client side. - -## `getStaticProps` (Static Generation) - -<details> - <summary><b>Version History</b></summary> - -| Version | Changes | -| --------- | ----------------------------------------------------------------------------------------------------------------- | -| `v12.0.0` | `staticPageGenerationTimeout` added. | -| `v10.0.0` | `locale`, `locales`, `defaultLocale`, and `notFound` options added. | -| `v9.5.0` | Stable [Incremental Static Regeneration](https://nextjs.org/blog/next-9-5#stable-incremental-static-regeneration) | -| `v9.3.0` | `getStaticProps` introduced. | - -</details> - -If you export an `async` function called `getStaticProps` from a page, Next.js will pre-render this page at build time using the props returned by `getStaticProps`. - -```jsx -export async function getStaticProps(context) { - return { - props: {}, // will be passed to the page component as props - } -} -``` - -The `context` parameter is an object containing the following keys: - -- `params` contains the route parameters for pages using dynamic routes. For example, if the page name is `[id].js` , then `params` will look like `{ id: ... }`. To learn more, take a look at the [Dynamic Routing documentation](/docs/routing/dynamic-routes.md). You should use this together with `getStaticPaths`, which we’ll explain later. -- `preview` is `true` if the page is in the preview mode and `undefined` otherwise. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md). -- `previewData` contains the preview data set by `setPreviewData`. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md). -- `locale` contains the active locale (if you've enabled [Internationalized Routing](/docs/advanced-features/i18n-routing.md)). -- `locales` contains all supported locales (if you've enabled [Internationalized Routing](/docs/advanced-features/i18n-routing.md)). -- `defaultLocale` contains the configured default locale (if you've enabled [Internationalized Routing](/docs/advanced-features/i18n-routing.md)). - -`getStaticProps` should return an object with: - -- `props` - An **optional** object with the props that will be received by the page component. It should be a [serializable object](https://en.wikipedia.org/wiki/Serialization) -- `revalidate` - An **optional** amount in seconds after which a page re-generation can occur. Defaults to `false`. When `revalidate` is `false` it means that there is no revalidation, so the page will be cached as built until your next build. More on [Incremental Static Regeneration](#incremental-static-regeneration) -- `notFound` - An **optional** boolean value to allow the page to return a 404 status and page. Below is an example of how it works: - - ```js - export async function getStaticProps(context) { - const res = await fetch(`https://.../data`) - const data = await res.json() - - if (!data) { - return { - notFound: true, - } - } - - return { - props: { data }, // will be passed to the page component as props - } - } - ``` - - > **Note**: `notFound` is not needed for [`fallback: false`](#fallback-false) mode as only paths returned from `getStaticPaths` will be pre-rendered. - - > **Note**: With `notFound: true` the page will return a 404 even if there was a successfully generated page before. This is meant to support use-cases like user generated content getting removed by its author. - -- `redirect` - An **optional** redirect value to allow redirecting to internal and external resources. It should match the shape of `{ destination: string, permanent: boolean }`. In some rare cases, you might need to assign a custom status code for older HTTP Clients to properly redirect. In these cases, you can use the `statusCode` property instead of the `permanent` property, but not both. You can also set `basePath: false` similar to redirects in `next.config.js`. Below is an example of how it works: - - ```js - export async function getStaticProps(context) { - const res = await fetch(`https://...`) - const data = await res.json() - - if (!data) { - return { - redirect: { - destination: '/', - permanent: false, - }, - } - } - - return { - props: { data }, // will be passed to the page component as props - } - } - ``` - - > **Note**: Redirecting at build-time is currently not allowed and if the redirects are known at build-time they should be added in [`next.config.js`](/docs/api-reference/next.config.js/redirects.md). - -> **Note**: You can import modules in top-level scope for use in `getStaticProps`. -> Imports used in `getStaticProps` will [not be bundled for the client-side](#write-server-side-code-directly). -> -> This means you can write **server-side code directly in `getStaticProps`**. -> This includes reading from the filesystem or a database. - -> **Note**: You should not use [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to -> call an API route in `getStaticProps`. -> Instead, directly import the logic used inside your API route. -> You may need to slightly refactor your code for this approach. -> -> Fetching from an external API is fine! - -### Example - -Here’s an example which uses `getStaticProps` to fetch a list of blog posts from a CMS (content management system). This example is also in the [Pages documentation](/docs/basic-features/pages.md). - -```jsx -// posts will be populated at build time by getStaticProps() -function Blog({ posts }) { - return ( - <ul> - {posts.map((post) => ( - <li>{post.title}</li> - ))} - </ul> - ) -} - -// This function gets called at build time on server-side. -// It won't be called on client-side, so you can even do -// direct database queries. See the "Technical details" section. -export async function getStaticProps() { - // Call an external API endpoint to get posts. - // You can use any data fetching library - const res = await fetch('https://.../posts') - const posts = await res.json() - - // By returning { props: { posts } }, the Blog component - // will receive `posts` as a prop at build time - return { - props: { - posts, - }, - } -} - -export default Blog -``` - -### When should I use `getStaticProps`? - -You should use `getStaticProps` if: - -- The data required to render the page is available at build time ahead of a user’s request. -- The data comes from a headless CMS. -- The data can be publicly cached (not user-specific). -- The page must be pre-rendered (for SEO) and be very fast — `getStaticProps` generates HTML and JSON files, both of which can be cached by a CDN for performance. - -### TypeScript: Use `GetStaticProps` - -For TypeScript, you can use the `GetStaticProps` type from `next`: - -```ts -import { GetStaticProps } from 'next' - -export const getStaticProps: GetStaticProps = async (context) => { - // ... -} -``` - -If you want to get inferred typings for your props, you can use `InferGetStaticPropsType<typeof getStaticProps>`, like this: - -```tsx -import { InferGetStaticPropsType } from 'next' - -type Post = { - author: string - content: string -} - -export const getStaticProps = async () => { - const res = await fetch('https://.../posts') - const posts: Post[] = await res.json() - - return { - props: { - posts, - }, - } -} - -function Blog({ posts }: InferGetStaticPropsType<typeof getStaticProps>) { - // will resolve posts to type Post[] -} - -export default Blog -``` - -Note: Next.js has a default static generation timeout of 60 seconds. If no new pages complete generating within the timeout, it will attempt generation three more times. If the fourth attempt fails, the build will fail. This timeout can be modified using the following configuration: - -```js -// next.config.js -module.exports = { - // time in seconds of no pages generating during static - // generation before timing out - staticPageGenerationTimeout: 90, -} -``` - -### Incremental Static Regeneration - -<details open> - <summary><b>Examples</b></summary> - <ul> - <li><a href="https://nextjs.org/commerce">Next.js Commerce</a></li> - <li><a href="https://reactions-demo.vercel.app/">GitHub Reactions Demo</a></li> - <li><a href="https://static-tweet.vercel.app/">Static Tweet Demo</a></li> - </ul> -</details> - -<details> - <summary><b>Version History</b></summary> - -| Version | Changes | -| -------- | ---------------- | -| `v9.5.0` | Base Path added. | - -</details> - -Next.js allows you to create or update static pages _after_ you’ve built your site. Incremental Static Regeneration (ISR) enables you to use static-generation on a per-page basis, **without needing to rebuild the entire site**. With ISR, you can retain the benefits of static while scaling to millions of pages. - -Consider our previous [`getStaticProps` example](#simple-example), but now with Incremental Static Regeneration enabled through the `revalidate` property: - -```jsx -function Blog({ posts }) { - return ( - <ul> - {posts.map((post) => ( - <li>{post.title}</li> - ))} - </ul> - ) -} - -// This function gets called at build time on server-side. -// It may be called again, on a serverless function, if -// revalidation is enabled and a new request comes in -export async function getStaticProps() { - const res = await fetch('https://.../posts') - const posts = await res.json() - - return { - props: { - posts, - }, - // Next.js will attempt to re-generate the page: - // - When a request comes in - // - At most once every 10 seconds - revalidate: 10, // In seconds - } -} - -// This function gets called at build time on server-side. -// It may be called again, on a serverless function, if -// the path has not been generated. -export async function getStaticPaths() { - const res = await fetch('https://.../posts') - const posts = await res.json() - - // Get the paths we want to pre-render based on posts - const paths = posts.map((post) => ({ - params: { id: post.id }, - })) - - // We'll pre-render only these paths at build time. - // { fallback: blocking } will server-render pages - // on-demand if the path doesn't exist. - return { paths, fallback: 'blocking' } -} - -export default Blog -``` - -When a request is made to a page that was pre-rendered at build time, it will initially show the cached page. - -- Any requests to the page after the initial request and before 10 seconds are also cached and instantaneous. -- After the 10-second window, the next request will still show the cached (stale) page -- Next.js triggers a regeneration of the page in the background. -- Once the page has been successfully generated, Next.js will invalidate the cache and show the updated product page. If the background regeneration fails, the old page will stay unaltered. - -When a request is made to a path that hasn’t been generated, Next.js will server-render the page on the first request. Future requests will serve the static file from the cache. - -To learn how to persist the cache globally and handle rollbacks, learn more about [Incremental Static Regeneration](https://vercel.com/docs/next.js/incremental-static-regeneration). - -### Reading files: Use `process.cwd()` - -Files can be read directly from the filesystem in `getStaticProps`. - -In order to do so you have to get the full path to a file. - -Since Next.js compiles your code into a separate directory you can't use `__dirname` as the path it will return will be different from the pages directory. - -Instead you can use `process.cwd()` which gives you the directory where Next.js is being executed. - -```jsx -import { promises as fs } from 'fs' -import path from 'path' - -// posts will be populated at build time by getStaticProps() -function Blog({ posts }) { - return ( - <ul> - {posts.map((post) => ( - <li> - <h3>{post.filename}</h3> - <p>{post.content}</p> - </li> - ))} - </ul> - ) -} - -// This function gets called at build time on server-side. -// It won't be called on client-side, so you can even do -// direct database queries. See the "Technical details" section. -export async function getStaticProps() { - const postsDirectory = path.join(process.cwd(), 'posts') - const filenames = await fs.readdir(postsDirectory) - - const posts = filenames.map(async (filename) => { - const filePath = path.join(postsDirectory, filename) - const fileContents = await fs.readFile(filePath, 'utf8') - - // Generally you would parse/transform the contents - // For example you can transform markdown to HTML here - - return { - filename, - content: fileContents, - } - }) - // By returning { props: { posts } }, the Blog component - // will receive `posts` as a prop at build time - return { - props: { - posts: await Promise.all(posts), - }, - } -} - -export default Blog -``` - -### Technical details - -#### Only runs at build time - -Because `getStaticProps` runs at build time, it does **not** receive data that’s only available during request time, such as query parameters or HTTP headers as it generates static HTML. - -#### Write server-side code directly - -Note that `getStaticProps` runs only on the server-side. It will never be run on the client-side. It won’t even be included in the JS bundle for the browser. That means you can write code such as direct database queries without them being sent to browsers. You should not fetch an **API route** from `getStaticProps` — instead, you can write the server-side code directly in `getStaticProps`. - -You can use [this tool](https://next-code-elimination.vercel.app/) to verify what Next.js eliminates from the client-side bundle. - -#### Statically Generates both HTML and JSON - -When a page with `getStaticProps` is pre-rendered at build time, in addition to the page HTML file, Next.js generates a JSON file holding the result of running `getStaticProps`. - -This JSON file will be used in client-side routing through `next/link` ([documentation](/docs/api-reference/next/link.md)) or `next/router` ([documentation](/docs/api-reference/next/router.md)). When you navigate to a page that’s pre-rendered using `getStaticProps`, Next.js fetches this JSON file (pre-computed at build time) and uses it as the props for the page component. This means that client-side page transitions will **not** call `getStaticProps` as only the exported JSON is used. - -When using Incremental Static Generation `getStaticProps` will be executed out of band to generate the JSON needed for client-side navigation. You may see this in the form of multiple requests being made for the same page, however, this is intended and has no impact on end-user performance. - -#### Only allowed in a page - -`getStaticProps` can only be exported from a **page**. You can’t export it from non-page files. - -One of the reasons for this restriction is that React needs to have all the required data before the page is rendered. - -Also, you must use `export async function getStaticProps() {}` — it will **not** work if you add `getStaticProps` as a property of the page component. - -#### Runs on every request in development - -In development (`next dev`), `getStaticProps` will be called on every request. - -#### Preview Mode - -In some cases, you might want to temporarily bypass Static Generation and render the page at **request time** instead of build time. For example, you might be using a headless CMS and want to preview drafts before they're published. - -This use case is supported by Next.js by the feature called **Preview Mode**. Learn more on the [Preview Mode documentation](/docs/advanced-features/preview-mode.md). - -## `getStaticPaths` (Static Generation) - -<details> - <summary><b>Version History</b></summary> - -| Version | Changes | -| -------- | ----------------------------------------------------------------------------------------------------------------- | -| `v9.5.0` | Stable [Incremental Static Regeneration](https://nextjs.org/blog/next-9-5#stable-incremental-static-regeneration) | -| `v9.3.0` | `getStaticPaths` introduced. | - -</details> - -If a page has dynamic routes ([documentation](/docs/routing/dynamic-routes.md)) and uses `getStaticProps` it needs to define a list of paths that have to be rendered to HTML at build time. - -If you export an `async` function called `getStaticPaths` from a page that uses dynamic routes, Next.js will statically pre-render all the paths specified by `getStaticPaths`. - -```jsx -export async function getStaticPaths() { - return { - paths: [ - { params: { ... } } // See the "paths" section below - ], - fallback: true, false, or 'blocking' // See the "fallback" section below - }; -} -``` - -#### The `paths` key (required) - -The `paths` key determines which paths will be pre-rendered. For example, suppose that you have a page that uses dynamic routes named `pages/posts/[id].js`. If you export `getStaticPaths` from this page and return the following for `paths`: - -```js -return { - paths: [ - { params: { id: '1' } }, - { params: { id: '2' } } - ], - fallback: ... -} -``` - -Then Next.js will statically generate `posts/1` and `posts/2` at build time using the page component in `pages/posts/[id].js`. - -Note that the value for each `params` must match the parameters used in the page name: - -- If the page name is `pages/posts/[postId]/[commentId]`, then `params` should contain `postId` and `commentId`. -- If the page name uses catch-all routes, for example `pages/[...slug]`, then `params` should contain `slug` which is an array. For example, if this array is `['foo', 'bar']`, then Next.js will statically generate the page at `/foo/bar`. -- If the page uses an optional catch-all route, supply `null`, `[]`, `undefined` or `false` to render the root-most route. For example, if you supply `slug: false` for `pages/[[...slug]]`, Next.js will statically generate the page `/`. - -#### The `fallback` key (required) - -The object returned by `getStaticPaths` must contain a boolean `fallback` key. - -#### `fallback: false` - -If `fallback` is `false`, then any paths not returned by `getStaticPaths` will result in a **404 page**. You can do this if you have a small number of paths to pre-render - so they are all statically generated during build time. It’s also useful when the new pages are not added often. If you add more items to the data source and need to render the new pages, you’d need to run the build again. - -Here’s an example which pre-renders one blog post per page called `pages/posts/[id].js`. The list of blog posts will be fetched from a CMS and returned by `getStaticPaths` . Then, for each page, it fetches the post data from a CMS using `getStaticProps`. This example is also in the [Pages documentation](/docs/basic-features/pages.md). - -```jsx -// pages/posts/[id].js - -function Post({ post }) { - // Render post... -} - -// This function gets called at build time -export async function getStaticPaths() { - // Call an external API endpoint to get posts - const res = await fetch('https://.../posts') - const posts = await res.json() - - // Get the paths we want to pre-render based on posts - const paths = posts.map((post) => ({ - params: { id: post.id }, - })) - - // We'll pre-render only these paths at build time. - // { fallback: false } means other routes should 404. - return { paths, fallback: false } -} - -// This also gets called at build time -export async function getStaticProps({ params }) { - // params contains the post `id`. - // If the route is like /posts/1, then params.id is 1 - const res = await fetch(`https://.../posts/${params.id}`) - const post = await res.json() - - // Pass post data to the page via props - return { props: { post } } -} - -export default Post -``` - -#### `fallback: true` - -<details> - <summary><b>Examples</b></summary> - <ul> - <li><a href="https://static-tweet.vercel.app">Static generation of a large number of pages</a></li> - </ul> -</details> - -If `fallback` is `true`, then the behavior of `getStaticProps` changes: - -- The paths returned from `getStaticPaths` will be rendered to HTML at build time by `getStaticProps`. -- The paths that have not been generated at build time will **not** result in a 404 page. Instead, Next.js will serve a “fallback” version of the page on the first request to such a path (see [“Fallback pages”](#fallback-pages) below for details). Note: this "fallback" version will not be served for crawlers like Google and instead will render the path in `blocking` mode. -- In the background, Next.js will statically generate the requested path HTML and JSON. This includes running `getStaticProps`. -- When that’s done, the browser receives the JSON for the generated path. This will be used to automatically render the page with the required props. From the user’s perspective, the page will be swapped from the fallback page to the full page. -- At the same time, Next.js adds this path to the list of pre-rendered pages. Subsequent requests to the same path will serve the generated page, like other pages pre-rendered at build time. - -> `fallback: true` is not supported when using [`next export`](/docs/advanced-features/static-html-export.md). - -#### Fallback pages - -In the “fallback” version of a page: - -- The page’s props will be empty. -- Using the [router](/docs/api-reference/next/router.md), you can detect if the fallback is being rendered, `router.isFallback` will be `true`. - -Here’s an example that uses `isFallback`: - -```jsx -// pages/posts/[id].js -import { useRouter } from 'next/router' - -function Post({ post }) { - const router = useRouter() - - // If the page is not yet generated, this will be displayed - // initially until getStaticProps() finishes running - if (router.isFallback) { - return <div>Loading...</div> - } - - // Render post... -} - -// This function gets called at build time -export async function getStaticPaths() { - return { - // Only `/posts/1` and `/posts/2` are generated at build time - paths: [{ params: { id: '1' } }, { params: { id: '2' } }], - // Enable statically generating additional pages - // For example: `/posts/3` - fallback: true, - } -} - -// This also gets called at build time -export async function getStaticProps({ params }) { - // params contains the post `id`. - // If the route is like /posts/1, then params.id is 1 - const res = await fetch(`https://.../posts/${params.id}`) - const post = await res.json() - - // Pass post data to the page via props - return { - props: { post }, - // Re-generate the post at most once per second - // if a request comes in - revalidate: 1, - } -} - -export default Post -``` - -#### When is `fallback: true` useful? - -`fallback: true` is useful if your app has a very large number of static pages that depend on data (think: a very large e-commerce site). You want to pre-render all product pages, but then your builds would take forever. - -Instead, you may statically generate a small subset of pages and use `fallback: true` for the rest. When someone requests a page that’s not generated yet, the user will see the page with a loading indicator. Shortly after, `getStaticProps` finishes and the page will be rendered with the requested data. From now on, everyone who requests the same page will get the statically pre-rendered page. - -This ensures that users always have a fast experience while preserving fast builds and the benefits of Static Generation. - -`fallback: true` will not _update_ generated pages, for that take a look at [Incremental Static Regeneration](#incremental-static-regeneration). - -#### `fallback: 'blocking'` - -If `fallback` is `'blocking'`, new paths not returned by `getStaticPaths` will wait for the HTML to be generated, identical to SSR (hence why _blocking_), and then be cached for future requests so it only happens once per path. - -`getStaticProps` will behave as follows: - -- The paths returned from `getStaticPaths` will be rendered to HTML at build time by `getStaticProps`. -- The paths that have not been generated at build time will **not** result in a 404 page. Instead, Next.js will SSR on the first request and return the generated HTML. -- When that’s done, the browser receives the HTML for the generated path. From the user’s perspective, it will transition from "the browser is requesting the page" to "the full page is loaded". There is no flash of loading/fallback state. -- At the same time, Next.js adds this path to the list of pre-rendered pages. Subsequent requests to the same path will serve the generated page, like other pages pre-rendered at build time. - -`fallback: 'blocking'` will not _update_ generated pages by default. To update generated pages, use [Incremental Static Regeneration](#incremental-static-regeneration) in conjunction with `fallback: 'blocking'`. - -> `fallback: 'blocking'` is not supported when using [`next export`](/docs/advanced-features/static-html-export.md). - -### When should I use `getStaticPaths`? - -You should use `getStaticPaths` if you’re statically pre-rendering pages that use dynamic routes. - -### TypeScript: Use `GetStaticPaths` - -For TypeScript, you can use the `GetStaticPaths` type from `next`: - -```ts -import { GetStaticPaths } from 'next' - -export const getStaticPaths: GetStaticPaths = async () => { - // ... -} -``` - -### Technical details - -#### Use together with `getStaticProps` - -When you use `getStaticProps` on a page with dynamic route parameters, you must use `getStaticPaths`. - -You cannot use `getStaticPaths` with `getServerSideProps`. - -#### Only runs at build time on server-side - -`getStaticPaths` only runs at build time on server-side. - -#### Only allowed in a page - -`getStaticPaths` can only be exported from a **page**. You can’t export it from non-page files. - -Also, you must use `export async function getStaticPaths() {}` — it will **not** work if you add `getStaticPaths` as a property of the page component. - -#### Runs on every request in development - -In development (`next dev`), `getStaticPaths` will be called on every request. - -## `getServerSideProps` (Server-side Rendering) - -<details> - <summary><b>Version History</b></summary> - -| Version | Changes | -| --------- | ------------------------------------------------------------------- | -| `v10.0.0` | `locale`, `locales`, `defaultLocale`, and `notFound` options added. | -| `v9.3.0` | `getServerSideProps` introduced. | - -</details> - -If you export an `async` function called `getServerSideProps` from a page, Next.js will pre-render this page on each request using the data returned by `getServerSideProps`. - -```js -export async function getServerSideProps(context) { - return { - props: {}, // will be passed to the page component as props - } -} -``` - -The `context` parameter is an object containing the following keys: - -- `params`: If this page uses a dynamic route, `params` contains the route parameters. If the page name is `[id].js` , then `params` will look like `{ id: ... }`. To learn more, take a look at the [Dynamic Routing documentation](/docs/routing/dynamic-routes.md). -- `req`: [The HTTP IncomingMessage object](https://nodejs.org/api/http.html#http_class_http_incomingmessage), plus additional [built-in parsing helpers](#provided-req-middleware-in-getserversideprops). -- `res`: [The HTTP response object](https://nodejs.org/api/http.html#http_class_http_serverresponse). -- `query`: An object representing the query string. -- `preview`: `preview` is `true` if the page is in the preview mode and `false` otherwise. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md). -- `previewData`: The preview data set by `setPreviewData`. See the [Preview Mode documentation](/docs/advanced-features/preview-mode.md). -- `resolvedUrl`: A normalized version of the request URL that strips the `_next/data` prefix for client transitions and includes original query values. -- `locale` contains the active locale (if you've enabled [Internationalized Routing](/docs/advanced-features/i18n-routing.md)). -- `locales` contains all supported locales (if you've enabled [Internationalized Routing](/docs/advanced-features/i18n-routing.md)). -- `defaultLocale` contains the configured default locale (if you've enabled [Internationalized Routing](/docs/advanced-features/i18n-routing.md)). - -`getServerSideProps` should return an object with: - -- `props` - An **optional** object with the props that will be received by the page component. It should be a [serializable object](https://en.wikipedia.org/wiki/Serialization) or a Promise that resolves to a serializable object. -- `notFound` - An **optional** boolean value to allow the page to return a 404 status and page. Below is an example of how it works: - - ```js - export async function getServerSideProps(context) { - const res = await fetch(`https://...`) - const data = await res.json() - - if (!data) { - return { - notFound: true, - } - } - - return { - props: {}, // will be passed to the page component as props - } - } - ``` - -- `redirect` - An **optional** redirect value to allow redirecting to internal and external resources. It should match the shape of `{ destination: string, permanent: boolean }`. In some rare cases, you might need to assign a custom status code for older HTTP Clients to properly redirect. In these cases, you can use the `statusCode` property instead of the `permanent` property, but not both. You can also set `basePath: false` similar to redirects in `next.config.js`. Below is an example of how it works: - - ```js - export async function getServerSideProps(context) { - const res = await fetch(`https://.../data`) - const data = await res.json() - - if (!data) { - return { - redirect: { - destination: '/', - permanent: false, - }, - } - } - - return { - props: {}, // will be passed to the page component as props - } - } - ``` - -> **Note**: You can import modules in top-level scope for use in `getServerSideProps`. -> Imports used in `getServerSideProps` will not be bundled for the client-side. -> -> This means you can write **server-side code directly in `getServerSideProps`**. -> This includes reading from the filesystem or a database. - -> **Note**: You should not use [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to -> call an API route in `getServerSideProps`. -> Instead, directly import the logic used inside your API route. -> You may need to slightly refactor your code for this approach. -> -> Fetching from an external API is fine! - -### Provided `req` middleware in `getServerSideProps` - -The `req` in the context passed to `getServerSideProps` provides built in middleware that parses the incoming request (req). That middleware is: - -- `req.cookies` - An object containing the cookies sent by the request. Defaults to `{}` - -### Example - -Here’s an example which uses `getServerSideProps` to fetch data at request time and pre-renders it. This example is also in the [Pages documentation](/docs/basic-features/pages.md). - -```jsx -function Page({ data }) { - // Render data... -} - -// This gets called on every request -export async function getServerSideProps() { - // Fetch data from external API - const res = await fetch(`https://.../data`) - const data = await res.json() - - // Pass data to the page via props - return { props: { data } } -} - -export default Page -``` - -### When should I use `getServerSideProps`? - -You should use `getServerSideProps` only if you need to pre-render a page whose data must be fetched at request time. Time to first byte (TTFB) will be slower than `getStaticProps` because the server must compute the result on every request, and the result cannot be cached by a CDN without extra configuration. - -If you don’t need to pre-render the data, then you should consider fetching data on the client side. [Click here to learn more](#fetching-data-on-the-client-side). - -### TypeScript: Use `GetServerSideProps` - -For TypeScript, you can use the `GetServerSideProps` type from `next`: - -```ts -import { GetServerSideProps } from 'next' - -export const getServerSideProps: GetServerSideProps = async (context) => { - // ... -} -``` - -If you want to get inferred typings for your props, you can use `InferGetServerSidePropsType<typeof getServerSideProps>`, like this: - -```tsx -import { InferGetServerSidePropsType } from 'next' - -type Data = { ... } - -export const getServerSideProps = async () => { - const res = await fetch('https://.../data') - const data: Data = await res.json() - - return { - props: { - data, - }, - } -} - -function Page({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) { - // will resolve posts to type Data -} - -export default Page -``` - -### Technical details - -#### Only runs on server-side - -`getServerSideProps` only runs on server-side and never runs on the browser. If a page uses `getServerSideProps`, then: - -- When you request this page directly, `getServerSideProps` runs at the request time, and this page will be pre-rendered with the returned props. -- When you request this page on client-side page transitions through `next/link` ([documentation](/docs/api-reference/next/link.md)) or `next/router` ([documentation](/docs/api-reference/next/router.md)), Next.js sends an API request to the server, which runs `getServerSideProps`. It’ll return JSON that contains the result of running `getServerSideProps`, and the JSON will be used to render the page. All this work will be handled automatically by Next.js, so you don’t need to do anything extra as long as you have `getServerSideProps` defined. - -You can use [this tool](https://next-code-elimination.vercel.app/) to verify what Next.js eliminates from the client-side bundle. - -#### Only allowed in a page - -`getServerSideProps` can only be exported from a **page**. You can’t export it from non-page files. - -Also, you must use `export async function getServerSideProps() {}` — it will **not** work if you add `getServerSideProps` as a property of the page component. - -## Fetching data on the client side - -If your page contains frequently updating data, and you don’t need to pre-render the data, you can fetch the data on the client side. An example of this is user-specific data. Here’s how it works: - -- First, immediately show the page without data. Parts of the page can be pre-rendered using Static Generation. You can show loading states for missing data. -- Then, fetch the data on the client side and display it when ready. - -This approach works well for user dashboard pages, for example. Because a dashboard is a private, user-specific page, SEO is not relevant and the page doesn’t need to be pre-rendered. The data is frequently updated, which requires request-time data fetching. - -### SWR - -The team behind Next.js has created a React hook for data fetching called [**SWR**](https://swr.vercel.app/). We highly recommend it if you’re fetching data on the client side. It handles caching, revalidation, focus tracking, refetching on interval, and more. And you can use it like so: - -```jsx -import useSWR from 'swr' - -const fetcher = (url) => fetch(url).then((res) => res.json()) - -function Profile() { - const { data, error } = useSWR('/api/user', fetcher) - - if (error) return <div>failed to load</div> - if (!data) return <div>loading...</div> - return <div>hello {data.name}!</div> -} -``` - -[Check out the SWR documentation to learn more](https://swr.vercel.app/). - -## Learn more - -We recommend you to read the following sections next: - -<div class="card"> - <a href="/docs/advanced-features/preview-mode.md"> - <b>Preview Mode:</b> - <small>Learn more about the preview mode in Next.js.</small> - </a> -</div> - -<div class="card"> - <a href="/docs/routing/introduction.md"> - <b>Routing:</b> - <small>Learn more about routing in Next.js.</small> - </a> -</div> - -<div class="card"> - <a href="/docs/basic-features/typescript.md#pages"> - <b>TypeScript:</b> - <small>Add TypeScript to your pages.</small> - </a> -</div> diff --git a/docs/basic-features/data-fetching/client-side.md b/docs/basic-features/data-fetching/client-side.md new file mode 100644 index 0000000000000..6c0837e191d12 --- /dev/null +++ b/docs/basic-features/data-fetching/client-side.md @@ -0,0 +1,70 @@ +--- +description: 'Learn about client-side data fetching, and how to use SWR, a data fetching React hook library that handles caching, revalidation, focus tracking, refetching on interval and more.' +--- + +# Client-side data fetching + +Client-side data fetching is useful when your page doesn't require SEO indexing, when you don't need to pre-render your data, or when the content of your pages needs to update frequently. Unlike the server-side rendering APIs, you can use client-side data fetching at the component level. + +If done at the page level, the data is fetched at runtime, and the content of the page is updated as the data changes. When used at the component level, the data is fetched at the time of the component mount, and the content of the component is updated as the data changes. + +It's important to note that using client-side data fetching can affect the performance of your application and the load speed of your pages. This is because the data fetching is done at the time of the component or pages mount, and the data is not cached. + +## Client-side data fetching with useEffect + +The following example shows how you can fetch data on the client side using the useEffect hook. + +```jsx +function Profile() { + const [data, setData] = useState(null) + const [isLoading, setLoading] = useState(false) + + useEffect(() => { + setLoading(true) + fetch('api/profile-data') + .then((res) => res.json()) + .then((data) => { + setData(data) + setLoading(false) + }) + }, []) + + if (isLoading) return <p>Loading...</p> + if (!profileData) return <p>No profile data</p> + + return ( + <div> + <h1>{data.name}</h1> + <p>{data.bio}</p> + </div> + ) +} +``` + +## Client-side data fetching with SWR + +The team behind Next.js has created a React hook library for data fetching called [**SWR**](https://swr.vercel.app/). It is **highly recommend** if you are fetching data on the client-side. It handles caching, revalidation, focus tracking, refetching on intervals, and more. + +Using the same example as above, we can now use SWR to fetch the profile data. SWR will automatically cache the data for us and will revalidate the data if it becomes stale. + +For more information on using SWR, check out the [SWR docs](https://swr.vercel.app/docs). + +```jsx +import useSWR from 'swr' + +const fetcher = (...args) => fetch(...args).then((res) => res.json()) + +function Profile() { + const { data, error } = useSWR('/api/profile-data', fetcher) + + if (error) return <div>Failed to load</div> + if (!data) return <div>Loading...</div> + + return ( + <div> + <h1>{data.name}</h1> + <p>{data.bio}</p> + </div> + ) +} +``` diff --git a/docs/basic-features/data-fetching/get-server-side-props.md b/docs/basic-features/data-fetching/get-server-side-props.md new file mode 100644 index 0000000000000..2e28a45cbb89d --- /dev/null +++ b/docs/basic-features/data-fetching/get-server-side-props.md @@ -0,0 +1,75 @@ +--- +description: Fetch data on each request with `getServerSideProps`. +--- + +# `getServerSideProps` + +If you export a function called `getServerSideProps` (Server-Side Rendering) from a page, Next.js will pre-render this page on each request using the data returned by `getServerSideProps`. + +```js +export async function getServerSideProps(context) { + return { + props: {}, // will be passed to the page component as props + } +} +``` + +## When does `getServerSideProps` run + +`getServerSideProps` only runs on server-side and never runs on the browser. If a page uses `getServerSideProps`, then: + +- When you request this page directly, `getServerSideProps` runs at request time, and this page will be pre-rendered with the returned props +- When you request this page on client-side page transitions through [`next/link`](/docs/api-reference/next/link.md) or [`next/router`](/docs/api-reference/next/router.md), Next.js sends an API request to the server, which runs `getServerSideProps`. + +It then returns `JSON` that contains the result of running `getServerSideProps`, that `JSON` will be used to render the page. All this work will be handled automatically by Next.js, so you don’t need to do anything extra as long as you have `getServerSideProps` defined. + +You can use the [next-code-elimination tool](https://next-code-elimination.vercel.app/) to verify what Next.js eliminates from the client-side bundle. + +`getServerSideProps` can only be exported from a **page**. You can’t export it from non-page files. + +Note that you must export `getServerSideProps` as a standalone function — it will **not** work if you add `getServerSideProps` as a property of the page component. + +The [`getServerSideProps` API reference](/docs/api-reference/data-fetching/get-server-side-props.md) covers all parameters and props that can be used with `getServerSideProps`. + +## When should I use `getServerSideProps`? + +You should use `getServerSideProps` only if you need to pre-render a page whose data must be fetched at request time. [Time to First Byte (TTFB)](/learn/seo/web-performance) will be higher than [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) because the server must compute the result on every request, and the result can only be cached by a CDN using `cache-control` headers (which could require extra configuration). + +If you do not need to pre-render the data, then you should consider fetching data on the [client side](#fetching-data-on-the-client-side). + +### `getServerSideProps` or API Routes + +It can be tempting to reach for an [API Route](/docs/api-routes/introduction.md) when you want to fetch data from the server, then call that API route from `getServerSideProps`. This is an unnecessary and inefficient approach, as it will cause an extra request to be made due to both `getServerSideProps` and API Routes running on the server. + +Take the following example. An API route is used to fetch some data from a CMS. That API route is then called directly from `getServerSideProps`. This produces an additional call, reducing performance. Instead, directly import the logic used inside your API Route into `getServerSideProps`. This could mean calling a CMS, database, or other API directly from inside `getServerSideProps`. + +## Fetching data on the client side + +If your page contains frequently updating data, and you don’t need to pre-render the data, you can fetch the data on the [client side](/docs/basic-features/client-side.md). An example of this is user-specific data: + +- First, immediately show the page without data. Parts of the page can be pre-rendered using Static Generation. You can show loading states for missing data. +- Then, fetch the data on the client side and display it when ready. + +This approach works well for user dashboard pages, for example. Because a dashboard is a private, user-specific page, SEO is not relevant and the page doesn’t need to be pre-rendered. The data is frequently updated, which requires request-time data fetching. + +## Using `getServerSideProps` to fetch data at request time + +The following example shows how to fetch data at request time and pre-render the result. + +```jsx +function Page({ data }) { + // Render data... +} + +// This gets called on every request +export async function getServerSideProps() { + // Fetch data from external API + const res = await fetch(`https://.../data`) + const data = await res.json() + + // Pass data to the page via props + return { props: { data } } +} + +export default Page +``` diff --git a/docs/basic-features/data-fetching/get-static-paths.md b/docs/basic-features/data-fetching/get-static-paths.md new file mode 100644 index 0000000000000..9ba7a450928f9 --- /dev/null +++ b/docs/basic-features/data-fetching/get-static-paths.md @@ -0,0 +1,48 @@ +--- +description: Fetch data and generate static pages with `getStaticProps`. Learn more about this API for data fetching in Next.js. +--- + +# `getStaticPaths` + +If a page has [Dynamic Routes](/docs/routing/dynamic-routes.md) and uses `getStaticProps`, it needs to define a list of paths to be statically generated. + +When you export a function called `getStaticPaths` (Static Site Generation) from a page that uses dynamic routes, Next.js will statically pre-render all the paths specified by `getStaticPaths`. + +```jsx +export async function getStaticPaths() { + return { + paths: [ + { params: { ... } } + ], + fallback: true // false or 'blocking' + }; +} +``` + +Note that`getStaticProps` **must** be used with `getStaticPaths`, and that you **cannot** use it with [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md). + +The [`getStaticPaths` API reference](/docs/api-reference/data-fetching/get-static-paths.md) covers all parameters and props that can be used with `getStaticPaths`. + +## When should I use `getStaticPaths`? + +You should use `getStaticPaths` if you’re statically pre-rendering pages that use dynamic routes and: + +- The data comes from a headless CMS +- The data comes from a database +- The data comes from the filesystem +- The data can be publicly cached (not user-specific) +- The page must be pre-rendered (for SEO) and be very fast — `getStaticProps` generates `HTML` and `JSON` files, both of which can be cached by a CDN for performance + +## When does `getStaticPaths` run + +`getStaticPaths` only runs at build time on server-side. If you're using [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md), `getStaticPaths` can also be run on-demand _in the background_, but still only on the server-side. + +## Where can I use `getStaticPaths` + +`getStaticPaths` can only be exported from a **page**. You **cannot** export it from non-page files. + +Note that you must use export `getStaticPaths` as a standalone function — it will **not** work if you add `getStaticPaths` as a property of the page component. + +## Runs on every request in development + +In development (`next dev`), `getStaticPaths` will be called on every request. diff --git a/docs/basic-features/data-fetching/get-static-props.md b/docs/basic-features/data-fetching/get-static-props.md new file mode 100644 index 0000000000000..adb8427fab01c --- /dev/null +++ b/docs/basic-features/data-fetching/get-static-props.md @@ -0,0 +1,103 @@ +--- +description: Fetch data and generate static pages with `getStaticProps`. Learn more about this API for data fetching in Next.js. +--- + +# `getStaticProps` + +If you export a function called `getStaticProps` (Static Site Generation) from a page, Next.js will pre-render this page at build time using the props returned by `getStaticProps`. + +```jsx +export async function getStaticProps(context) { + return { + props: {}, // will be passed to the page component as props + } +} +``` + +## When should I use `getStaticProps`? + +You should use `getStaticProps` if: + +- The data required to render the page is available at build time ahead of a user’s request +- The data comes from a headless CMS +- The data can be publicly cached (not user-specific) +- The page must be pre-rendered (for SEO) and be very fast — `getStaticProps` generates `HTML` and `JSON` files, both of which can be cached by a CDN for performance + +Because `getStaticProps` runs at build time, it does **not** receive data that’s only available during request time, such as query parameters or `HTTP` headers, as it generates static `HTML`. When combined with [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md) however, it will run in the background while the stale page is being revalidated, and the fresh page served to the browser. + +## Using `getStaticProps` to fetch data from a CMS + +The following example shows how you can fetch a list of blog posts from a CMS. + +```jsx +// posts will be populated at build time by getStaticProps() +function Blog({ posts }) { + return ( + <ul> + {posts.map((post) => ( + <li>{post.title}</li> + ))} + </ul> + ) +} + +// This function gets called at build time on server-side. +// It won't be called on client-side, so you can even do +// direct database queries. +export async function getStaticProps() { + // Call an external API endpoint to get posts. + // You can use any data fetching library + const res = await fetch('https://.../posts') + const posts = await res.json() + + // By returning { props: { posts } }, the Blog component + // will receive `posts` as a prop at build time + return { + props: { + posts, + }, + } +} + +export default Blog +``` + +The [`getStaticProps` API reference](/docs/api-reference/data-fetching/get-static-props.md) covers all parameters and props that can be used with `getStaticProps`. + +## Write server-side code directly + +As `getStaticProps` runs only on the server-side, it will never run on the client-side. It won’t even be included in the JS bundle for the browser, so you can write direct database queries without them being sent to browsers. + +This means that instead of fetching an **API route** from `getStaticProps` (that itself fetches data from an external source), you can write the server-side code directly in `getStaticProps`. + +Take the following example. An API route is used to fetch some data from a CMS. That API route is then called directly from `getStaticProps`. This produces an additional call, reducing performance. Instead, the logic for fetching the data from the CMS can be moved to `getStaticProps`. + +Alternatively, if you are **not** using API routes to fetch data, then the [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) API _can_ be used directly in `getStaticProps` to fetch data. + +To verify what Next.js eliminates from the client-side bundle, you can use the [next-code-elimination tool](https://next-code-elimination.vercel.app/). + +## Statically Generates both HTML and JSON + +When a page with `getStaticProps` is pre-rendered at build time, in addition to the page HTML file, Next.js generates a JSON file holding the result of running `getStaticProps`. + +This JSON file will be used in client-side routing through [`next/link`](/docs/api-reference/next/link.md) or [`next/router`](/docs/api-reference/next/router.md). When you navigate to a page that’s pre-rendered using `getStaticProps`, Next.js fetches this JSON file (pre-computed at build time) and uses it as the props for the page component. This means that client-side page transitions will **not** call `getStaticProps` as only the exported JSON is used. + +When using Incremental Static Generation `getStaticProps` will be executed out of band to generate the JSON needed for client-side navigation. You may see this in the form of multiple requests being made for the same page, however, this is intended and has no impact on end-user performance + +## Where can I use `getStaticProps` + +`getStaticProps` can only be exported from a **page**. You **cannot** export it from non-page files. + +One of the reasons for this restriction is that React needs to have all the required data before the page is rendered. + +Also, you must use export `getStaticProps` as a standalone function — it will **not** work if you add `getStaticProps` as a property of the page component. + +## Runs on every request in development + +In development (`next dev`), `getStaticProps` will be called on every request. + +## Preview Mode + +In some cases, you might want to temporarily bypass Static Generation and render the page at **request time** instead of build time. For example, you might be using a headless CMS and want to preview drafts before they're published. + +This use case is supported in Next.js by the [**Preview Mode**](/docs/advanced-features/preview-mode.md) feature. diff --git a/docs/basic-features/data-fetching/incremental-static-regeneration.md b/docs/basic-features/data-fetching/incremental-static-regeneration.md new file mode 100644 index 0000000000000..7a7d197c3d09c --- /dev/null +++ b/docs/basic-features/data-fetching/incremental-static-regeneration.md @@ -0,0 +1,88 @@ +--- +description: 'Learn how to create or update static pages at runtime with Incremental Static Regeneration.' +--- + +# Incremental Static Regeneration + +<details> + <summary><b>Examples</b></summary> + <ul> + <li><a href="https://nextjs.org/commerce">Next.js Commerce</a></li> + <li><a href="https://reactions-demo.vercel.app/">GitHub Reactions Demo</a></li> + <li><a href="https://static-tweet.vercel.app/">Static Tweet Demo</a></li> + </ul> +</details> + +<details> + <summary><b>Version History</b></summary> + +| Version | Changes | +| -------- | ---------------- | +| `v9.5.0` | Base Path added. | + +</details> + +Next.js allows you to create or update static pages _after_ you’ve built your site. Incremental Static Regeneration (ISR) enables you to use static-generation on a per-page basis, **without needing to rebuild the entire site**. With ISR, you can retain the benefits of static while scaling to millions of pages. + +To use ISR add the `revalidate` prop to `getStaticProps`: + +```jsx +function Blog({ posts }) { + return ( + <ul> + {posts.map((post) => ( + <li>{post.title}</li> + ))} + </ul> + ) +} + +// This function gets called at build time on server-side. +// It may be called again, on a serverless function, if +// revalidation is enabled and a new request comes in +export async function getStaticProps() { + const res = await fetch('https://.../posts') + const posts = await res.json() + + return { + props: { + posts, + }, + // Next.js will attempt to re-generate the page: + // - When a request comes in + // - At most once every 10 seconds + revalidate: 10, // In seconds + } +} + +// This function gets called at build time on server-side. +// It may be called again, on a serverless function, if +// the path has not been generated. +export async function getStaticPaths() { + const res = await fetch('https://.../posts') + const posts = await res.json() + + // Get the paths we want to pre-render based on posts + const paths = posts.map((post) => ({ + params: { id: post.id }, + })) + + // We'll pre-render only these paths at build time. + // { fallback: blocking } will server-render pages + // on-demand if the path doesn't exist. + return { paths, fallback: 'blocking' } +} + +export default Blog +``` + +When a request is made to a page that was pre-rendered at build time, it will initially show the cached page. + +- Any requests to the page after the initial request and before 10 seconds are also cached and instantaneous. +- After the 10-second window, the next request will still show the cached (stale) page +- Next.js triggers a regeneration of the page in the background. +- Once the page has been successfully generated, Next.js will invalidate the cache and show the updated page. If the background regeneration fails, the old page would still be unaltered. + +When a request is made to a path that hasn’t been generated, Next.js will server-render the page on the first request. Future requests will serve the static file from the cache. + +[Incremental Static Regeneration](https://vercel.com/docs/concepts/next.js/incremental-static-regeneration) covers how to persist the cache globally and handle rollbacks. diff --git a/docs/basic-features/data-fetching/index.md b/docs/basic-features/data-fetching/index.md new file mode 100644 index 0000000000000..d414515f11ad8 --- /dev/null +++ b/docs/basic-features/data-fetching/index.md @@ -0,0 +1,87 @@ +--- +description: 'Data fetching in Next.js allows you to render your content in different ways, depending on your applications use case. These include pre-rendering with server-side rendering or static-site generation, and incremental static regeneration. Learn how to manage your application data in Next.js.' +--- + +# Data Fetching Overview + +<details> + <summary><b>Examples</b></summary> + <ul> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-wordpress">WordPress Example</a> (<a href="https://next-blog-wordpress.vercel.app">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/blog-starter">Blog Starter using markdown files</a> (<a href="https://next-blog-starter.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-datocms">DatoCMS Example</a> (<a href="https://next-blog-datocms.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-takeshape">TakeShape Example</a> (<a href="https://next-blog-takeshape.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-sanity">Sanity Example</a> (<a href="https://next-blog-sanity.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-prismic">Prismic Example</a> (<a href="https://next-blog-prismic.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-contentful">Contentful Example</a> (<a href="https://next-blog-contentful.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-strapi">Strapi Example</a> (<a href="https://next-blog-strapi.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-prepr">Prepr Example</a> (<a href="https://next-blog-prepr.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-agilitycms">Agility CMS Example</a> (<a href="https://next-blog-agilitycms.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-cosmic">Cosmic Example</a> (<a href="https://next-blog-cosmic.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-buttercms">ButterCMS Example</a> (<a href="https://next-blog-buttercms.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-storyblok">Storyblok Example</a> (<a href="https://next-blog-storyblok.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-graphcms">GraphCMS Example</a> (<a href="https://next-blog-graphcms.vercel.app/">Demo</a>)</li> + <li><a href="https://github.com/vercel/next.js/tree/canary/examples/cms-kontent">Kontent Example</a> (<a href="https://next-blog-kontent.vercel.app/">Demo</a>)</li> + <li><a href="https://static-tweet.vercel.app/">Static Tweet Demo</a></li> + </ul> +</details> + +Data fetching in Next.js allows you to render your content in different ways, depending on your application's use case. These include pre-rendering with **Server-side Rendering** or **Static Generation**, and updating or creating content at runtime with **Incremental Static Regeneration**. + +<div class="card"> + <a href="/docs/basic-features/data-fetching/get-server-side-props.md"> + <b>SSR: Server-side rendering</b> + <small>Learn more about server-side rendering in Next.js with getServerSideProps.</small> + </a> +</div> + +<div class="card"> + <a href="/docs/basic-features/data-fetching/get-static-props.md"> + <b>SSG: Static-site generation</b> + <small>Learn more about static site generation in Next.js with getStaticProps.</small> + </a> +</div> + +<div class="card"> + <a href="/docs/basic-features/data-fetching/client-side.md"> + <b>CSR: Client-side rendering</b> + <small>Learn more about client side rendering in Next.js with SWR.</small> + </a> +</div> + +<div class="card"> + <a href="/docs/basic-features/data-fetching/get-static-paths.md"> + <b>Dynamic routing</b> + <small>Learn more about dynamic routing in Next.js with getStaticPaths.</small> + </a> +</div> + +<div class="card"> + <a href="/docs/basic-features/data-fetching/incremental-static-regeneration.md"> + <b>ISR: Incremental Static Regeneration</b> + <small>Learn more about Incremental Static Regeneration in Next.js.</small> + </a> +</div> + +## Learn more + +<div class="card"> + <a href="/docs/advanced-features/preview-mode.md"> + <b>Preview Mode:</b> + <small>Learn more about the preview mode in Next.js.</small> + </a> +</div> + +<div class="card"> + <a href="/docs/routing/introduction.md"> + <b>Routing:</b> + <small>Learn more about routing in Next.js.</small> + </a> +</div> + +<div class="card"> + <a href="/docs/basic-features/typescript.md#pages"> + <b>TypeScript:</b> + <small>Add TypeScript to your pages.</small> + </a> +</div> diff --git a/docs/basic-features/environment-variables.md b/docs/basic-features/environment-variables.md index 857f4f488dc0b..4e9211bc2f9f3 100644 --- a/docs/basic-features/environment-variables.md +++ b/docs/basic-features/environment-variables.md @@ -30,9 +30,9 @@ DB_USER=myuser DB_PASS=mypassword ``` -This loads `process.env.DB_HOST`, `process.env.DB_USER`, and `process.env.DB_PASS` into the Node.js environment automatically allowing you to use them in [Next.js data fetching methods](/docs/basic-features/data-fetching.md) and [API routes](/docs/api-routes/introduction.md). +This loads `process.env.DB_HOST`, `process.env.DB_USER`, and `process.env.DB_PASS` into the Node.js environment automatically allowing you to use them in [Next.js data fetching methods](/docs/basic-features/data-fetching/index.md) and [API routes](/docs/api-routes/introduction.md). -For example, using [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation): +For example, using [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md): ```js // pages/index.js diff --git a/docs/basic-features/pages.md b/docs/basic-features/pages.md index c01b5f046ce21..ad46f39e5913a 100644 --- a/docs/basic-features/pages.md +++ b/docs/basic-features/pages.md @@ -41,7 +41,7 @@ Importantly, Next.js lets you **choose** which pre-rendering form you'd like to We **recommend** using **Static Generation** over Server-side Rendering for performance reasons. Statically generated pages can be cached by CDN with no extra configuration to boost performance. However, in some cases, Server-side Rendering might be the only option. -You can also use **Client-side Rendering** along with Static Generation or Server-side Rendering. That means some parts of a page can be rendered entirely by client side JavaScript. To learn more, take a look at the [Data Fetching](/docs/basic-features/data-fetching.md#fetching-data-on-the-client-side) documentation. +You can also use **Client-side Rendering** along with Static Generation or Server-side Rendering. That means some parts of a page can be rendered entirely by client side JavaScript. To learn more, take a look at the [Data Fetching](/docs/basic-features/data-fetching/client-side.md) documentation. ## Static Generation (Recommended) @@ -137,7 +137,7 @@ export async function getStaticProps() { export default Blog ``` -To learn more about how `getStaticProps` works, check out the [Data Fetching documentation](/docs/basic-features/data-fetching.md#getstaticprops-static-generation). +To learn more about how `getStaticProps` works, check out the [Data Fetching documentation](/docs/basic-features/data-fetching/get-static-props.md). #### Scenario 2: Your page paths depend on external data @@ -196,7 +196,7 @@ export async function getStaticProps({ params }) { export default Post ``` -To learn more about how `getStaticPaths` works, check out the [Data Fetching documentation](/docs/basic-features/data-fetching.md#getstaticpaths-static-generation). +To learn more about how `getStaticPaths` works, check out the [Data Fetching documentation](/docs/basic-features/data-fetching/get-static-paths.md). ### When should I use Static Generation? @@ -215,7 +215,7 @@ On the other hand, Static Generation is **not** a good idea if you cannot pre-re In cases like this, you can do one of the following: -- Use Static Generation with **Client-side Rendering:** You can skip pre-rendering some parts of a page and then use client-side JavaScript to populate them. To learn more about this approach, check out the [Data Fetching documentation](/docs/basic-features/data-fetching.md#fetching-data-on-the-client-side). +- Use Static Generation with **Client-side Rendering:** You can skip pre-rendering some parts of a page and then use client-side JavaScript to populate them. To learn more about this approach, check out the [Data Fetching documentation](/docs/basic-features/data-fetching/client-side.md). - Use **Server-Side Rendering:** Next.js pre-renders a page on each request. It will be slower because the page cannot be cached by a CDN, but the pre-rendered page will always be up-to-date. We'll talk about this approach below. ## Server-side Rendering @@ -248,7 +248,7 @@ export default Page As you can see, `getServerSideProps` is similar to `getStaticProps`, but the difference is that `getServerSideProps` is run on every request instead of on build time. -To learn more about how `getServerSideProps` works, check out our [Data Fetching documentation](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) +To learn more about how `getServerSideProps` works, check out our [Data Fetching documentation](/docs/basic-features/data-fetching/get-server-side-props.md) ## Summary @@ -262,7 +262,7 @@ We've discussed two forms of pre-rendering for Next.js. We recommend you to read the following sections next: <div class="card"> - <a href="/docs/basic-features/data-fetching.md"> + <a href="/docs/basic-features/data-fetching/index.md"> <b>Data Fetching:</b> <small>Learn more about data fetching in Next.js.</small> </a> diff --git a/docs/basic-features/typescript.md b/docs/basic-features/typescript.md index 3290a8477063d..f56028f7fe5f5 100644 --- a/docs/basic-features/typescript.md +++ b/docs/basic-features/typescript.md @@ -85,7 +85,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => { } ``` -> If you're using `getInitialProps`, you can [follow the directions on this page](/docs/api-reference/data-fetching/getInitialProps.md#typescript). +> If you're using `getInitialProps`, you can [follow the directions on this page](/docs/api-reference/data-fetching/get-initial-props.md#typescript). ## API Routes diff --git a/docs/faq.md b/docs/faq.md index 8a1cec7254a91..187f8836762c3 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -39,7 +39,7 @@ description: Get to know more about Next.js with the frequently asked questions. <details> <summary>How do I fetch data?</summary> - <p>It's up to you. You can use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">fetch API</a> or <a href="https://swr.vercel.app/">SWR</a> inside your React components for remote data fetching; or use our <a href="/docs/basic-features/data-fetching.md">data fetching methods</a> for initial data population.</p> + <p>It's up to you. You can use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">fetch API</a> or <a href="https://swr.vercel.app/">SWR</a> inside your React components for remote data fetching; or use our <a href="/docs/basic-features/data-fetching/index.md">data fetching methods</a> for initial data population.</p> </details> <details> diff --git a/docs/getting-started.md b/docs/getting-started.md index d037f7ed9e418..a9d0501b1941b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -91,7 +91,7 @@ So far, we get: - Automatic compilation and bundling (with webpack and babel) - [React Fast Refresh](https://nextjs.org/blog/next-9-4#fast-refresh) -- [Static generation and server-side rendering](/docs/basic-features/data-fetching.md) of [`./pages/`](/docs/basic-features/pages.md) +- [Static generation and server-side rendering](/docs/basic-features/data-fetching/index.md) of [`./pages/`](/docs/basic-features/pages.md) - [Static file serving](/docs/basic-features/static-file-serving.md). `./public/` is mapped to `/` In addition, any Next.js application is ready for production from the start, read more in our [Deployment documentation](/docs/deployment.md). diff --git a/docs/going-to-production.md b/docs/going-to-production.md index 55d94ef2b5728..aa713bf04577c 100644 --- a/docs/going-to-production.md +++ b/docs/going-to-production.md @@ -38,7 +38,7 @@ Caching improves response times and reduces the number of requests to external s Cache-Control: public, max-age=31536000, immutable ``` -`Cache-Control` headers set in `next.config.js` will be overwritten in production to ensure that static assets can be cached effectively. If you need to revalidate the cache of a page that has been [statically generated](/docs/basic-features/pages.md#static-generation-recommended), you can do so by setting `revalidate` in the page's [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) function. If you're using `next/image`, there are also [specific caching rules](/docs/basic-features/image-optimization.md#caching) for the default Image Optimization loader. +`Cache-Control` headers set in `next.config.js` will be overwritten in production to ensure that static assets can be cached effectively. If you need to revalidate the cache of a page that has been [statically generated](/docs/basic-features/pages.md#static-generation-recommended), you can do so by setting `revalidate` in the page's [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) function. If you're using `next/image`, there are also [specific caching rules](/docs/basic-features/image-optimization.md#caching) for the default Image Optimization loader. **Note:** When running your application locally with `next dev`, your headers are overwritten to prevent caching locally. diff --git a/docs/manifest.json b/docs/manifest.json index 340199c8ff9d7..9e2534b1baa3d 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -15,7 +15,33 @@ }, { "title": "Data Fetching", - "path": "/docs/basic-features/data-fetching.md" + "path": "/docs/basic-features/data-fetching/index.md", + "routes": [ + { + "title": "Overview", + "path": "/docs/basic-features/data-fetching/index.md" + }, + { + "title": "getServerSideProps", + "path": "/docs/basic-features/data-fetching/get-server-side-props.md" + }, + { + "title": "getStaticPaths", + "path": "/docs/basic-features/data-fetching/get-static-paths.md" + }, + { + "title": "getStaticProps", + "path": "/docs/basic-features/data-fetching/get-static-props.md" + }, + { + "title": "Incremental Static Regeneration", + "path": "/docs/basic-features/data-fetching/incremental-static-regeneration.md" + }, + { + "title": "Client side", + "path": "/docs/basic-features/data-fetching/client-side.md" + } + ] }, { "title": "Built-in CSS Support", @@ -33,10 +59,6 @@ "title": "Font Optimization", "path": "/docs/basic-features/font-optimization.md" }, - { - "title": "Script Optimization", - "path": "/docs/basic-features/script.md" - }, { "title": "Static File Serving", "path": "/docs/basic-features/static-file-serving.md" @@ -60,6 +82,10 @@ { "title": "Supported Browsers and Features", "path": "/docs/basic-features/supported-browsers-features.md" + }, + { + "title": "Handling Scripts", + "path": "/docs/basic-features/script.md" } ] }, @@ -321,7 +347,19 @@ "routes": [ { "title": "getInitialProps", - "path": "/docs/api-reference/data-fetching/getInitialProps.md" + "path": "/docs/api-reference/data-fetching/get-initial-props.md" + }, + { + "title": "getServerSideProps", + "path": "/docs/api-reference/data-fetching/get-server-side-props.md" + }, + { + "title": "getStaticPaths", + "path": "/docs/api-reference/data-fetching/get-static-paths.md" + }, + { + "title": "getStaticProps", + "path": "/docs/api-reference/data-fetching/get-static-props.md" } ] }, diff --git a/docs/migrating/from-create-react-app.md b/docs/migrating/from-create-react-app.md index 93db9eddd3d88..77697644ec1c4 100644 --- a/docs/migrating/from-create-react-app.md +++ b/docs/migrating/from-create-react-app.md @@ -6,8 +6,8 @@ description: Learn how to transition an existing Create React App project to Nex This guide will help you understand how to transition from an existing non-ejected Create React App project to Next.js. Migrating to Next.js will allow you to: -- Choose which [data fetching](/docs/basic-features/data-fetching.md) strategy you want on a per-page basis. -- Use [Incremental Static Regeneration](/docs/basic-features/data-fetching.md#incremental-static-regeneration) to update _existing_ pages by re-rendering them in the background as traffic comes in. +- Choose which [data fetching](/docs/basic-features/data-fetching/index.md) strategy you want on a per-page basis. +- Use [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md) to update _existing_ pages by re-rendering them in the background as traffic comes in. - Use [API Routes](/docs/api-routes/introduction.md). And more! Let’s walk through a series of steps to complete the migration. @@ -51,7 +51,7 @@ Create React App uses the `public` directory for the [entry HTML file](https://c With Create React App, you're likely using React Router. Instead of using a third-party library, Next.js includes its own [file-system based routing](/docs/routing/introduction.md). - Convert all `Route` components to new files in the `pages` directory. -- For routes that require dynamic content (e.g. `/blog/:slug`), you can use [Dynamic Routes](/docs/routing/dynamic-routes.md) with Next.js (e.g. `pages/blog/[slug].js`). The value of `slug` is accessible through a [query parameter](/docs/routing/dynamic-routes.md). For example, the route `/blog/first-post` would forward the query object `{ 'slug': 'first-post' }` to `pages/blog/[slug].js` ([learn more here](/docs/basic-features/data-fetching.md#getstaticpaths-static-generation)). +- For routes that require dynamic content (e.g. `/blog/:slug`), you can use [Dynamic Routes](/docs/routing/dynamic-routes.md) with Next.js (e.g. `pages/blog/[slug].js`). The value of `slug` is accessible through a [query parameter](/docs/routing/dynamic-routes.md). For example, the route `/blog/first-post` would forward the query object `{ 'slug': 'first-post' }` to `pages/blog/[slug].js` ([learn more here](/docs/basic-features/data-fetching/get-static-paths.md)). For more information, see [Migrating from React Router](/docs/migrating/from-react-router.md). diff --git a/docs/migrating/from-gatsby.md b/docs/migrating/from-gatsby.md index 8198ee0ce5c8a..fa46c9819c22b 100644 --- a/docs/migrating/from-gatsby.md +++ b/docs/migrating/from-gatsby.md @@ -6,8 +6,8 @@ description: Learn how to transition an existing Gatsby project to Next.js. This guide will help you understand how to transition from an existing Gatsby project to Next.js. Migrating to Next.js will allow you to: -- Choose which [data fetching](/docs/basic-features/data-fetching.md) strategy you want on a per-page basis. -- Use [Incremental Static Regeneration](/docs/basic-features/data-fetching.md#incremental-static-regeneration) to update _existing_ pages by re-rendering them in the background as traffic comes in. +- Choose which [data fetching](/docs/basic-features/data-fetching/index.md) strategy you want on a per-page basis. +- Use [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md) to update _existing_ pages by re-rendering them in the background as traffic comes in. - Use [API Routes](/docs/api-routes/introduction.md). And more! Let’s walk through a series of steps to complete the migration. @@ -52,7 +52,7 @@ Both Gatsby and Next support a `pages` directory, which uses [file-system based Gatsby creates dynamic routes using the `createPages` API inside of `gatsby-node.js`. With Next, we can use [Dynamic Routes](/docs/routing/dynamic-routes.md) inside of `pages` to achieve the same effect. Rather than having a `template` directory, you can use the React component inside your dynamic route file. For example: - **Gatsby:** `createPages` API inside `gatsby-node.js` for each blog post, then have a template file at `src/templates/blog-post.js`. -- **Next:** Create `pages/blog/[slug].js` which contains the blog post template. The value of `slug` is accessible through a [query parameter](/docs/routing/dynamic-routes.md). For example, the route `/blog/first-post` would forward the query object `{ 'slug': 'first-post' }` to `pages/blog/[slug].js` ([learn more here](/docs/basic-features/data-fetching.md#getstaticpaths-static-generation)). +- **Next:** Create `pages/blog/[slug].js` which contains the blog post template. The value of `slug` is accessible through a [query parameter](/docs/routing/dynamic-routes.md). For example, the route `/blog/first-post` would forward the query object `{ 'slug': 'first-post' }` to `pages/blog/[slug].js` ([learn more here](/docs/basic-features/data-fetching/get-static-paths.md)). ## Styling @@ -92,7 +92,7 @@ Update any import statements, switch `to` to `href`, and add an `<a>` tag as a c The largest difference between Gatsby and Next.js is how data fetching is implemented. Gatsby is opinionated with GraphQL being the default strategy for retrieving data across your application. With Next.js, you get to choose which strategy you want (GraphQL is one supported option). -Gatsby uses the `graphql` tag to query data in the pages of your site. This may include local data, remote data, or information about your site configuration. Gatsby only allows the creation of static pages. With Next.js, you can choose on a [per-page basis](/docs/basic-features/pages.md) which [data fetching strategy](/docs/basic-features/data-fetching.md) you want. For example, `getServerSideProps` allows you to do server-side rendering. If you wanted to generate a static page, you'd export `getStaticProps` / `getStaticPaths` inside the page, rather than using `pageQuery`. For example: +Gatsby uses the `graphql` tag to query data in the pages of your site. This may include local data, remote data, or information about your site configuration. Gatsby only allows the creation of static pages. With Next.js, you can choose on a [per-page basis](/docs/basic-features/pages.md) which [data fetching strategy](/docs/basic-features/data-fetching/index.md) you want. For example, `getServerSideProps` allows you to do server-side rendering. If you wanted to generate a static page, you'd export `getStaticProps` / `getStaticPaths` inside the page, rather than using `pageQuery`. For example: ```js // src/pages/[slug].js diff --git a/docs/routing/introduction.md b/docs/routing/introduction.md index 2481440ff15ce..6d165c22d6259 100644 --- a/docs/routing/introduction.md +++ b/docs/routing/introduction.md @@ -74,7 +74,7 @@ The example above uses multiple links. Each one maps a path (`href`) to a known - `/about` → `pages/about.js` - `/blog/hello-world` → `pages/blog/[slug].js` -Any `<Link />` in the viewport (initially or through scroll) will be prefetched by default (including the corresponding data) for pages using [Static Generation](/docs/basic-features/data-fetching.md#getstaticprops-static-generation). The corresponding data for [server-rendered](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering) routes is _not_ prefetched. +Any `<Link />` in the viewport (initially or through scroll) will be prefetched by default (including the corresponding data) for pages using [Static Generation](/docs/basic-features/data-fetching/get-static-props.md). The corresponding data for [server-rendered](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering) routes is _not_ prefetched. ### Linking to dynamic paths diff --git a/docs/routing/shallow-routing.md b/docs/routing/shallow-routing.md index caa9cf35138e1..d1703af6b6e1c 100644 --- a/docs/routing/shallow-routing.md +++ b/docs/routing/shallow-routing.md @@ -11,7 +11,7 @@ description: You can use shallow routing to change the URL without triggering a </ul> </details> -Shallow routing allows you to change the URL without running data fetching methods again, that includes [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering), [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation), and [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md). +Shallow routing allows you to change the URL without running data fetching methods again, that includes [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md), [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md), and [`getInitialProps`](/docs/api-reference/data-fetching/get-initial-props.md). You'll receive the updated `pathname` and the `query` via the [`router` object](/docs/api-reference/next/router.md#router-object) (added by [`useRouter`](/docs/api-reference/next/router.md#useRouter) or [`withRouter`](/docs/api-reference/next/router.md#withRouter)), without losing state. diff --git a/errors/get-initial-props-as-an-instance-method.md b/errors/get-initial-props-as-an-instance-method.md index 26218c66e28eb..805055202f40c 100644 --- a/errors/get-initial-props-as-an-instance-method.md +++ b/errors/get-initial-props-as-an-instance-method.md @@ -36,4 +36,4 @@ export default YourEntryComponent ### Useful Links -- [Fetching data and component lifecycle](https://nextjs.org/docs/api-reference/data-fetching/getInitialProps) +- [Fetching data and component lifecycle](https://nextjs.org/docs/api-reference/data-fetching/get-initial-props) diff --git a/examples/blog/pages/posts/pages.md b/examples/blog/pages/posts/pages.md index d97c0afefc3d8..98d4c8333d218 100644 --- a/examples/blog/pages/posts/pages.md +++ b/examples/blog/pages/posts/pages.md @@ -43,7 +43,7 @@ Importantly, Next.js lets you **choose** which pre-rendering form you'd like to We **recommend** using **Static Generation** over Server-side Rendering for performance reasons. Statically generated pages can be cached by CDN with no extra configuration to boost performance. However, in some cases, Server-side Rendering might be the only option. -You can also use **Client-side Rendering** along with Static Generation or Server-side Rendering. That means some parts of a page can be rendered entirely by client side JavaScript. To learn more, take a look at the [Data Fetching](/docs/basic-features/data-fetching.md#fetching-data-on-the-client-side) documentation. +You can also use **Client-side Rendering** along with Static Generation or Server-side Rendering. That means some parts of a page can be rendered entirely by client side JavaScript. To learn more, take a look at the [Data Fetching](/docs/basic-features/data-fetching/client-side.md) documentation. ## Static Generation (Recommended) @@ -117,7 +117,7 @@ export async function getStaticProps() { export default Blog ``` -To learn more about how `getStaticProps` works, check out the [Data Fetching documentation](/docs/basic-features/data-fetching.md#getstaticprops-static-generation). +To learn more about how `getStaticProps` works, check out the [Data Fetching documentation](/docs/basic-features/data-fetching/get-static-props.md). #### Scenario 2: Your page paths depend on external data @@ -176,7 +176,7 @@ export async function getStaticProps({ params }) { export default Post ``` -To learn more about how `getStaticPaths` works, check out the [Data Fetching documentation](/docs/basic-features/data-fetching.md#getstaticpaths-static-generation). +To learn more about how `getStaticPaths` works, check out the [Data Fetching documentation](/docs/basic-features/data-fetching/get-static-paths.md). ### When should I use Static Generation? @@ -195,7 +195,7 @@ On the other hand, Static Generation is **not** a good idea if you cannot pre-re In cases like this, you can do one of the following: -- Use Static Generation with **Client-side Rendering:** You can skip pre-rendering some parts of a page and then use client-side JavaScript to populate them. To learn more about this approach, check out the [Data Fetching documentation](/docs/basic-features/data-fetching.md#fetching-data-on-the-client-side). +- Use Static Generation with **Client-side Rendering:** You can skip pre-rendering some parts of a page and then use client-side JavaScript to populate them. To learn more about this approach, check out the [Data Fetching documentation](/docs/basic-features/data-fetching/client-side.md). - Use **Server-Side Rendering:** Next.js pre-renders a page on each request. It will be slower because the page cannot be cached by a CDN, but the pre-rendered page will always be up-to-date. We'll talk about this approach below. ## Server-side Rendering @@ -228,7 +228,7 @@ export default Page As you can see, `getServerSideProps` is similar to `getStaticProps`, but the difference is that `getServerSideProps` is run on every request instead of on build time. -To learn more about how `getServerSideProps` works, check out our [Data Fetching documentation](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) +To learn more about how `getServerSideProps` works, check out our [Data Fetching documentation](/docs/basic-features/data-fetching/get-server-side-props.md) ## Summary From df0e89984e4f057c2f03745b090732bb055ebabb Mon Sep 17 00:00:00 2001 From: Tim Neutkens <tim@timneutkens.nl> Date: Wed, 12 Jan 2022 09:09:32 +0100 Subject: [PATCH 07/12] v12.0.8-canary.22 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- 15 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lerna.json b/lerna.json index c87688c20ca06..36f0fecf4ca6e 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.0.8-canary.21" + "version": "12.0.8-canary.22" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 0127d9a34558f..c4319ad9a1aea 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index b67348b16aa5f..5b19a40d10098 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.0.8-canary.21", + "@next/eslint-plugin-next": "12.0.8-canary.22", "@rushstack/eslint-patch": "^1.0.8", "@typescript-eslint/parser": "^5.0.0", "eslint-import-resolver-node": "^0.3.4", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index a0053881f0761..f15f2f6d731b1 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index d7051cfae395b..597262907b536 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index bdd760b3c2126..a44f78564be37 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index ca4442879c0a2..86cbba5c09f68 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index f349da7d93f0c..edb8e9a65ebbc 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 8c132bbf5cdbc..858d3d3eed645 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 9c8e8f754136b..17fc97b35e160 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 67e8bdc03e06f..4125b8119937d 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 45531e4b2b2b6..7557ca4b280d2 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "private": true, "scripts": { "build-native": "napi build --platform --cargo-name next_swc_napi native", diff --git a/packages/next/package.json b/packages/next/package.json index 9fd4d108fbddb..4ecebd1259f2d 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -71,8 +71,8 @@ ] }, "dependencies": { - "@next/env": "12.0.8-canary.21", - "@next/react-refresh-utils": "12.0.8-canary.21", + "@next/env": "12.0.8-canary.22", + "@next/react-refresh-utils": "12.0.8-canary.22", "caniuse-lite": "^1.0.30001283", "jest-worker": "27.0.0-next.5", "node-fetch": "2.6.1", @@ -125,10 +125,10 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "1.2.1", "@napi-rs/triples": "1.0.3", - "@next/polyfill-module": "12.0.8-canary.21", - "@next/polyfill-nomodule": "12.0.8-canary.21", - "@next/react-dev-overlay": "12.0.8-canary.21", - "@next/swc": "12.0.8-canary.21", + "@next/polyfill-module": "12.0.8-canary.22", + "@next/polyfill-nomodule": "12.0.8-canary.22", + "@next/react-dev-overlay": "12.0.8-canary.22", + "@next/swc": "12.0.8-canary.22", "@peculiar/webcrypto": "1.1.7", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 6202691122cce..9d591ae7f238e 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index b31946fd03a29..d68d04f40679e 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.0.8-canary.21", + "version": "12.0.8-canary.22", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", From d7a96d22be60bd84297befe7bff9ecc8862eaebf Mon Sep 17 00:00:00 2001 From: Tim Neutkens <tim@timneutkens.nl> Date: Wed, 12 Jan 2022 09:14:02 +0100 Subject: [PATCH 08/12] v12.0.8 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- 15 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lerna.json b/lerna.json index 36f0fecf4ca6e..7ad8784a0b0fd 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.0.8-canary.22" + "version": "12.0.8" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index c4319ad9a1aea..a9e734cb8f24d 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.0.8-canary.22", + "version": "12.0.8", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 5b19a40d10098..0ab87c3a9fd6e 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.0.8-canary.22", + "version": "12.0.8", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.0.8-canary.22", + "@next/eslint-plugin-next": "12.0.8", "@rushstack/eslint-patch": "^1.0.8", "@typescript-eslint/parser": "^5.0.0", "eslint-import-resolver-node": "^0.3.4", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index f15f2f6d731b1..ec7c69977f263 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.0.8-canary.22", + "version": "12.0.8", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 597262907b536..deddc3d78fba5 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.0.8-canary.22", + "version": "12.0.8", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index a44f78564be37..43d1a6f8ec1cf 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.0.8-canary.22", + "version": "12.0.8", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 86cbba5c09f68..c662fc293a015 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.0.8-canary.22", + "version": "12.0.8", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index edb8e9a65ebbc..1565ef3139fe2 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.0.8-canary.22", + "version": "12.0.8", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 858d3d3eed645..1c46fa1ccf542 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.0.8-canary.22", + "version": "12.0.8", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 17fc97b35e160..0001eceb52051 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.0.8-canary.22", + "version": "12.0.8", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 4125b8119937d..de645743cfd89 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.0.8-canary.22", + "version": "12.0.8", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 7557ca4b280d2..0660363ec97b8 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.0.8-canary.22", + "version": "12.0.8", "private": true, "scripts": { "build-native": "napi build --platform --cargo-name next_swc_napi native", diff --git a/packages/next/package.json b/packages/next/package.json index 4ecebd1259f2d..cf55d55e0eb41 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.0.8-canary.22", + "version": "12.0.8", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -71,8 +71,8 @@ ] }, "dependencies": { - "@next/env": "12.0.8-canary.22", - "@next/react-refresh-utils": "12.0.8-canary.22", + "@next/env": "12.0.8", + "@next/react-refresh-utils": "12.0.8", "caniuse-lite": "^1.0.30001283", "jest-worker": "27.0.0-next.5", "node-fetch": "2.6.1", @@ -125,10 +125,10 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "1.2.1", "@napi-rs/triples": "1.0.3", - "@next/polyfill-module": "12.0.8-canary.22", - "@next/polyfill-nomodule": "12.0.8-canary.22", - "@next/react-dev-overlay": "12.0.8-canary.22", - "@next/swc": "12.0.8-canary.22", + "@next/polyfill-module": "12.0.8", + "@next/polyfill-nomodule": "12.0.8", + "@next/react-dev-overlay": "12.0.8", + "@next/swc": "12.0.8", "@peculiar/webcrypto": "1.1.7", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 9d591ae7f238e..347ce77fd5be6 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.0.8-canary.22", + "version": "12.0.8", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index d68d04f40679e..6e6ec3a1b10c1 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.0.8-canary.22", + "version": "12.0.8", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", From 029f2e360f68c9382d91e4320802a37027a4e70a Mon Sep 17 00:00:00 2001 From: Rich Haines <hello@richardhaines.dev> Date: Wed, 12 Jan 2022 13:35:17 +0100 Subject: [PATCH 09/12] Fixed broken link (#33209) --- docs/advanced-features/i18n-routing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced-features/i18n-routing.md b/docs/advanced-features/i18n-routing.md index 6eb849294e063..119e43578f1db 100644 --- a/docs/advanced-features/i18n-routing.md +++ b/docs/advanced-features/i18n-routing.md @@ -313,7 +313,7 @@ For [Automatically Statically Optimized](/docs/advanced-features/automatic-stati For example, if you have 50 locales configured with 10 non-dynamic pages using `getStaticProps`, this means `getStaticProps` will be called 500 times. 50 versions of the 10 pages will be generated during each build. -To decrease the build time of dynamic pages with `getStaticProps`, use a [`fallback` mode](https://nextjs.org/docs/basic-features/data-fetching#fallback-true). This allows you to return only the most popular paths and locales from `getStaticPaths` for prerendering during the build. Then, Next.js will build the remaining pages at runtime as they are requested. +To decrease the build time of dynamic pages with `getStaticProps`, use a [`fallback` mode](/docs/api-reference/data-fetching/get-static-paths#fallback-true). This allows you to return only the most popular paths and locales from `getStaticPaths` for prerendering during the build. Then, Next.js will build the remaining pages at runtime as they are requested. ### Automatically Statically Optimized Pages From e69500462d827c9050232aeb729b83b06f4fe94a Mon Sep 17 00:00:00 2001 From: Gal Schlezinger <gal@spitfire.co.il> Date: Wed, 12 Jan 2022 15:09:24 +0200 Subject: [PATCH 10/12] middlewares: limit `process.env` to inferred usage (#33186) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Production middlewares will only expose env vars that are statically analyzable, as mentioned here: https://nextjs.org/docs/api-reference/next/server#how-do-i-access-environment-variables This creates some incompatibility with `next dev` and `next start`, where all `process.env` data is shared and can lead to unexpected behavior in runtime. This PR fixes it by limiting the data in `process.env` with the inferred env vars from the code usage. I believe the test speaks for itself 🕺 <!-- ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `yarn lint` --> --- .../webpack/plugins/middleware-plugin.ts | 7 ++- packages/next/server/base-server.ts | 1 + packages/next/server/require.ts | 3 +- packages/next/server/web/sandbox/context.ts | 20 ++++++-- packages/next/server/web/sandbox/sandbox.ts | 2 + .../index.test.ts | 50 +++++++++++++++++++ 6 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 test/production/middleware-environment-variables-in-node-server-reflect-the-usage-inference/index.test.ts diff --git a/packages/next/build/webpack/plugins/middleware-plugin.ts b/packages/next/build/webpack/plugins/middleware-plugin.ts index 9f0c53abe43d5..0cac58aa6e726 100644 --- a/packages/next/build/webpack/plugins/middleware-plugin.ts +++ b/packages/next/build/webpack/plugins/middleware-plugin.ts @@ -7,8 +7,8 @@ import { MIDDLEWARE_BUILD_MANIFEST, MIDDLEWARE_REACT_LOADABLE_MANIFEST, MIDDLEWARE_RUNTIME_WEBPACK, + MIDDLEWARE_SSR_RUNTIME_WEBPACK, } from '../../../shared/lib/constants' -import { MIDDLEWARE_ROUTE } from '../../../lib/constants' import { nonNullable } from '../../../lib/non-nullable' const PLUGIN_NAME = 'MiddlewarePlugin' @@ -141,7 +141,10 @@ export default class MiddlewarePlugin { envPerRoute.clear() for (const [name, info] of compilation.entries) { - if (name.match(MIDDLEWARE_ROUTE)) { + if ( + info.options.runtime === MIDDLEWARE_SSR_RUNTIME_WEBPACK || + info.options.runtime === MIDDLEWARE_RUNTIME_WEBPACK + ) { const middlewareEntries = new Set<webpack5.Module>() const env = new Set<string>() diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 655826c9a0141..44a39d9fe60db 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -725,6 +725,7 @@ export default abstract class Server { result = await run({ name: middlewareInfo.name, paths: middlewareInfo.paths, + env: middlewareInfo.env, request: { headers: params.request.headers, method: params.request.method || 'GET', diff --git a/packages/next/server/require.ts b/packages/next/server/require.ts index a45a661908410..9c34b8538300f 100644 --- a/packages/next/server/require.ts +++ b/packages/next/server/require.ts @@ -85,7 +85,7 @@ export function getMiddlewareInfo(params: { distDir: string page: string serverless: boolean -}): { name: string; paths: string[] } { +}): { name: string; paths: string[]; env: string[] } { const serverBuildPath = join( params.distDir, params.serverless && !params.dev ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY @@ -112,5 +112,6 @@ export function getMiddlewareInfo(params: { return { name: pageInfo.name, paths: pageInfo.files.map((file) => join(params.distDir, file)), + env: pageInfo.env ?? [], } } diff --git a/packages/next/server/web/sandbox/context.ts b/packages/next/server/web/sandbox/context.ts index 880ab46f220db..de3876ffae948 100644 --- a/packages/next/server/web/sandbox/context.ts +++ b/packages/next/server/web/sandbox/context.ts @@ -56,6 +56,7 @@ export function getModuleContext(options: { module: string onWarning: (warn: Error) => void useCache: boolean + env: string[] }) { let moduleCache = options.useCache ? caches.get(options.module) @@ -97,12 +98,13 @@ export function getModuleContext(options: { function createModuleContext(options: { onWarning: (warn: Error) => void module: string + env: string[] }) { const requireCache = new Map([ [require.resolve('next/dist/compiled/cookie'), { exports: cookie }], ]) - const context = createContext() + const context = createContext(options) requireDependencies({ requireCache: requireCache, @@ -171,7 +173,10 @@ function createModuleContext(options: { * Create a base context with all required globals for the runtime that * won't depend on any externally provided dependency. */ -function createContext() { +function createContext(options: { + /** Environment variables to be provided to the context */ + env: string[] +}) { const context: { [key: string]: unknown } = { _ENTRIES: {}, atob: polyfills.atob, @@ -196,7 +201,9 @@ function createContext() { crypto: new polyfills.Crypto(), File, FormData, - process: { env: { ...process.env } }, + process: { + env: buildEnvironmentVariablesFrom(options.env), + }, ReadableStream: polyfills.ReadableStream, setInterval, setTimeout, @@ -245,3 +252,10 @@ function createContext() { : undefined, }) } + +function buildEnvironmentVariablesFrom( + keys: string[] +): Record<string, string | undefined> { + const pairs = keys.map((key) => [key, process.env[key]]) + return Object.fromEntries(pairs) +} diff --git a/packages/next/server/web/sandbox/sandbox.ts b/packages/next/server/web/sandbox/sandbox.ts index 7a98d4d122343..576e8be7580c6 100644 --- a/packages/next/server/web/sandbox/sandbox.ts +++ b/packages/next/server/web/sandbox/sandbox.ts @@ -3,6 +3,7 @@ import { getModuleContext } from './context' export async function run(params: { name: string + env: string[] onWarning: (warn: Error) => void paths: string[] request: RequestData @@ -12,6 +13,7 @@ export async function run(params: { module: params.name, onWarning: params.onWarning, useCache: params.useCache !== false, + env: params.env, }) for (const paramPath of params.paths) { diff --git a/test/production/middleware-environment-variables-in-node-server-reflect-the-usage-inference/index.test.ts b/test/production/middleware-environment-variables-in-node-server-reflect-the-usage-inference/index.test.ts new file mode 100644 index 0000000000000..f18fc371cf08a --- /dev/null +++ b/test/production/middleware-environment-variables-in-node-server-reflect-the-usage-inference/index.test.ts @@ -0,0 +1,50 @@ +import { createNext } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import { renderViaHTTP } from 'next-test-utils' + +describe('middleware environment variables in node server reflect the usage inference', () => { + let next: NextInstance + + beforeAll(() => { + process.env.CAN_BE_INFERRED = 'can-be-inferred' + process.env.X_CUSTOM_HEADER = 'x-custom-header' + process.env.IGNORED_ENV_VAR = 'ignored-env-var' + }) + + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/_middleware.js': ` + export default function middleware() { + return new Response(JSON.stringify({ + canBeInferred: process.env.CAN_BE_INFERRED, + rest: process.env + }), { + headers: { + 'Content-Type': 'application/json', + 'X-Custom-Header': process.env.X_CUSTOM_HEADER, + } + }) + } + `, + }, + dependencies: {}, + }) + }) + afterAll(() => next.destroy()) + + it('limits process.env to only contain env vars that are inferred from usage', async () => { + const html = await renderViaHTTP(next.url, '/test') + let parsed: any + expect(() => { + parsed = JSON.parse(html) + }).not.toThrow() + expect(parsed).toEqual({ + canBeInferred: 'can-be-inferred', + rest: { + CAN_BE_INFERRED: 'can-be-inferred', + X_CUSTOM_HEADER: 'x-custom-header', + }, + }) + }) +}) From b3226303be8118b8d090899af3b0adaf69484915 Mon Sep 17 00:00:00 2001 From: Rich Haines <hello@richardhaines.dev> Date: Wed, 12 Jan 2022 15:21:22 +0100 Subject: [PATCH 11/12] Removed backticks on data fetching api titles (#33216) This PR removes the backticks used when referring to a data fetching api in a title `getStaticProps` => getStaticProps ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `yarn lint` --- docs/api-reference/data-fetching/get-server-side-props.md | 6 +++--- docs/api-reference/data-fetching/get-static-paths.md | 6 +++--- docs/api-reference/data-fetching/get-static-props.md | 6 +++--- .../basic-features/data-fetching/get-server-side-props.md | 8 ++++---- docs/basic-features/data-fetching/get-static-paths.md | 8 ++++---- docs/basic-features/data-fetching/get-static-props.md | 8 ++++---- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/api-reference/data-fetching/get-server-side-props.md b/docs/api-reference/data-fetching/get-server-side-props.md index 582b04db9e7b1..10b469ae28217 100644 --- a/docs/api-reference/data-fetching/get-server-side-props.md +++ b/docs/api-reference/data-fetching/get-server-side-props.md @@ -2,7 +2,7 @@ description: API reference for `getServerSideProps`. Learn how to fetch data on each request with Next.js. --- -# `getServerSideProps` +# getServerSideProps <details> <summary><b>Version History</b></summary> @@ -41,7 +41,7 @@ The `context` parameter is an object containing the following keys: - `locales` contains all supported locales (if enabled). - `defaultLocale` contains the configured default locale (if enabled). -## `getServerSideProps` return values +## getServerSideProps return values The `getServerSideProps` function should return an object with the following **optional** properties: @@ -102,7 +102,7 @@ export async function getServerSideProps(context) { } ``` -### `getServerSideProps` with TypeScript +### getServerSideProps with TypeScript For TypeScript, you can use the `GetServerSideProps` type from `next`: diff --git a/docs/api-reference/data-fetching/get-static-paths.md b/docs/api-reference/data-fetching/get-static-paths.md index d185922fae93d..fe5de2933a2b8 100644 --- a/docs/api-reference/data-fetching/get-static-paths.md +++ b/docs/api-reference/data-fetching/get-static-paths.md @@ -2,7 +2,7 @@ description: API reference for `getStaticPaths`. Learn how to fetch data and generate static pages with `getStaticPaths`. --- -# `getStaticPaths` +# getStaticPaths <details> <summary><b>Version History</b></summary> @@ -27,7 +27,7 @@ export async function getStaticPaths() { } ``` -## `getStaticPaths` return values +## getStaticPaths return values The `getStaticPaths` function should return an object with the following **required** properties: @@ -199,7 +199,7 @@ export async function getStaticProps({ params }) { export default Post ``` -## `getStaticProps` with TypeScript +## getStaticProps with TypeScript For TypeScript, you can use the `GetStaticPaths` type from `next`: diff --git a/docs/api-reference/data-fetching/get-static-props.md b/docs/api-reference/data-fetching/get-static-props.md index 2ab5ddb9f2625..23c0e70900981 100644 --- a/docs/api-reference/data-fetching/get-static-props.md +++ b/docs/api-reference/data-fetching/get-static-props.md @@ -2,7 +2,7 @@ description: API reference for `getStaticProps`. Learn how to use `getStaticProps` to generate static pages with Next.js. --- -# `getStaticProps` +# getStaticProps <details> <summary><b>Version History</b></summary> @@ -39,7 +39,7 @@ The `context` parameter is an object containing the following keys: - `locales` contains all supported locales (if enabled). - `defaultLocale` contains the configured default locale (if enabled). -## `getStaticProps` return values +## getStaticProps return values The `getStaticProps` function should return an object with the following **optional** properties: @@ -192,7 +192,7 @@ export async function getStaticProps() { export default Blog ``` -## `getStaticProps` with TypeScript +## getStaticProps with TypeScript You can use the `GetStaticProps` type from `next` to type the function: diff --git a/docs/basic-features/data-fetching/get-server-side-props.md b/docs/basic-features/data-fetching/get-server-side-props.md index 2e28a45cbb89d..6caea00e656c1 100644 --- a/docs/basic-features/data-fetching/get-server-side-props.md +++ b/docs/basic-features/data-fetching/get-server-side-props.md @@ -2,7 +2,7 @@ description: Fetch data on each request with `getServerSideProps`. --- -# `getServerSideProps` +# getServerSideProps If you export a function called `getServerSideProps` (Server-Side Rendering) from a page, Next.js will pre-render this page on each request using the data returned by `getServerSideProps`. @@ -14,7 +14,7 @@ export async function getServerSideProps(context) { } ``` -## When does `getServerSideProps` run +## When does getServerSideProps run `getServerSideProps` only runs on server-side and never runs on the browser. If a page uses `getServerSideProps`, then: @@ -37,7 +37,7 @@ You should use `getServerSideProps` only if you need to pre-render a page whose If you do not need to pre-render the data, then you should consider fetching data on the [client side](#fetching-data-on-the-client-side). -### `getServerSideProps` or API Routes +### getServerSideProps or API Routes It can be tempting to reach for an [API Route](/docs/api-routes/introduction.md) when you want to fetch data from the server, then call that API route from `getServerSideProps`. This is an unnecessary and inefficient approach, as it will cause an extra request to be made due to both `getServerSideProps` and API Routes running on the server. @@ -52,7 +52,7 @@ If your page contains frequently updating data, and you don’t need to pre-rend This approach works well for user dashboard pages, for example. Because a dashboard is a private, user-specific page, SEO is not relevant and the page doesn’t need to be pre-rendered. The data is frequently updated, which requires request-time data fetching. -## Using `getServerSideProps` to fetch data at request time +## Using getServerSideProps to fetch data at request time The following example shows how to fetch data at request time and pre-render the result. diff --git a/docs/basic-features/data-fetching/get-static-paths.md b/docs/basic-features/data-fetching/get-static-paths.md index 9ba7a450928f9..e83f195a348da 100644 --- a/docs/basic-features/data-fetching/get-static-paths.md +++ b/docs/basic-features/data-fetching/get-static-paths.md @@ -2,7 +2,7 @@ description: Fetch data and generate static pages with `getStaticProps`. Learn more about this API for data fetching in Next.js. --- -# `getStaticPaths` +# getStaticPaths If a page has [Dynamic Routes](/docs/routing/dynamic-routes.md) and uses `getStaticProps`, it needs to define a list of paths to be statically generated. @@ -23,7 +23,7 @@ Note that`getStaticProps` **must** be used with `getStaticPaths`, and that you * The [`getStaticPaths` API reference](/docs/api-reference/data-fetching/get-static-paths.md) covers all parameters and props that can be used with `getStaticPaths`. -## When should I use `getStaticPaths`? +## When should I use getStaticPaths? You should use `getStaticPaths` if you’re statically pre-rendering pages that use dynamic routes and: @@ -33,11 +33,11 @@ You should use `getStaticPaths` if you’re statically pre-rendering pages that - The data can be publicly cached (not user-specific) - The page must be pre-rendered (for SEO) and be very fast — `getStaticProps` generates `HTML` and `JSON` files, both of which can be cached by a CDN for performance -## When does `getStaticPaths` run +## When does getStaticPaths run `getStaticPaths` only runs at build time on server-side. If you're using [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md), `getStaticPaths` can also be run on-demand _in the background_, but still only on the server-side. -## Where can I use `getStaticPaths` +## Where can I use getStaticPaths `getStaticPaths` can only be exported from a **page**. You **cannot** export it from non-page files. diff --git a/docs/basic-features/data-fetching/get-static-props.md b/docs/basic-features/data-fetching/get-static-props.md index adb8427fab01c..1e5319e34c21f 100644 --- a/docs/basic-features/data-fetching/get-static-props.md +++ b/docs/basic-features/data-fetching/get-static-props.md @@ -2,7 +2,7 @@ description: Fetch data and generate static pages with `getStaticProps`. Learn more about this API for data fetching in Next.js. --- -# `getStaticProps` +# getStaticProps If you export a function called `getStaticProps` (Static Site Generation) from a page, Next.js will pre-render this page at build time using the props returned by `getStaticProps`. @@ -14,7 +14,7 @@ export async function getStaticProps(context) { } ``` -## When should I use `getStaticProps`? +## When should I use getStaticProps? You should use `getStaticProps` if: @@ -25,7 +25,7 @@ You should use `getStaticProps` if: Because `getStaticProps` runs at build time, it does **not** receive data that’s only available during request time, such as query parameters or `HTTP` headers, as it generates static `HTML`. When combined with [Incremental Static Regeneration](/docs/basic-features/data-fetching/incremental-static-regeneration.md) however, it will run in the background while the stale page is being revalidated, and the fresh page served to the browser. -## Using `getStaticProps` to fetch data from a CMS +## Using getStaticProps to fetch data from a CMS The following example shows how you can fetch a list of blog posts from a CMS. @@ -84,7 +84,7 @@ This JSON file will be used in client-side routing through [`next/link`](/docs/a When using Incremental Static Generation `getStaticProps` will be executed out of band to generate the JSON needed for client-side navigation. You may see this in the form of multiple requests being made for the same page, however, this is intended and has no impact on end-user performance -## Where can I use `getStaticProps` +## Where can I use getStaticProps `getStaticProps` can only be exported from a **page**. You **cannot** export it from non-page files. From 22eca10c6a4cc5e5531ddb23f70043eaa67d2c38 Mon Sep 17 00:00:00 2001 From: Rich Haines <hello@richardhaines.dev> Date: Wed, 12 Jan 2022 16:52:55 +0100 Subject: [PATCH 12/12] Added links to data fetching api refs, fixed title (#33221) This PR adds links from the data fetching api pages to their api ref pages. Also removes rouge backticks on header ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `yarn lint` --- .../data-fetching/get-server-side-props.md | 9 ++++++++- docs/basic-features/data-fetching/get-static-paths.md | 7 +++++++ docs/basic-features/data-fetching/get-static-props.md | 7 +++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/basic-features/data-fetching/get-server-side-props.md b/docs/basic-features/data-fetching/get-server-side-props.md index 6caea00e656c1..8aa844221785c 100644 --- a/docs/basic-features/data-fetching/get-server-side-props.md +++ b/docs/basic-features/data-fetching/get-server-side-props.md @@ -31,7 +31,7 @@ Note that you must export `getServerSideProps` as a standalone function — it w The [`getServerSideProps` API reference](/docs/api-reference/data-fetching/get-server-side-props.md) covers all parameters and props that can be used with `getServerSideProps`. -## When should I use `getServerSideProps`? +## When should I use getServerSideProps You should use `getServerSideProps` only if you need to pre-render a page whose data must be fetched at request time. [Time to First Byte (TTFB)](/learn/seo/web-performance) will be higher than [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) because the server must compute the result on every request, and the result can only be cached by a CDN using `cache-control` headers (which could require extra configuration). @@ -73,3 +73,10 @@ export async function getServerSideProps() { export default Page ``` + +<div class="card"> + <a href="/docs/api-reference/data-fetching/get-server-side-props.md"> + <b>getServerSideProps API Reference</b> + <small>Read the API Reference for getServerSideProps</small> + </a> +</div> diff --git a/docs/basic-features/data-fetching/get-static-paths.md b/docs/basic-features/data-fetching/get-static-paths.md index e83f195a348da..cb9b5b68b4381 100644 --- a/docs/basic-features/data-fetching/get-static-paths.md +++ b/docs/basic-features/data-fetching/get-static-paths.md @@ -46,3 +46,10 @@ Note that you must use export `getStaticPaths` as a standalone function — it w ## Runs on every request in development In development (`next dev`), `getStaticPaths` will be called on every request. + +<div class="card"> + <a href="/docs/api-reference/data-fetching/get-static-paths.md"> + <b>getStaticPaths API Reference</b> + <small>Read the API Reference for getStaticPaths</small> + </a> +</div> diff --git a/docs/basic-features/data-fetching/get-static-props.md b/docs/basic-features/data-fetching/get-static-props.md index 1e5319e34c21f..96bad22811c37 100644 --- a/docs/basic-features/data-fetching/get-static-props.md +++ b/docs/basic-features/data-fetching/get-static-props.md @@ -101,3 +101,10 @@ In development (`next dev`), `getStaticProps` will be called on every request. In some cases, you might want to temporarily bypass Static Generation and render the page at **request time** instead of build time. For example, you might be using a headless CMS and want to preview drafts before they're published. This use case is supported in Next.js by the [**Preview Mode**](/docs/advanced-features/preview-mode.md) feature. + +<div class="card"> + <a href="/docs/api-reference/data-fetching/get-static-props.md"> + <b>getStaticProps API Reference</b> + <small>Read the API Reference for getStaticProps</small> + </a> +</div>