diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index 1e2dec27b00c..bd8eafaac3a2 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -148,17 +148,12 @@ jobs: steps: - uses: actions/checkout@v2 - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - - run: cat package.json | jq '.resolutions.webpack = "^5.0.0-beta.30"' > package.json.tmp && mv package.json.tmp package.json + - run: cat package.json | jq '.resolutions.webpack = "^5.11.1"' > package.json.tmp && mv package.json.tmp package.json - run: cat package.json | jq '.resolutions.react = "^17.0.1"' > package.json.tmp && mv package.json.tmp package.json - run: cat package.json | jq '.resolutions."react-dom" = "^17.0.1"' > package.json.tmp && mv package.json.tmp package.json - run: yarn install --check-files - run: yarn list webpack react react-dom - - run: node run-tests.js test/integration/link-ref/test/index.test.js - - run: node run-tests.js test/integration/production/test/index.test.js - - run: node run-tests.js test/integration/basic/test/index.test.js - - run: node run-tests.js test/integration/async-modules/test/index.test.js - - run: node run-tests.js test/integration/font-optimization/test/index.test.js - - run: node run-tests.js test/acceptance/* + - run: xvfb-run node run-tests.js test/integration/{link-ref,production,basic,async-modules,font-optimization,ssr-ctx}/test/index.test.js test/acceptance/*.test.js testFirefox: name: Test Firefox (production) diff --git a/.gitignore b/.gitignore index bc9176f4c40b..f043ec68d93f 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ test/**/next-env.d.ts # Editors **/.idea +**/.#* # examples examples/**/out diff --git a/.vscode/launch.json b/.vscode/launch.json index 512d385b8e43..e7cd5522232f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,7 +22,8 @@ "runtimeExecutable": "yarn", "runtimeArgs": ["run", "debug", "build", "test/integration/basic"], "skipFiles": ["/**"], - "port": 9229 + "port": 9229, + "outFiles": ["${workspaceFolder}/packages/next/dist/**/*"] }, { "name": "Launch app production", diff --git a/.vscode/settings.json b/.vscode/settings.json index e521849f2cdb..9b9d414d6ec5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,6 @@ "javascriptreact", { "language": "typescript", "autoFix": true }, { "language": "typescriptreact", "autoFix": true } - ] + ], + "debug.javascript.unmapMissingSources": true } diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 701d0aa7b8d2..11de5bce016a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,3 +1,25 @@ +trigger: + # Only run latest commit for branches: + batch: true + # Do not run Azure CI for docs-only/example-only changes: + paths: + include: + - '*' + exclude: + - bench/* + - docs/* + - errors/* + - examples/* + # Do not run Azure on `canary`, `master`, or release tags. This unnecessarily + # increases the backlog, and the change was already tested on the PR. + branches: + include: + - '*' + exclude: + - canary + - master + - refs/tags/* + variables: YARN_CACHE_FOLDER: $(Pipeline.Workspace)/.yarn NEXT_TELEMETRY_DISABLED: '1' diff --git a/docs/api-reference/next.config.js/rewrites.md b/docs/api-reference/next.config.js/rewrites.md index 28c040178919..c32a370eddab 100644 --- a/docs/api-reference/next.config.js/rewrites.md +++ b/docs/api-reference/next.config.js/rewrites.md @@ -154,9 +154,10 @@ module.exports = { destination: '/another', // automatically becomes /docs/another }, { - // does not add /docs since basePath: false is set + // does not add /docs to /without-basePath since basePath: false is set + // Note: this can not be used for internal rewrites e.g. `destination: '/another'` source: '/without-basePath', - destination: '/another', + destination: 'https://example.com', basePath: false, }, ] diff --git a/docs/api-reference/next/image.md b/docs/api-reference/next/image.md index 39d5a11bda8c..dcca53f4db4e 100644 --- a/docs/api-reference/next/image.md +++ b/docs/api-reference/next/image.md @@ -11,9 +11,21 @@ description: Enable Image Optimization with the built-in Image component. -> Before moving forward, we recommend you to read [Image Optimization](/docs/basic-features/image-optimization.md) first. +
+ Version History + +| Version | Changes | +| --------- | ------------------------ | +| `v10.0.1` | `layout` prop added. | +| `v10.0.0` | `next/image` introduced. | + +
+ +> Before moving forward, we recommend you to read +> [Image Optimization](/docs/basic-features/image-optimization.md) first. -Image Optimization can be enabled via the `Image` component exported by `next/image`. +Image Optimization can be enabled via the `` component exported by +`next/image`. ## Usage @@ -47,41 +59,49 @@ export default Home ## Required Props -The `Image` component requires the following properties. +The `` component requires the following properties. ### src The path or URL to the source image. This is required. -When using an external URL, you must add it to [domains](/docs/basic-features/image-optimization.md#domains) in `next.config.js`. +When using an external URL, you must add it to +[domains](/docs/basic-features/image-optimization.md#domains) in +`next.config.js`. ### width The width of the image, in pixels. Must be an integer without a unit. -Required unless [layout="fill"`](#layout). +Required unless [`layout="fill"`](#layout). ### height The height of the image, in pixels. Must be an integer without a unit. -Required unless [layout="fill"`](#layout). +Required unless [`layout="fill"`](#layout). ## Optional Props -The `Image` component optionally accepts the following properties. +The `` component optionally accepts the following properties. ### layout -The layout behavior of the image as the viewport changes size. Defaults to `intrinsic`. +The layout behavior of the image as the viewport changes size. Defaults to +`intrinsic`. -When `fixed`, the image dimensions will not change as the viewport changes (no responsiveness) similar to the native `img` element. +When `fixed`, the image dimensions will not change as the viewport changes (no +responsiveness) similar to the native `img` element. -When `intrinsic`, the image will scale the dimensions down for smaller viewports but maintain the original dimensions for larger viewports. +When `intrinsic`, the image will scale the dimensions down for smaller viewports +but maintain the original dimensions for larger viewports. -When `responsive`, the image will scale the dimensions down for smaller viewports and scale up for larger viewports. +When `responsive`, the image will scale the dimensions down for smaller +viewports and scale up for larger viewports. -When `fill`, the image will stretch both width and height to the dimensions of the parent element, usually paired with [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit). +When `fill`, the image will stretch both width and height to the dimensions of +the parent element, usually paired with +[object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit). Try it out: @@ -95,23 +115,27 @@ Try it out: A string mapping media queries to device sizes. Defaults to `100vw`. -We recommend setting `sizes` when `layout="responsive"` and your image will not be the same width as the viewport. +We recommend setting `sizes` when using `layout="responsive"` or `layout="fill"` and your image will **not** be the same width as the viewport. [Learn more](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes). ### quality -The quality of the optimized image, an integer between 1 and 100 where 100 is the best quality. Defaults to 75. +The quality of the optimized image, an integer between `1` and `100` where `100` +is the best quality. Defaults to `75`. ### priority -When true, the image will be considered high priority and [preload](https://web.dev/preload-responsive-images/). +When true, the image will be considered high priority and +[preload](https://web.dev/preload-responsive-images/). -Should only be used when the image is visible above the fold. Defaults to false. +Should only be used when the image is visible above the fold. Defaults to +`false`. ## Advanced Props -In some cases, you may need more advanced usage. The `Image` component optionally accepts the following advanced properties. +In some cases, you may need more advanced usage. The `` component +optionally accepts the following advanced properties. ### objectFit @@ -127,9 +151,16 @@ The image position when using `layout="fill"`. ### loading +> **Attention**: This property is only meant for advanced usage. Switching an +> image to load with `eager` will normally **hurt performance**. +> +> We recommend using the [`priority`](#priority) property instead, which +> properly loads the image eagerly for nearly all use cases. + The loading behavior of the image. Defaults to `lazy`. -When `lazy`, defer loading the image until it reaches a calculated distance from the viewport. +When `lazy`, defer loading the image until it reaches a calculated distance from +the viewport. When `eager`, load the image immediately. @@ -137,14 +168,18 @@ When `eager`, load the image immediately. ### unoptimized -When true, the source image will be served as-is instead of changing quality, size, or format. Defaults to false. +When true, the source image will be served as-is instead of changing quality, +size, or format. Defaults to `false`. ## Other Props -Other properties on the `Image` component will be passed to the underlying `img` element with the exception of the following: +Other properties on the `` component will be passed to the underlying +`img` element with the exception of the following: - `style`. Use `className` instead. -- `srcSet`. Use [Device Sizes](/docs/basic-features/image-optimization.md#device-sizes) instead. +- `srcSet`. Use + [Device Sizes](/docs/basic-features/image-optimization.md#device-sizes) + instead. - `decoding`. It is always `"async"`. ## Related diff --git a/docs/api-reference/next/router.md b/docs/api-reference/next/router.md index 65d131888458..56de35581fb5 100644 --- a/docs/api-reference/next/router.md +++ b/docs/api-reference/next/router.md @@ -49,6 +49,7 @@ The following is the definition of the `router` object returned by both [`useRou - `locale`: `String` - The active locale (if enabled). - `locales`: `String[]` - All supported locales (if enabled). - `defaultLocale`: `String` - The current default locale (if enabled). +- `isReady`: `boolean` - Whether the router fields are updated client-side and ready for use. Should only be used inside of `useEffect` methods and not for conditionally rendering on the server. Additionally, the following methods are also included inside `router`: @@ -100,7 +101,7 @@ export default function Page() { } ``` -Redirecting the user to `pages/login.js`, useful for pages behind authentication: +Redirecting the user to `pages/login.js`, useful for pages behind [authentication](/docs/authentication): ```jsx import { useEffect } from 'react' diff --git a/docs/authentication.md b/docs/authentication.md new file mode 100644 index 000000000000..591cddb311d9 --- /dev/null +++ b/docs/authentication.md @@ -0,0 +1,208 @@ +--- +description: Learn about authentication patterns in Next.js apps and explore a few examples. +--- + +# Authentication + +Authentication verifies who a user is, while authorization controls what a user can access. Next.js supports multiple authentication patterns, each designed for different use cases. This page will go through each case so that you can choose based on your constraints. + +## 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: + +- 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. + +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/)). + +Let's look at an example for a profile page. This will initially render a loading skeleton. Once the request for a user has finished, it will show the user's name: + +```jsx +// pages/profile.js + +import useUser from '../lib/useUser' +import Layout from '../components/Layout' + +const Profile = () => { + // Fetch the user client-side + const { user } = useUser({ redirectTo: '/login' }) + + // Server-render loading state + if (!user || user.isLoggedIn === false) { + return Loading... + } + + // Once the user request finishes, show the user + return ( + +

Your Profile

+
{JSON.stringify(user, null, 2)}
+
+ ) +} + +export default Profile +``` + +You can view this example in action [here](https://next-with-iron-session.vercel.app/). Check out the [`with-iron-session`](https://github.com/vercel/next.js/tree/canary/examples/with-iron-session) example to see how it works. + +### 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`. + +```jsx +export async function getServerSideProps(context) { + return { + props: {}, // Will be passed to the page component as props + } +} +``` + +Let's transform the profile example to use [server-side rendering](/docs/basic-features/pages#server-side-rendering). If there's a session, return `user` as a prop to the `Profile` component in the page. Notice there is not a loading skeleton in [this example](https://next-with-iron-session.vercel.app/). + +```jsx +// pages/profile.js + +import withSession from '../lib/session' +import useUser from '../lib/useUser' +import Layout from '../components/Layout' + +export const getServerSideProps = withSession(async function ({ req, res }) { + // Get the user's session based on the request + const user = req.session.get('user') + + if (!user) { + return { + redirect: { + destination: '/login', + permanent: false, + }, + } + } + + return { + props: { user }, + } +}) + +const Profile = ({ user }) => { + // Show the user. No loading state is required + return ( + +

Your Profile

+
{JSON.stringify(user, null, 2)}
+
+ ) +} + +export default Profile +``` + +An advantage of this pattern is preventing a flash of unauthenticated content before redirecting. It's important to note fetching user data in `getServerSideProps` will block rendering until the request to your authentication provider resolves. To prevent creating a bottleneck and decreasing your TTFB ([Time to First Byte](https://web.dev/time-to-first-byte/)), you should ensure your authentication lookup is fast. Otherwise, consider [static generation](#authenticating-statically-generated-pages). + +## Authentication Providers + +Now that we've discussed authentication patterns, let's look at specific providers and explore how they're used with Next.js. + +### Bring Your Own Database + +
+ Examples + +
+ +If you have an existing database with user data, you'll likely want to utilize an open-source solution that's provider agnostic. + +- If you need email/password log-in, use [`next-iron-session`](https://github.com/vercel/next.js/tree/canary/examples/with-iron-session). +- If you need to persist session data on the server, use [`next-auth`](https://github.com/vercel/next.js/tree/canary/examples/with-next-auth). +- If you need to support social login (Google, Facebook, etc.), use [`next-auth`](https://github.com/vercel/next.js/tree/canary/examples/with-next-auth). +- If you want to use [JWTs](https://jwt.io/), use [`next-auth`](https://github.com/vercel/next.js/tree/canary/examples/with-next-auth). + +Both of these libraries support either authentication pattern. If you're interested in [Passport](http://www.passportjs.org/), we also have examples for it using secure and encrypted cookies: + +- [with-passport](https://github.com/vercel/next.js/tree/canary/examples/with-passport) +- [with-passport-and-next-connect](https://github.com/vercel/next.js/tree/canary/examples/with-passport-and-next-connect) + +### Firebase + +
+ Examples + +
+ +When using Firebase Authentication, we recommend using the static generation pattern. + +It is possible to use the Firebase Client SDK to generate an ID token and forward it directly to Firebase's REST API on the server to log-in. However, requests to Firebase might take some time to resolve, depending on your user's location. + +You can either use [FirebaseUI](https://github.com/firebase/firebaseui-web-react) for a drop-in UI, or create your own with a [custom React hook](https://usehooks.com/useAuth/). + +### Magic (Passwordless) + +
+ Examples + +
+ +[Magic](https://magic.link/), which uses [passwordless login](https://magic.link/), supports the static generation pattern. Similar to Firebase, a [unique identifier](https://w3c-ccg.github.io/did-primer/) has to be created on the client-side and then forwarded as a header to log-in. Then, Magic's Node SDK can be used to exchange the indentifier for a user's information. + +### Auth0 + +
+ Examples + +
+ +[Auth0](https://auth0.com/) can support both authentication patterns. You can also utilize [API routes](/docs/api-routes/introduction.md) for logging in/out and retrieving user information. After logging in using the [Auth0 SDK](https://github.com/auth0/nextjs-auth0), you can utilize static generation or `getServerSideProps` for server-side rendering. + +### Supabase + +
+ Examples + +
+ +[Supabase](https://supabase.io/) is an open source Firebase alternative that supports many of its features, including authentication. It allows for row level security using JWT tokens and supports third party logins. Either authentication pattern is supported. + +### Userbase + +
+ Examples + +
+ +[Userbase](https://userbase.com/) supports the static generation pattern for authentication. It's open source and allows for a high level of security with end-to-end encryption. You can learn more about it in their [official site](https://userbase.com/). + +## Related + +For more information on what to do next, we recommend the following sections: + +
+ + Pages: + Learn more about pages and the different pre-rendering methods in Next.js. + +
+ +
+ + Data Fetching: + Learn more about data fetching in Next.js. + +
diff --git a/docs/basic-features/data-fetching.md b/docs/basic-features/data-fetching.md index 0a7c05aa96ce..65f369480ab3 100644 --- a/docs/basic-features/data-fetching.md +++ b/docs/basic-features/data-fetching.md @@ -39,6 +39,17 @@ In addition, we’ll talk briefly about how to fetch data on the client side. ## `getStaticProps` (Static Generation) +
+ Version History + +| 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. | + +
+ 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 @@ -364,6 +375,16 @@ This use case is supported by Next.js by the feature called **Preview Mode**. Le ## `getStaticPaths` (Static Generation) +
+ Version History + +| 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. | + +
+ 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`. @@ -453,7 +474,7 @@ export default Post
Examples
@@ -587,6 +608,16 @@ In development (`next dev`), `getStaticPaths` will be called on every request. ## `getServerSideProps` (Server-side Rendering) +
+ Version History + +| Version | Changes | +| --------- | ------------------------------------------------------------------- | +| `v10.0.0` | `locale`, `locales`, `defaultLocale`, and `notFound` options added. | +| `v9.3.0` | `getServerSideProps` introduced. | + +
+ 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 diff --git a/docs/basic-features/environment-variables.md b/docs/basic-features/environment-variables.md index b53994fc2fac..68d1629a666c 100644 --- a/docs/basic-features/environment-variables.md +++ b/docs/basic-features/environment-variables.md @@ -81,7 +81,7 @@ In order to expose a variable to the browser you have to prefix the variable wit NEXT_PUBLIC_ANALYTICS_ID=abcdefghijk ``` -This loads `process.env.NEXT_PUBLIC_ANALYTICS_ID` into the Node.js environment automatically. Allowing you to use it anywhere in your code. The value will be inlined into JavaScript sent to the browser because of the `NEXT_PUBLIC_` prefix. +This loads `process.env.NEXT_PUBLIC_ANALYTICS_ID` into the Node.js environment automatically, allowing you to use it anywhere in your code. The value will be inlined into JavaScript sent to the browser because of the `NEXT_PUBLIC_` prefix. ```js // pages/index.js diff --git a/docs/basic-features/image-optimization.md b/docs/basic-features/image-optimization.md index 21094e9b547a..e3734f53db5c 100644 --- a/docs/basic-features/image-optimization.md +++ b/docs/basic-features/image-optimization.md @@ -59,7 +59,7 @@ In addition to [using properties](/docs/api-reference/next/image.md) available t ### Domains To enable Image Optimization for images hosted on an external website, use an absolute url for the Image `src` and specify which -`domains` are allowed to be optimized. This is needed to ensure that external urls can't be abused. +`domains` are allowed to be optimized. This is needed to ensure that external urls can't be abused. When `loader` is set to an external image service, this option is ignored. ```js module.exports = { diff --git a/docs/manifest.json b/docs/manifest.json index bd32807629d8..140527683c97 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -93,6 +93,10 @@ "title": "Deployment", "path": "/docs/deployment.md" }, + { + "title": "Authentication", + "path": "/docs/authentication.md" + }, { "title": "Advanced Features", "routes": [ diff --git a/errors/incompatible-href-as.md b/errors/incompatible-href-as.md index b6c4e68e1d88..f6677e90b6e7 100644 --- a/errors/incompatible-href-as.md +++ b/errors/incompatible-href-as.md @@ -11,13 +11,15 @@ Note: this error will only show when the `next/link` component is clicked not wh ```jsx import Link from 'next/link' -export default () => ( - <> - - Invalid link - - -) +export default function Page(props) { + return ( + <> + + Invalid link + + + ) +} ``` **Compatible `href` and `as`** @@ -25,13 +27,15 @@ export default () => ( ```jsx import Link from 'next/link' -export default () => ( - <> - - Valid link - - -) +export default function Page(props) { + return ( + <> + + Valid link + + + ) +} ``` #### Possible Ways to Fix It diff --git a/errors/invalid-relative-url-external-as.md b/errors/invalid-relative-url-external-as.md new file mode 100644 index 000000000000..848b56d422e4 --- /dev/null +++ b/errors/invalid-relative-url-external-as.md @@ -0,0 +1,47 @@ +# Invalid relative `href` and external `as` values + +#### Why This Error Occurred + +Somewhere you are utilizing the `next/link` component, `Router#push`, or `Router#replace` with a relative route in your `href` that has an external `as` value. The `as` value must be relative also or only `href` should be used with an external URL. + +Note: this error will only show when the `next/link` component is clicked not when only rendered. + +**Incompatible `href` and `as`** + +```jsx +import Link from 'next/link' + +export default function Page(props) { + return ( + <> + + Invalid link + + + ) +} +``` + +**Compatible `href` and `as`** + +```jsx +import Link from 'next/link' + +export default function Page(props) { + return ( + <> + + Invalid link + + + ) +} +``` + +#### Possible Ways to Fix It + +Look for any usage of the `next/link` component, `Router#push`, or `Router#replace` and make sure that the provided `href` and `as` values are compatible + +### Useful Links + +- [Routing section in Documentation](https://nextjs.org/docs/routing/introduction) diff --git a/errors/invalid-webpack-5-version.md b/errors/invalid-webpack-5-version.md new file mode 100644 index 000000000000..cb89df09be23 --- /dev/null +++ b/errors/invalid-webpack-5-version.md @@ -0,0 +1,13 @@ +# Invalid webpack 5 version + +#### Why This Error Occurred + +While leveraging webpack 5 support in Next.js the minimum required version of `v5.11.1` was not met. This version is needed while leveraging webpack 5 support with Next.js as early versions are missing patches that cause unexpected behavior. + +#### Possible Ways to Fix It + +Upgrade the version of webpack 5 being used with Next.js to at least `v5.11.1` by updating your resolutions field for `webpack` in your `package.json`. + +### Useful Links + +- [Yarn Selective Dependency Resolutions Documentation](https://classic.yarnpkg.com/en/docs/selective-version-resolutions/) diff --git a/examples/api-routes-apollo-server-and-client-auth/README.md b/examples/api-routes-apollo-server-and-client-auth/README.md index c0e2ff213bc2..509135bbfc3c 100644 --- a/examples/api-routes-apollo-server-and-client-auth/README.md +++ b/examples/api-routes-apollo-server-and-client-auth/README.md @@ -4,6 +4,12 @@ In this simple example, we integrate Apollo seamlessly with [Next.js data fetching methods](https://nextjs.org/docs/basic-features/data-fetching) to fetch queries in the server and hydrate them in the browser. +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/vercel/next.js/tree/canary/examples/api-routes-apollo-server-and-client-auth) + ## How to use Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) or [npx](https://github.com/zkat/npx#readme) to bootstrap the example: diff --git a/examples/api-routes-apollo-server-and-client-auth/lib/auth.js b/examples/api-routes-apollo-server-and-client-auth/lib/auth.js index 6dc386d15e6b..fe830e95d5e4 100644 --- a/examples/api-routes-apollo-server-and-client-auth/lib/auth.js +++ b/examples/api-routes-apollo-server-and-client-auth/lib/auth.js @@ -21,7 +21,9 @@ export async function getLoginSession(req) { const expiresAt = session.createdAt + session.maxAge * 1000 // Validate the expiration date of the session - if (Date.now() < expiresAt) { - return session + if (Date.now() > expiresAt) { + throw new Error('Session expired') } + + return session } diff --git a/examples/blog-starter-typescript/README.md b/examples/blog-starter-typescript/README.md index e8db3fc2498c..671760cb4b37 100644 --- a/examples/blog-starter-typescript/README.md +++ b/examples/blog-starter-typescript/README.md @@ -30,4 +30,6 @@ Deploy it to the cloud with [Vercel](https://vercel.com/import?filter=next.js&ut # Notes -This blog-starter-typescript uses [Tailwind CSS](https://tailwindcss.com). To control the generated stylesheet's filesize, this example uses Tailwind CSS' v1.4 [`purge` option](https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css) to remove unused CSS. +This blog-starter-typescript uses [Tailwind CSS](https://tailwindcss.com). To control the generated stylesheet's filesize, this example uses Tailwind CSS' v2.0 [`purge` option](https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css) to remove unused CSS. + +[Tailwind CSS v2.0 no longer supports Node.js 8 or 10](https://tailwindcss.com/docs/upgrading-to-v2#upgrade-to-node-js-12-13-or-higher). To build your CSS you'll need to ensure you are running Node.js 12.13.0 or higher in both your local and CI environments. diff --git a/examples/blog-starter-typescript/components/hero-post.tsx b/examples/blog-starter-typescript/components/hero-post.tsx index 5bd84f9bbe0d..cd0f121c01fa 100644 --- a/examples/blog-starter-typescript/components/hero-post.tsx +++ b/examples/blog-starter-typescript/components/hero-post.tsx @@ -26,7 +26,7 @@ const HeroPost = ({
-
+

diff --git a/examples/blog-starter-typescript/components/more-stories.tsx b/examples/blog-starter-typescript/components/more-stories.tsx index 205c548f665a..1c2c038266e2 100644 --- a/examples/blog-starter-typescript/components/more-stories.tsx +++ b/examples/blog-starter-typescript/components/more-stories.tsx @@ -11,7 +11,7 @@ const MoreStories = ({ posts }: Props) => {

More Stories

-
+
{posts.map((post) => ( ) return ( diff --git a/examples/blog-starter/components/hero-post.js b/examples/blog-starter/components/hero-post.js index cfedfb874fe4..ddb182a8b716 100644 --- a/examples/blog-starter/components/hero-post.js +++ b/examples/blog-starter/components/hero-post.js @@ -14,9 +14,15 @@ export default function HeroPost({ return (
- +
-
+

diff --git a/examples/blog-starter/components/more-stories.js b/examples/blog-starter/components/more-stories.js index dcdd9b4e6ae7..57fdbb6c4659 100644 --- a/examples/blog-starter/components/more-stories.js +++ b/examples/blog-starter/components/more-stories.js @@ -6,7 +6,7 @@ export default function MoreStories({ posts }) {

More Stories

-
+
{posts.map((post) => (
- +
diff --git a/examples/blog-starter/components/post-preview.js b/examples/blog-starter/components/post-preview.js index fd067f4f868f..3e3009fa2721 100644 --- a/examples/blog-starter/components/post-preview.js +++ b/examples/blog-starter/components/post-preview.js @@ -14,7 +14,13 @@ export default function PostPreview({ return (
- +

diff --git a/examples/blog-starter/package.json b/examples/blog-starter/package.json index b720e7a34a85..134d656d9364 100644 --- a/examples/blog-starter/package.json +++ b/examples/blog-starter/package.json @@ -8,17 +8,19 @@ }, "dependencies": { "classnames": "2.2.6", - "date-fns": "2.10.0", + "date-fns": "2.16.1", "gray-matter": "4.0.2", "next": "latest", - "react": "^16.13.0", - "react-dom": "^16.13.0", - "remark": "11.0.2", - "remark-html": "10.0.0" + "react": "^17.0.1", + "react-dom": "^17.0.1", + "remark": "13.0.0", + "remark-html": "13.0.1" }, "devDependencies": { + "autoprefixer": "10.0.4", + "postcss": "8.1.10", "postcss-preset-env": "^6.7.0", - "tailwindcss": "^1.4.0" + "tailwindcss": "2.0.1" }, "license": "MIT" } diff --git a/examples/blog-starter/tailwind.config.js b/examples/blog-starter/tailwind.config.js index dc81b5174ced..e32267d853ff 100644 --- a/examples/blog-starter/tailwind.config.js +++ b/examples/blog-starter/tailwind.config.js @@ -25,8 +25,8 @@ module.exports = { '8xl': '6.25rem', }, boxShadow: { - small: '0 5px 10px rgba(0, 0, 0, 0.12)', - medium: '0 8px 30px rgba(0, 0, 0, 0.12)', + sm: '0 5px 10px rgba(0, 0, 0, 0.12)', + md: '0 8px 30px rgba(0, 0, 0, 0.12)', }, }, }, diff --git a/examples/using-router/pages/about.js b/examples/using-router/pages/about.js index 3db9c4292686..086dde4a3266 100644 --- a/examples/using-router/pages/about.js +++ b/examples/using-router/pages/about.js @@ -1,4 +1,4 @@ -import Header from '../components/header' +import Header from '../components/Header' export default function About() { return ( diff --git a/examples/with-ant-design-mobile/README.md b/examples/with-ant-design-mobile/README.md index 2cc3dfa18b97..dae1315050df 100644 --- a/examples/with-ant-design-mobile/README.md +++ b/examples/with-ant-design-mobile/README.md @@ -1,6 +1,6 @@ # Ant Design Mobile example -This example features how you use [antd-mobile](https://github.com/ant-design/ant-design-mobile) (Ant Design Mobile FrontEnd Framwork) with Next.js. +This example features how you use [antd-mobile](https://github.com/ant-design/ant-design-mobile) (Ant Design Mobile FrontEnd Framework) with Next.js. ## Deploy your own diff --git a/examples/with-deta-base/README.md b/examples/with-deta-base/README.md index 8e7e989fd198..c302ded01d15 100644 --- a/examples/with-deta-base/README.md +++ b/examples/with-deta-base/README.md @@ -36,10 +36,10 @@ Then set each variable on `.env.local`: - `DETA_PROJECT_KEY` should be the default _Project Key_ that you saved from step 1. -The resulting `env.local` file shoule look like this: +The resulting `env.local` file should look like this: ```bash -DETA_PROEJECT_KEY=... +DETA_PROJECT_KEY=... ``` ### Step 3. Run Next.js in development mode diff --git a/examples/with-draft-js/README.md b/examples/with-draft-js/README.md index 8bed79038428..28cba34dc57f 100644 --- a/examples/with-draft-js/README.md +++ b/examples/with-draft-js/README.md @@ -2,7 +2,7 @@ Have you ever wanted to have an editor like medium.com in your Next.js app? DraftJS is available for SSR, but some plugins like the toolbar are using `window`, which does not work when doing SSR. -This example aims to provides a fully customizable example of the famous medium editor with DraftJS. The goal was to get it as customizable as possible, and fully working with Next.js without using the react-no-ssr package. +This example aims to provide a fully customizable example of the famous medium editor with DraftJS. The goal was to get it as customizable as possible, and fully working with Next.js without using the react-no-ssr package. ## Deploy your own diff --git a/examples/with-electron-typescript/README.md b/examples/with-electron-typescript/README.md index fb9174987141..fd6c82b2fcaa 100644 --- a/examples/with-electron-typescript/README.md +++ b/examples/with-electron-typescript/README.md @@ -29,7 +29,7 @@ Available commands: "build-electron": transpile electron layer "build": build both layers "dev": start dev version -"dist": create production elctron build +"dist": create production electron build "type-check": check TypeScript in project ``` diff --git a/examples/with-emotion/README.md b/examples/with-emotion/README.md index b3c23b672426..884851b8aa6b 100644 --- a/examples/with-emotion/README.md +++ b/examples/with-emotion/README.md @@ -3,7 +3,7 @@ Extract and inline critical css with [emotion](https://github.com/emotion-js/emotion/tree/master/packages/emotion), [emotion-server](https://github.com/emotion-js/emotion/tree/master/packages/emotion-server), -[@emotion/core](https://github.com/emotion-js/emotion/tree/master/packages/core), +[@emotion/react](https://github.com/emotion-js/emotion/tree/master/packages/react), and [@emotion/styled](https://github.com/emotion-js/emotion/tree/master/packages/styled). ## Deploy your own diff --git a/examples/with-env-from-next-config-js/README.md b/examples/with-env-from-next-config-js/README.md index 2ebf547d7edf..fa1d882fa958 100644 --- a/examples/with-env-from-next-config-js/README.md +++ b/examples/with-env-from-next-config-js/README.md @@ -46,4 +46,4 @@ following behavior while you are doing development. - When you run `next build` then `next start`, assuming you set externally the environmental variable STAGING to anything but 1, you will get the results assuming `isProd` is true. - When your run `next build` or `npm run build` in production, if the environmental variable `STAGING` is set to `1`, `isStaging` will be set and you will get those values returned. -You can read more about this feature in thie blog post Next.js 5.1: Faster Page Resolution, Environment Config and More (under Environment Config). +You can read more about this feature in this blog post Next.js 5.1: Faster Page Resolution, Environment Config and More (under Environment Config). diff --git a/examples/with-firebase-hosting/README.md b/examples/with-firebase-hosting/README.md index 0aad56b34cc0..1dcee30bc395 100644 --- a/examples/with-firebase-hosting/README.md +++ b/examples/with-firebase-hosting/README.md @@ -54,7 +54,7 @@ Then you can create components and pages in `.tsx` or `.ts` ## Good to know - [`firebase.json`](firebase.json:#L7) outlines the catchall rewrite rule for our Cloud Function. -- The empty `public/.gitignore` file is to ensure `public/` dir exists as it is required for Firebase Hosting. It is [configured](firebase.json:#L4) (by [default](https://firebase.google.com/docs/hosting/full-config#ignore)) that dotfiles (`public/.*`) are ignored from bein publicly served. +- The empty `public/.gitignore` file is to ensure `public/` dir exists as it is required for Firebase Hosting. It is [configured](firebase.json:#L4) (by [default](https://firebase.google.com/docs/hosting/full-config#ignore)) that dotfiles (`public/.*`) are ignored from being publicly served. - The Cloud Function is named `nextjsFunc` (changeable in [firebaseFunctions.js](firebaseFunctions.js#L16) and [firebase.json](firebase.json#L8)). - `public/*` files are statically served through [Firebase hosting](https://firebase.google.com/docs/hosting/full-config#public), not through [NextJs server](https://nextjs.org/docs/basic-features/static-file-serving). diff --git a/examples/with-google-tag-manager/.env.local.example b/examples/with-google-tag-manager/.env.local.example new file mode 100644 index 000000000000..474e6beaa7ec --- /dev/null +++ b/examples/with-google-tag-manager/.env.local.example @@ -0,0 +1 @@ +NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID= \ No newline at end of file diff --git a/examples/with-google-tag-manager/.gitignore b/examples/with-google-tag-manager/.gitignore new file mode 100644 index 000000000000..1437c53f70bc --- /dev/null +++ b/examples/with-google-tag-manager/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/examples/with-google-tag-manager/README.md b/examples/with-google-tag-manager/README.md new file mode 100644 index 000000000000..3d418c94efaf --- /dev/null +++ b/examples/with-google-tag-manager/README.md @@ -0,0 +1,29 @@ +## Example app using Google Tag Manager + +This example shows how to use Next.js along with Google Tag Manager. [`pages/_document.js`](pages/_document.js) is used to inject [base code](https://developers.google.com/tag-manager/quickstart). [`pages/_app.js`](pages/_app.js) is used to track route changes and send page views to Google Tag Manager. + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/vercel/next.js/tree/canary/examples/with-google-tag-manager) + +## How to use + +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npx create-next-app --example with-google-tag-manager with-google-tag-manager-app +# or +yarn create next-app --example with-google-tag-manager with-google-tag-manager-app +``` + +Next, copy the `.env.local.example` file in this directory to `.env.local` (which will be ignored by Git): + +```bash +cp .env.local.example .env.local +``` + +Set the `NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID` variable in `.env.local` to match your Google Tag Manager ID. + +Deploy it to the cloud with [Vercel](https://vercel.com/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-google-tag-manager/components/GoogleTagManager.js b/examples/with-google-tag-manager/components/GoogleTagManager.js new file mode 100644 index 000000000000..49b89be14c5f --- /dev/null +++ b/examples/with-google-tag-manager/components/GoogleTagManager.js @@ -0,0 +1,22 @@ +import { useEffect } from 'react' +import { useRouter } from 'next/router' +import * as gtm from '../lib/gtm' + +const handleRouteChange = () => { + gtm.pageview() +} + +const GoogleTagManager = ({ children }) => { + const router = useRouter() + + useEffect(() => { + router.events.on('routeChangeComplete', handleRouteChange) + return () => { + router.events.off('routeChangeComplete', handleRouteChange) + } + }, [router.events]) + + return children +} + +export default GoogleTagManager diff --git a/examples/with-google-tag-manager/lib/gtm.js b/examples/with-google-tag-manager/lib/gtm.js new file mode 100644 index 000000000000..7044f1aa8389 --- /dev/null +++ b/examples/with-google-tag-manager/lib/gtm.js @@ -0,0 +1,8 @@ +export const GTM_ID = process.env.NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID + +export const pageview = (url) => { + window.dataLayer({ + event: 'pageview', + page: url, + }) +} diff --git a/examples/with-google-tag-manager/package.json b/examples/with-google-tag-manager/package.json new file mode 100644 index 000000000000..711839deedb8 --- /dev/null +++ b/examples/with-google-tag-manager/package.json @@ -0,0 +1,15 @@ +{ + "name": "with-google-tag-manager", + "version": "0.1.0", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "latest", + "react": "^16.13.1", + "react-dom": "^16.13.1" + }, + "license": "MIT" +} diff --git a/examples/with-google-tag-manager/pages/_app.js b/examples/with-google-tag-manager/pages/_app.js new file mode 100644 index 000000000000..3e2416997425 --- /dev/null +++ b/examples/with-google-tag-manager/pages/_app.js @@ -0,0 +1,11 @@ +import GoogleTagManager from '../components/GoogleTagManager' + +function MyApp({ Component, pageProps }) { + return ( + + + + ) +} + +export default MyApp diff --git a/examples/with-google-tag-manager/pages/_document.js b/examples/with-google-tag-manager/pages/_document.js new file mode 100644 index 000000000000..d9ab0ee01f96 --- /dev/null +++ b/examples/with-google-tag-manager/pages/_document.js @@ -0,0 +1,37 @@ +import Document, { Html, Head, Main, NextScript } from 'next/document' +import { GTM_ID } from '../lib/gtm' + +export default class MyDocument extends Document { + render() { + return ( + + + {/* Google Tag Manager - Global base code */} +