diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index eacdc887f86c5..9b315dc64a7f2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,7 +4,7 @@ * @timneutkens @ijjk @shuding @huozhi /.github/ @timneutkens @ijjk @shuding @styfle @huozhi @padmaia @balazsorban44 /docs/ @timneutkens @ijjk @shuding @styfle @huozhi @padmaia @leerob @balazsorban44 -/errors/ @balazsorban44 +/errors/ @timneutkens @ijjk @shuding @styfle @huozhi @padmaia @leerob @balazsorban44 /examples/ @timneutkens @ijjk @shuding @leerob @steven-tey @balazsorban44 # SWC Build & Telemetry (@padmaia) diff --git a/docs/advanced-features/output-file-tracing.md b/docs/advanced-features/output-file-tracing.md index 69dcfa1568f83..b12c8a8c757eb 100644 --- a/docs/advanced-features/output-file-tracing.md +++ b/docs/advanced-features/output-file-tracing.md @@ -16,11 +16,11 @@ During `next build`, Next.js will use [`@vercel/nft`](https://github.com/vercel/ Next.js' production server is also traced for its needed files and output at `.next/next-server.js.nft.json` which can be leveraged in production. -To leverage the `.nft.json` files emitted to the `.next` output directory, you can read the list of files in each trace which are relative to the `.nft.json` file and then copy them to your deployment location. +To leverage the `.nft.json` files emitted to the `.next` output directory, you can read the list of files in each trace that are relative to the `.nft.json` file and then copy them to your deployment location. ## Automatically Copying Traced Files -Next.js can automatically create a `standalone` folder which copies only the necessary files for a production deployment including select files in `node_modules`. +Next.js can automatically create a `standalone` folder that copies only the necessary files for a production deployment including select files in `node_modules`. To leverage this automatic copying you can enable it in your `next.config.js`: @@ -30,12 +30,26 @@ module.exports = { } ``` -This will create a folder at `.next/standalone` which can then be deployed on it's own without installing `node_modules`. +This will create a folder at `.next/standalone` which can then be deployed on its own without installing `node_modules`. Additionally, a minimal `server.js` file is also output which can be used instead of `next start`. This minimal server does not copy the `public` or `.next/static` folders by default as these should ideally be handled by a CDN instead, although these folders can be copied to the `standalone/public` and `standalone/.next/static` folders manually, after which `server.js` file will serve these automatically. Note: `next.config.js` is read during `next build` and serialized into the `server.js` output file. If the legacy [`serverRuntimeConfig` or `publicRuntimeConfig` options](/docs/api-reference/next.config.js/runtime-configuration.md) are being used, the values will be specific to values at build time. +If your project uses [Image Optimization](/docs/basic-features/image-optimization.md) with the default `loader`, you must install `sharp` as a dependency: + +```bash +npm i sharp +``` + +```bash +yarn add sharp +``` + +```bash +pnpm add sharp +``` + ## Caveats - While tracing in monorepo setups, the project directory is used for tracing by default. For `next build packages/web-app`, `packages/web-app` would be the tracing root and any files outside of that folder will not be included. To include files outside of this folder you can set `experimental.outputFileTracingRoot` in your `next.config.js`. @@ -50,5 +64,5 @@ module.exports = { } ``` -- There are some cases that Next.js might fail to include required files, or might incorrectly include unused files. In those cases, you can export page configs props `unstable_includeFiles` and `unstable_excludeFiles` respectively. Each prop accepts an array of [minimatch globs](https://www.npmjs.com/package/minimatch) relative to the project's root to either include or exclude in the trace. +- There are some cases in which Next.js might fail to include required files, or might incorrectly include unused files. In those cases, you can export page configs props `unstable_includeFiles` and `unstable_excludeFiles` respectively. Each prop accepts an array of [minimatch globs](https://www.npmjs.com/package/minimatch) relative to the project's root to either include or exclude in the trace. - Currently, Next.js does not do anything with the emitted `.nft.json` files. The files must be read by your deployment platform, for example [Vercel](https://vercel.com), to create a minimal deployment. In a future release, a new command is planned to utilize these `.nft.json` files. diff --git a/errors/babel-font-loader-conflict.md b/errors/babel-font-loader-conflict.md new file mode 100644 index 0000000000000..6999883ddcda4 --- /dev/null +++ b/errors/babel-font-loader-conflict.md @@ -0,0 +1,14 @@ +# Babel and Font loader conflict + +#### Why This Error Occurred + +You have tried to use `experimental.fontLoaders` with a custom babel config. When your application has a custom babel config you opt-out of the Next.js Compiler which is required to use `experimental.fontLoaders`. + +#### Possible Ways to Fix It + +- Remove your custom babel config and use the Next.js Compiler + +### Useful Links + +- [Next.js Compiler](https://nextjs.org/docs/advanced-features/compiler) +- [Customizing Babel Config](https://nextjs.org/docs/advanced-features/customizing-babel-config) diff --git a/errors/manifest.json b/errors/manifest.json index 41bb35c7d6004..79a55d1d71831 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -737,6 +737,10 @@ { "title": "nonce-contained-invalid-characters", "path": "/errors/nonce-contained-invalid-characters.md" + }, + { + "title": "babel-font-loader-conflict", + "path": "/errors/babel-font-loader-conflict.md" } ] } diff --git a/errors/sharp-missing-in-production.md b/errors/sharp-missing-in-production.md index 96903efad9ca5..d7c70fde8169a 100644 --- a/errors/sharp-missing-in-production.md +++ b/errors/sharp-missing-in-production.md @@ -2,14 +2,35 @@ #### Why This Error Occurred -The `next/image` component's default loader uses [`squoosh`](https://www.npmjs.com/package/@squoosh/lib) because it is quick to install and suitable for a development environment. For a production environment using `next start`, it is strongly recommended you install [`sharp`](https://www.npmjs.com/package/sharp) by running `yarn add sharp` in your project directory. +The `next/image` component's default loader uses [`squoosh`](https://www.npmjs.com/package/@squoosh/lib) because it is quick to install and suitable for a development environment. + +- For a production environment using `next start`, it is strongly recommended you install [`sharp`](https://www.npmjs.com/package/sharp). You are seeing this error because Image Optimization in production mode (`next start`) was detected. +- For a production environment using `output: "standalone"`, you must install [`sharp`](https://www.npmjs.com/package/sharp). + +You are seeing this error because Image Optimization in standalone mode (`output: "standalone"`) was detected. + #### Possible Ways to Fix It -- Install `sharp` by running `yarn add sharp` in your project directory and then reboot the server by running `next start` again -- If `sharp` is already installed but can't be resolved, set the `NEXT_SHARP_PATH` environment variable such as `NEXT_SHARP_PATH=/tmp/node_modules/sharp next start` +- Install `sharp` by running one of the following commands in your project directory: + +```bash +npm i sharp +``` + +```bash +yarn add sharp +``` + +```bash +pnpm add sharp +``` + +Then, build your project with `next build`. Finally, restart the server with either `next start` for production mode or `node server.js` for standalone mode. + +- If `sharp` is already installed but can't be resolved, set the `NEXT_SHARP_PATH` environment variable such as `export NEXT_SHARP_PATH=/tmp/node_modules/sharp`. Then, build your project with `next build`. Finally, restart the server with either `next start` for production mode or `node server.js` for standalone mode. > Note: This is not necessary for Vercel deployments, since `sharp` is installed automatically for you. @@ -17,3 +38,4 @@ You are seeing this error because Image Optimization in production mode (`next s - [Image Optimization Documentation](https://nextjs.org/docs/basic-features/image-optimization) - [`next/image` Documentation](https://nextjs.org/docs/api-reference/next/image) +- [Output File Tracing](/docs/advanced-features/output-file-tracing) diff --git a/examples/cms-webiny/.env.local.example b/examples/cms-webiny/.env.local.example new file mode 100644 index 0000000000000..414d0d3c6b55b --- /dev/null +++ b/examples/cms-webiny/.env.local.example @@ -0,0 +1,4 @@ +PREVIEW_API_SECRET= +WEBINY_API_SECRET= +NEXT_PUBLIC_WEBINY_API_URL= +NEXT_PUBLIC_WEBINY_PREVIEW_API_URL= \ No newline at end of file diff --git a/examples/cms-webiny/.gitignore b/examples/cms-webiny/.gitignore new file mode 100644 index 0000000000000..8f322f0d8f495 --- /dev/null +++ b/examples/cms-webiny/.gitignore @@ -0,0 +1,35 @@ +# 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 + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/examples/cms-webiny/README.md b/examples/cms-webiny/README.md new file mode 100644 index 0000000000000..2d17ed015941f --- /dev/null +++ b/examples/cms-webiny/README.md @@ -0,0 +1,132 @@ +# A statically generated blog example using Next.js and Webiny + +This example showcases Next.js's [Static Generation](https://nextjs.org/docs/basic-features/pages) feature using [Webiny](https://webiny.com/) as the data source. + +## Demo + +[https://webiny-headlesscms-nextjs-example.vercel.app/](https://webiny-headlesscms-nextjs-example.vercel.app/) + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/cms-webiny&project-name=cms-webiny&repository-name=cms-webiny&env=PREVIEW_API_SECRET,WEBINY_API_SECRET,NEXT_PUBLIC_WEBINY_API_URL,NEXT_PUBLIC_WEBINY_PREVIEW_API_URL&envDescription=Required%20to%20connect%20the%20app%20with%20Webiny&envLink=https://vercel.link/cms-webiny-env) + +### Related examples + +- [WordPress](/examples/cms-wordpress) +- [DatoCMS](/examples/cms-datocms) +- [Sanity](/examples/cms-sanity) +- [TakeShape](/examples/cms-takeshape) +- [Prismic](/examples/cms-prismic) +- [Contentful](/examples/cms-contentful) +- [Strapi](/examples/cms-strapi) +- [Agility CMS](/examples/cms-agilitycms) +- [Cosmic](/examples/cms-cosmic) +- [ButterCMS](/examples/cms-buttercms) +- [Storyblok](/examples/cms-storyblok) +- [GraphCMS](/examples/cms-graphcms) +- [Kontent](/examples/cms-kontent) +- [Umbraco Heartcore](/examples/cms-umbraco-heartcore) +- [Builder.io](/examples/cms-builder-io) + +## 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), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: + +```bash +npx create-next-app --example cms-webiny cms-webiny-app +``` + +```bash +yarn create next-app --example cms-webiny cms-webiny-app +``` + +```bash +pnpm create next-app --example cms-webiny cms-webiny-app +``` + +### Step 1. Set up a Webiny project + +Follow the [Webiny docs](https://www.webiny.com/docs/tutorials/install-webiny) to install a Webiny project on your cloud hosting provider. Because Webiny is a distributed system we don't run it locally. This also means you don't need to worry about setting up Docker, or installing databases and drivers on your local machine for Postgres, MongoDB or similar. The cloud takes care of that for you. + +If you get stuck or have any questions, please [join the community](http://webiny-community.slack.com 'Webiny slack channel') and reach out for some help. + +Once you have an app up and running click into the "HeadlessCMS" app in the sidebar, click on _models_ and add the following models and fields: + +#### Authors + +- A `text` field with the value "name" +- A `text` field with the value "slug" (optionally add a validator using this regex which will make sure you have valid urls: `^(?!.*--)[a-z0-9\-]+$`) +- a `files` field with the value "picture" + +#### Posts + +- A `text` field with the value "title" +- A `text` field with the value "slug" (optionally use the regex above as a validator) +- A `files` field with the value "featured image" +- A `rich text` field with the value "body" +- A `reference` field with the value "Author" + +Next, choose **API Keys** in the sidebar. Add an API key with any name and description. Select "Headless CMS" and choose a Custom access level for all content model groups with the values `read` and `preview`. Save the API token and the token itself will be revealed. + +You will be able to use the same API token for both published and draft posts. + +### Step 2. Set up environment variables + +Copy the `.env.local.example` file to `.env.local`, then set the variables as follows: + +- `PREVIEW_API_SECRET` can be any random string (but avoid spaces), like `MY_SECRET` - this is used for [Preview Mode](https://nextjs.org/docs/advanced-features/preview-mode). +- WEBINY_API_SECRET this will be your security token generated in Webiny +- You can find the values for `NEXT_PUBLIC_WEBINY_API_URL` and `NEXT_PUBLIC_WEBINY_PREVIEW_API_URL` two ways: From your local Webiny project root, run `yarn webiny info`, alternatively go to **API Playground** in the sidebar. At the top of the GraphQL explorer are four tabs, one for each of our APIs, and you'll see both the Read API and the Preview API on those tabs. The URL for your environment is just below the tab. ([More info here if you get stuck](https://www.webiny.com/docs/headless-cms/basics/graphql-api)) + +### Step 3. Run Next.js in development mode + +Inside the Next.js app directory, run: + +```bash +npm install +npm run dev + +# or + +yarn install +yarn dev +``` + +Your blog should be up and running on [http://localhost:3000](http://localhost:3000)! + +The best place to debug is inside the `fetchAPI` function in `lib/api.js`. If you need help, you can post on [GitHub discussions](https://github.com/vercel/next.js/discussions). + +### Step 4. Try preview mode + +If you go to the `/posts/draft` page on localhost, you won't see this post because it’s not published. However, if you use the **Preview Mode**, you'll be able to see the change ([Documentation](https://nextjs.org/docs/advanced-features/preview-mode)). + +To enable the Preview Mode, go to this URL: + +``` +http://localhost:3000/api/preview?secret=&slug=draft +``` + +- `` should be the string you entered for `PREVIEW_API_SECRET`. +- `` should be the post's `slug` attribute. + +You should now be able to see the draft post. To exit the preview mode, you can click **Click here to exit preview mode** at the top. + +To add more preview pages, create a post and set the **status** as `draft`. + +### Step 5. Deploy on Vercel + +You can deploy this app to the cloud with [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). + +#### Deploy Your Local Project + +To deploy your local project to Vercel, push it to GitHub/GitLab/Bitbucket and [import to Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example). + +**Important**: When you import your project on Vercel, make sure to click on **Environment Variables** and set them to match your `.env.local` file. + +#### Deploy from Our Template + +Alternatively, you can deploy using our template by clicking on the Deploy button below. + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/cms-webiny&project-name=cms-webiny&repository-name=cms-webiny&env=PREVIEW_API_SECRET,WEBINY_API_SECRET,NEXT_PUBLIC_WEBINY_API_URL,NEXT_PUBLIC_WEBINY_PREVIEW_API_URL&envDescription=Required%20to%20connect%20the%20app%20with%20Webiny&envLink=https://vercel.link/cms-webiny-env) diff --git a/examples/cms-webiny/components/alert.tsx b/examples/cms-webiny/components/alert.tsx new file mode 100644 index 0000000000000..018eae66ad5aa --- /dev/null +++ b/examples/cms-webiny/components/alert.tsx @@ -0,0 +1,42 @@ +import Container from './container' +import cn from 'classnames' +import { EXAMPLE_PATH } from '../lib/constants' + +export default function Alert({ preview }) { + return ( +
+ +
+ {preview ? ( + <> + This page is a preview.{' '} + + Click here + {' '} + to exit preview mode. + + ) : ( + <> + The source code for this blog is{' '} + + available on GitHub + + . + + )} +
+
+
+ ) +} diff --git a/examples/cms-webiny/components/avatar.tsx b/examples/cms-webiny/components/avatar.tsx new file mode 100644 index 0000000000000..228e60143747f --- /dev/null +++ b/examples/cms-webiny/components/avatar.tsx @@ -0,0 +1,15 @@ +import Image from 'next/image' +export default function Avatar({ name, picture }) { + return ( +
+ {name} +
{name}
+
+ ) +} diff --git a/examples/cms-webiny/components/container.tsx b/examples/cms-webiny/components/container.tsx new file mode 100644 index 0000000000000..c3ed24c0515ba --- /dev/null +++ b/examples/cms-webiny/components/container.tsx @@ -0,0 +1,3 @@ +export default function Container({ children }) { + return
{children}
+} diff --git a/examples/cms-webiny/components/cover-image.tsx b/examples/cms-webiny/components/cover-image.tsx new file mode 100644 index 0000000000000..f99220e78a396 --- /dev/null +++ b/examples/cms-webiny/components/cover-image.tsx @@ -0,0 +1,44 @@ +import cn from 'classnames' +import Link from 'next/link' +import Image from 'next/image' + +export type TCoverImage = { + title: string + src: string + slug?: string + height: number + width: number +} + +const CoverImage: React.FC = ({ + title, + src, + slug, + height, + width, +}) => { + const image = ( + {`Cover + ) + return ( +
+ {slug ? ( + + {image} + + ) : ( + image + )} +
+ ) +} +export default CoverImage diff --git a/examples/cms-webiny/components/date-formatter.tsx b/examples/cms-webiny/components/date-formatter.tsx new file mode 100644 index 0000000000000..f91f2fbcb371f --- /dev/null +++ b/examples/cms-webiny/components/date-formatter.tsx @@ -0,0 +1,10 @@ +import { parseISO, format } from 'date-fns' + +export default function DateFormatter({ dateString }) { + if (!dateString) { + return null + } + const date = parseISO(dateString) + const formattedDate = format(date, 'LLLL d, yyyy') + return +} diff --git a/examples/cms-webiny/components/footer.tsx b/examples/cms-webiny/components/footer.tsx new file mode 100644 index 0000000000000..ca1e8bac51eff --- /dev/null +++ b/examples/cms-webiny/components/footer.tsx @@ -0,0 +1,30 @@ +import Container from './container' +import { EXAMPLE_PATH } from '../lib/constants' + +export default function Footer() { + return ( + + ) +} diff --git a/examples/cms-webiny/components/header.tsx b/examples/cms-webiny/components/header.tsx new file mode 100644 index 0000000000000..eb9c8e1bcf652 --- /dev/null +++ b/examples/cms-webiny/components/header.tsx @@ -0,0 +1,12 @@ +import Link from 'next/link' + +export default function Header() { + return ( +

+ + Blog + + . +

+ ) +} diff --git a/examples/cms-webiny/components/hero-post.tsx b/examples/cms-webiny/components/hero-post.tsx new file mode 100644 index 0000000000000..b6905a9fd122f --- /dev/null +++ b/examples/cms-webiny/components/hero-post.tsx @@ -0,0 +1,43 @@ +import Avatar from '../components/avatar' +import DateFormatter from '../components/date-formatter' +import CoverImage from '../components/cover-image' +import Link from 'next/link' + +export default function HeroPost({ + title, + coverImage, + createdOn, + excerpt, + author, + slug, +}) { + return ( +
+
+ +
+
+
+

+ + {title} + +

+
+ +
+
+
+

{excerpt}

+ +
+
+
+ ) +} diff --git a/examples/cms-webiny/components/intro.tsx b/examples/cms-webiny/components/intro.tsx new file mode 100644 index 0000000000000..01759fd8fad03 --- /dev/null +++ b/examples/cms-webiny/components/intro.tsx @@ -0,0 +1,28 @@ +import { CMS_NAME, CMS_URL } from '../lib/constants' + +export default function Intro() { + return ( +
+

+ Blog. +

+

+ A statically generated blog example using{' '} + + Next.js + {' '} + and{' '} + + {CMS_NAME} + + . +

+
+ ) +} diff --git a/examples/cms-webiny/components/layout.tsx b/examples/cms-webiny/components/layout.tsx new file mode 100644 index 0000000000000..99d95353131e0 --- /dev/null +++ b/examples/cms-webiny/components/layout.tsx @@ -0,0 +1,16 @@ +import Alert from '../components/alert' +import Footer from '../components/footer' +import Meta from '../components/meta' + +export default function Layout({ preview, children }) { + return ( + <> + +
+ +
{children}
+
+