From b92b7447fa0e6a517f142f467ca97b9de991ec1b Mon Sep 17 00:00:00 2001 From: Michael Novotny Date: Mon, 14 Feb 2022 11:14:32 -0600 Subject: [PATCH 01/20] Adds consistency to ESLint rules. --- docs/basic-features/eslint.md | 42 ++++++----- errors/google-font-display.md | 9 ++- errors/google-font-preconnect.md | 2 + errors/inline-script-id.md | 4 +- errors/link-passhref.md | 4 +- errors/manifest.json | 8 +- errors/next-script-for-ga.md | 2 + errors/no-css-tags.md | 4 +- errors/no-document-import-in-page.md | 2 + errors/no-duplicate-head.md | 2 + errors/no-head-element.md | 4 +- errors/no-head-import-in-document.md | 6 ++ errors/no-html-link-for-pages.md | 4 +- errors/no-img-element.md | 4 +- errors/no-page-custom-font.md | 4 +- ...nent.md => no-script-component-in-head.md} | 8 +- ...ument-page.md => no-script-in-document.md} | 8 +- errors/no-server-import-in-page.md | 2 + errors/no-sync-scripts.md | 15 +++- errors/no-title-in-document-head.md | 4 +- errors/no-unwanted-polyfillio.md | 8 +- packages/eslint-plugin-next/lib/index.js | 70 ++++++++--------- .../lib/rules/google-font-display.js | 18 +++-- .../lib/rules/google-font-preconnect.js | 8 +- .../lib/rules/inline-script-id.js | 9 ++- .../lib/rules/link-passhref.js | 13 ++-- .../lib/rules/next-script-for-ga.js | 14 ++-- .../lib/rules/no-css-tags.js | 75 +++++++++++-------- .../lib/rules/no-document-import-in-page.js | 8 +- .../lib/rules/no-duplicate-head.js | 10 ++- .../lib/rules/no-head-element.js | 9 ++- .../lib/rules/no-head-import-in-document.js | 8 +- .../lib/rules/no-html-link-for-pages.js | 11 ++- .../lib/rules/no-img-element.js | 8 +- .../lib/rules/no-page-custom-font.js | 14 ++-- .../lib/rules/no-script-component-in-head.js | 10 ++- .../lib/rules/no-script-in-document.js | 8 +- .../lib/rules/no-server-import-in-page.js | 8 +- .../lib/rules/no-sync-scripts.js | 61 ++++++++------- .../lib/rules/no-title-in-document-head.js | 10 ++- .../eslint-plugin-next/lib/rules/no-typos.js | 2 +- .../lib/rules/no-unwanted-polyfillio.js | 11 +-- 42 files changed, 314 insertions(+), 217 deletions(-) rename errors/{no-script-component-in-head-component.md => no-script-component-in-head.md} (75%) rename errors/{no-script-in-document-page.md => no-script-in-document.md} (54%) diff --git a/docs/basic-features/eslint.md b/docs/basic-features/eslint.md index fd342db4c80f..ad2e0d40d85e 100644 --- a/docs/basic-features/eslint.md +++ b/docs/basic-features/eslint.md @@ -80,27 +80,31 @@ This will take precedence over the configuration from `next.config.js`. Next.js provides an ESLint plugin, [`eslint-plugin-next`](https://www.npmjs.com/package/@next/eslint-plugin-next), already bundled within the base configuration that makes it possible to catch common issues and problems in a Next.js application. The full set of rules is as follows: -| | Rule | Description | -| :-: | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| ✔️ | [next/google-font-display](https://nextjs.org/docs/messages/google-font-display) | Enforce optional or swap font-display behavior with Google Fonts | -| ✔️ | [next/google-font-preconnect](https://nextjs.org/docs/messages/google-font-preconnect) | Enforce preconnect usage with Google Fonts | -| ✔️ | [next/link-passhref](https://nextjs.org/docs/messages/link-passhref) | Enforce passHref prop usage with custom Link components | -| ✔️ | [next/no-css-tags](https://nextjs.org/docs/messages/no-css-tags) | Prevent manual stylesheet tags | -| ✔️ | [next/no-document-import-in-page](https://nextjs.org/docs/messages/no-document-import-in-page) | Disallow importing next/document outside of pages/document.js | -| ✔️ | [next/no-head-import-in-document](https://nextjs.org/docs/messages/no-head-import-in-document) | Disallow importing next/head in pages/document.js | -| ✔️ | [next/no-html-link-for-pages](https://nextjs.org/docs/messages/no-html-link-for-pages) | Prohibit HTML anchor links to pages without a Link component | -| ✔️ | [next/no-img-element](https://nextjs.org/docs/messages/no-img-element) | Prohibit usage of HTML <img> element | -| ✔️ | [next/no-head-element](https://nextjs.org/docs/messages/no-head-element) | Prohibit usage of HTML <head> element | -| ✔️ | [next/no-page-custom-font](https://nextjs.org/docs/messages/no-page-custom-font) | Prevent page-only custom fonts | -| ✔️ | [next/no-sync-scripts](https://nextjs.org/docs/messages/no-sync-scripts) | Forbid synchronous scripts | -| ✔️ | [next/no-title-in-document-head](https://nextjs.org/docs/messages/no-title-in-document-head) | Disallow using <title> with Head from next/document | -| ✔️ | [next/no-unwanted-polyfillio](https://nextjs.org/docs/messages/no-unwanted-polyfillio) | Prevent duplicate polyfills from Polyfill.io | -| ✔️ | [next/inline-script-id](https://nextjs.org/docs/messages/inline-script-id) | Enforce id attribute on next/script components with inline content | -| ✔️ | next/no-typos | Ensure no typos were made declaring [Next.js's data fetching function](https://nextjs.org/docs/basic-features/data-fetching) | -| ✔️ | [next/next-script-for-ga](https://nextjs.org/docs/messages/next-script-for-ga) | Use the Script component to defer loading of the script until necessary. | - - ✔: Enabled in the recommended configuration +| | Rule | Description | +| :-: | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | +| ✔️ | [@next/next/google-font-display](https://nextjs.org/docs/messages/google-font-display) | Enforce font-display behavior with Google Fonts. | +| ✔️ | [@next/next/google-font-preconnect](https://nextjs.org/docs/messages/google-font-preconnect) | Ensure `preconnect` is used with Google Fonts. | +| ✔️ | [@next/next/inline-script-id](https://nextjs.org/docs/messages/inline-script-id) | Enforce `id` attribute on `next/script` components with inline content. | +| ✔️ | [@next/next/link-passhref](https://nextjs.org/docs/messages/link-passhref) | Ensure `passHref` is used with custom `Link` components. | +| ✔️ | [@next/next/next-script-for-ga](https://nextjs.org/docs/messages/next-script-for-ga) | Prefer `next/script` component when using the inline script for Google Analytics. | +| ✔️ | [@next/next/no-css-tags](https://nextjs.org/docs/messages/no-css-tags) | Prevent manual stylesheet tags. | +| ✔️ | [@next/next/no-document-import-in-page](https://nextjs.org/docs/messages/no-document-import-in-page) | Prevent importing `next/document` outside of `pages/_document.js`. | +| ✔️ | [@next/next/no-duplicate-head](https://nextjs.org/docs/messages/no-duplicate-head) | Prevent duplicate usage of `` in `pages/_document.js`. | +| ✔️ | [@next/next/no-head-element](https://nextjs.org/docs/messages/no-head-element) | Prevent usage of `` element. | +| ✔️ | [@next/next/no-head-import-in-document](https://nextjs.org/docs/messages/no-head-import-in-document) | Prevent usage of `next/head` in `pages/_document.js`. | +| ✔️ | [@next/next/no-html-link-for-pages](https://nextjs.org/docs/messages/no-html-link-for-pages) | Prevent usage of `` elements to navigate to Next.js pages. | +| ✔️ | [@next/next/no-img-element](https://nextjs.org/docs/messages/no-img-element) | Prevent usage of `` element. | +| ✔️ | [@next/next/no-page-custom-font](https://nextjs.org/docs/messages/no-page-custom-font) | Prevent page-only custom fonts. | +| ✔️ | [@next/next/no-script-in-document](https://nextjs.org/docs/messages/no-script-in-document) | Prevent usage of `next/script` in `pages/_document.js`. | +| ✔️ | [@next/next/no-script-component-in-head](https://nextjs.org/docs/messages/no-script-component-in-head) | Prevent usage of `next/script` in `next/head` component. | +| ✔️ | [@next/next/no-server-import-in-page](https://nextjs.org/docs/messages/no-server-import-in-page) | Prevent usage of `next/server` outside of `pages/_middleware.js`. | +| ✔️ | [@next/next/no-sync-scripts](https://nextjs.org/docs/messages/no-sync-scripts) | Prevent synchronous scripts. | +| ✔️ | [@next/next/no-title-in-document-head](https://nextjs.org/docs/messages/no-title-in-document-head) | Prevent usage of `` with `Head` component from `next/document`. | +| ✔️ | @next/next/no-typos | Prevent common typos in [Next.js's data fetching functions](https://nextjs.org/docs/basic-features/data-fetching) | +| ✔️ | [@next/next/no-unwanted-polyfillio](https://nextjs.org/docs/messages/no-unwanted-polyfillio) | Prevent duplicate polyfills from Polyfill.io. | + If you already have ESLint configured in your application, we recommend extending from this plugin directly instead of including `eslint-config-next` unless a few conditions are met. Refer to the [Recommended Plugin Ruleset](/docs/basic-features/eslint.md#recommended-plugin-ruleset) to learn more. ### Custom Settings diff --git a/errors/google-font-display.md b/errors/google-font-display.md index 61328e897628..39f880a972f4 100644 --- a/errors/google-font-display.md +++ b/errors/google-font-display.md @@ -1,8 +1,10 @@ # Google Font Display +> Enforce font-display behavior with Google Fonts. + ### Why This Error Occurred -For a Google Font, the `display` descriptor was either not assigned or set to `auto`, `fallback`, or `block`. +For a Google Font, the font-display descriptor was either missing or set to `auto`, `block`, or `fallback`, which are not recommended. ### Possible Ways to Fix It @@ -29,8 +31,9 @@ Specifying `display=optional` minimizes the risk of invisible text or layout shi ### When Not To Use It -If you want to specifically display a font using a `block` or `fallback` strategy, then you can disable this rule. +If you want to specifically display a font using a `auto, `block`, or `fallback` strategy, then you can disable this rule. ### Useful Links -- [Font-display](https://font-display.glitch.me/) +- [Controlling Font Performance with font-display](https://developers.google.com/web/updates/2016/02/font-display) +- [Font-display: a small explainer on web fonts and performance](https://font-display.glitch.me/) diff --git a/errors/google-font-preconnect.md b/errors/google-font-preconnect.md index d95d72dba9bd..1731f22322f0 100644 --- a/errors/google-font-preconnect.md +++ b/errors/google-font-preconnect.md @@ -1,5 +1,7 @@ # Google Font Preconnect +> Ensure `preconnect` is used with Google Fonts. + ### Why This Error Occurred A preconnect resource hint was not used with a request to the Google Fonts domain. Adding `preconnect` is recommended to initiate an early connection to the origin. diff --git a/errors/inline-script-id.md b/errors/inline-script-id.md index fe7f1250be73..a6cbd6301f86 100644 --- a/errors/inline-script-id.md +++ b/errors/inline-script-id.md @@ -1,4 +1,6 @@ -# next/script components with inline content require an `id` attribute +# Inline script id + +> Enforce `id` attribute on `next/script` components with inline content. ## Why This Error Occurred diff --git a/errors/link-passhref.md b/errors/link-passhref.md index 33fec658066e..e22a15b71869 100644 --- a/errors/link-passhref.md +++ b/errors/link-passhref.md @@ -1,4 +1,6 @@ -# Link passHref +# Link `passHref` + +> Ensure `passHref` is used with custom `Link` components. ### Why This Error Occurred diff --git a/errors/manifest.json b/errors/manifest.json index a7e0bc694424..4a354c33a0f8 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -549,12 +549,12 @@ "path": "/errors/sharp-version-avif.md" }, { - "title": "script-in-document-page", - "path": "/errors/no-script-in-document-page.md" + "title": "no-script-in-document", + "path": "/errors/no-script-in-document.md" }, { - "title": "script-component-in-head-component", - "path": "/errors/no-script-component-in-head-component.md" + "title": "script-component-in-head", + "path": "/errors/no-script-component-in-head.md" }, { "title": "script-tags-in-head-component", diff --git a/errors/next-script-for-ga.md b/errors/next-script-for-ga.md index 0785fcca1770..4d2eca881983 100644 --- a/errors/next-script-for-ga.md +++ b/errors/next-script-for-ga.md @@ -1,5 +1,7 @@ # Next Script for Google Analytics +> Prefer `next/script` component when using the inline script for Google Analytics. + ### Why This Error Occurred An inline script was used for Google analytics which might impact your webpage's performance. diff --git a/errors/no-css-tags.md b/errors/no-css-tags.md index 8a3e5540402c..cb1664205983 100644 --- a/errors/no-css-tags.md +++ b/errors/no-css-tags.md @@ -1,8 +1,8 @@ -# No CSS Tags +> Prevent manual stylesheet tags. ### Why This Error Occurred -An HTML link element was used to link to an external stylesheet. This can negatively affect CSS resource loading on your web page. +A `link` element was used to link to an external stylesheet. This can negatively affect CSS resource loading on your webpage. ### Possible Ways to Fix It diff --git a/errors/no-document-import-in-page.md b/errors/no-document-import-in-page.md index 8abbf7ceb3d0..bb2713856f9a 100644 --- a/errors/no-document-import-in-page.md +++ b/errors/no-document-import-in-page.md @@ -1,5 +1,7 @@ # No Document Import in Page +> Prevent importing `next/document` outside of `pages/_document.js`. + ### Why This Error Occurred `next/document` was imported in a page outside of `pages/_document.js` (or `pages/_document.tsx` if you are using TypeScript). This can cause unexpected issues in your application. diff --git a/errors/no-duplicate-head.md b/errors/no-duplicate-head.md index ed16c4f102b0..4ba4314f1845 100644 --- a/errors/no-duplicate-head.md +++ b/errors/no-duplicate-head.md @@ -1,5 +1,7 @@ # No Duplicate Head +> Prevent duplicate usage of `<Head>` in `pages/_document.js`. + ### Why This Error Occurred More than a single instance of the `<Head />` component was used in a single custom document. This can cause unexpected behavior in your application. diff --git a/errors/no-head-element.md b/errors/no-head-element.md index 670894e64a44..f3bd5ca34927 100644 --- a/errors/no-head-element.md +++ b/errors/no-head-element.md @@ -1,8 +1,10 @@ # No Head Element +> Prevent usage of `<head>` element. + ### Why This Error Occurred -An HTML `<head>` element was used to include page-level metadata, but this can cause unexpected behavior in a Next.js application. Use Next.js' built-in `<Head />` component instead. +A `<head>` element was used to include page-level metadata, but this can cause unexpected behavior in a Next.js application. Use Next.js' built-in `next/head` component instead. ### Possible Ways to Fix It diff --git a/errors/no-head-import-in-document.md b/errors/no-head-import-in-document.md index 9336cff2c8ec..e2ef1c8dae95 100644 --- a/errors/no-head-import-in-document.md +++ b/errors/no-head-import-in-document.md @@ -1,5 +1,11 @@ # No Head Import in Document +> Prevent usage of `next/head` in `pages/_document.js`. + +### Why This Error Occurred + +`next/head` should not be imported in `pages/_document.js`. This can cause unexpected issues in your application.# No Head Import in Document + ### Why This Error Occurred `next/head` was imported in `pages/_document.js`. This can cause unexpected issues in your application. diff --git a/errors/no-html-link-for-pages.md b/errors/no-html-link-for-pages.md index 38457ae4a46a..28162132bc65 100644 --- a/errors/no-html-link-for-pages.md +++ b/errors/no-html-link-for-pages.md @@ -1,8 +1,10 @@ # No HTML link for pages +> Prevent usage of `<a>` elements to navigate to Next.js pages. + ### Why This Error Occurred -An HTML anchor element, `<a>`, was used to navigate to a page route without using the `Link` component. +An `<a>` element was used to navigate to a page route without using the `next/link` component, causing unnecessary full page refreshes. The `Link` component is required in order to enable client-side route transitions between pages and provide a single-page app experience. diff --git a/errors/no-img-element.md b/errors/no-img-element.md index 532dac586cb2..1c1eee89573f 100644 --- a/errors/no-img-element.md +++ b/errors/no-img-element.md @@ -1,8 +1,10 @@ # No Img Element +> Prevent usage of `<img>` element. + ### Why This Error Occurred -An HTML `<img>` element was used to display an image. For better performance and automatic Image Optimization, use Next.js' built-in image component instead. +An `<img>` element was used to display an image. For better performance and automatic Image Optimization, use `next/image` instead. ### Possible Ways to Fix It diff --git a/errors/no-page-custom-font.md b/errors/no-page-custom-font.md index edcea71d99b3..2f2e51e3d28e 100644 --- a/errors/no-page-custom-font.md +++ b/errors/no-page-custom-font.md @@ -1,9 +1,11 @@ # No Page Custom Font +> Prevent page-only custom fonts. + ### Why This Error Occurred - The custom font you're adding was added to a page - this only adds the font to the specific page and not the entire application. -- The custom font you're adding was added to a separate component within `Document` - this disables automatic font optimization. +- The custom font you're adding was added to a separate component within `pages/_document.js` - this disables automatic font optimization. ### Possible Ways to Fix It diff --git a/errors/no-script-component-in-head-component.md b/errors/no-script-component-in-head.md similarity index 75% rename from errors/no-script-component-in-head-component.md rename to errors/no-script-component-in-head.md index c070deb14ec6..50503ebe0eae 100644 --- a/errors/no-script-component-in-head-component.md +++ b/errors/no-script-component-in-head.md @@ -1,12 +1,14 @@ -# Script component inside Head component +# No Script Component in Head + +> Prevent usage of `next/script` in `next/head` component. #### Why This Error Occurred -The `next/script` component shouldn't be placed inside the `next/head` component +The `next/script` component should not be used in a `next/head` component. #### Possible Ways to Fix It -Move the `<Script />` component outside of `<Head>...</Head>` +Move the `<Script />` component outside of `<Head>` instead. **Before** diff --git a/errors/no-script-in-document-page.md b/errors/no-script-in-document.md similarity index 54% rename from errors/no-script-in-document-page.md rename to errors/no-script-in-document.md index 201d01d32e24..ae9155e72764 100644 --- a/errors/no-script-in-document-page.md +++ b/errors/no-script-in-document.md @@ -1,12 +1,14 @@ -# Script component inside \_document.js +# No Script in Document + +> Prevent usage of `next/script` in `pages/_document.js`. #### Why This Error Occurred -You can't use the `next/script` component inside the `_document.js` page. That's because the `_document.js` page only runs on the server and `next/script` has client-side functionality to ensure loading order. +You should not use the `next/script` component in `pages/_document.js`. That's because the `pages/_document.js` page only runs on the server and `next/script` has client-side functionality to ensure loading order. #### Possible Ways to Fix It -If you want a global script, instead use the `_app.js` page. +If you want a global script, `pages/_app.js` instead. ```jsx import Script from 'next/script' diff --git a/errors/no-server-import-in-page.md b/errors/no-server-import-in-page.md index c8fc45069a28..f9a9432d8666 100644 --- a/errors/no-server-import-in-page.md +++ b/errors/no-server-import-in-page.md @@ -1,5 +1,7 @@ # No Server Import In Page +> Prevent usage of `next/server` outside of `pages/_middleware.js`. + ### Why This Error Occurred `next/server` was imported outside of `pages/**/_middleware.{js,ts}`. diff --git a/errors/no-sync-scripts.md b/errors/no-sync-scripts.md index b8a200e8b58d..110e24564baf 100644 --- a/errors/no-sync-scripts.md +++ b/errors/no-sync-scripts.md @@ -1,14 +1,14 @@ # No Sync Scripts +> Prevent synchronous scripts. + ### Why This Error Occurred -A synchronous script was used which can impact your webpage's performance. +A synchronous script was used which can impact your webpage performance. ### Possible Ways to Fix It -#### Script component (experimental) - -Use the Script component with the right loading strategy to defer loading of the script until necessary. +#### Script component (recommended) ```jsx import Script from 'next/script' @@ -25,6 +25,13 @@ function Home() { export default Home ``` +#### Use `async` or `defer` + +```html +<script src="https://third-party-script.js" async></script> +<script src="https://third-party-script.js" defer></script> +``` + ### Useful Links - [Efficiently load third-party JavaScript](https://web.dev/efficiently-load-third-party-javascript/) diff --git a/errors/no-title-in-document-head.md b/errors/no-title-in-document-head.md index 771e99674d5c..3f450d18862e 100644 --- a/errors/no-title-in-document-head.md +++ b/errors/no-title-in-document-head.md @@ -1,8 +1,10 @@ # No Title in Document Head +> Prevent usage of `<title>` with `Head` component from `next/document`. + ### Why This Error Occurred -A `<title>` element was defined within the `Head` component imported from `next/document`, which should only be used for any `<head>` code that is common for all pages. Title tags should be defined at the page-level using `next/head`. +A `<title>` element was defined within the `Head` component imported from `next/document`, which should only be used for any `<head>` code that is common for all pages. Title tags should be defined at the page-level using `next/head` instead. ### Possible Ways to Fix It diff --git a/errors/no-unwanted-polyfillio.md b/errors/no-unwanted-polyfillio.md index 6f05aa9a7251..9d00cbc8579f 100644 --- a/errors/no-unwanted-polyfillio.md +++ b/errors/no-unwanted-polyfillio.md @@ -1,12 +1,14 @@ -# Duplicate Polyfills from Polyfill.io +# No Unwanted Polyfill.io + +> Prevent duplicate polyfills from Polyfill.io. #### Why This Error Occurred -You are using Polyfill.io and including duplicate polyfills already shipped with Next.js. This increases page weight unnecessarily which can affect loading performance. +You are using polyfills from Polyfill.io and including polyfills already shipped with Next.js. This unnecessarily increases page weight which can affect loading performance. #### Possible Ways to Fix It -Remove all duplicate polyfills that are included with Polyfill.io. If you need to add polyfills but are not sure if Next.js already includes it, take a look at the list of [supported browsers and features](https://nextjs.org/docs/basic-features/supported-browsers-features) first. +Remove all duplicate polyfills. If you need to add polyfills but are not sure if Next.js already includes it, take a look at the list of [supported browsers and features](https://nextjs.org/docs/basic-features/supported-browsers-features). ### Useful Links diff --git a/packages/eslint-plugin-next/lib/index.js b/packages/eslint-plugin-next/lib/index.js index 295978b671b6..a724461cde2c 100644 --- a/packages/eslint-plugin-next/lib/index.js +++ b/packages/eslint-plugin-next/lib/index.js @@ -1,58 +1,60 @@ module.exports = { rules: { - 'no-css-tags': require('./rules/no-css-tags'), - 'no-sync-scripts': require('./rules/no-sync-scripts'), - 'no-html-link-for-pages': require('./rules/no-html-link-for-pages'), - 'no-img-element': require('./rules/no-img-element'), - 'no-head-element': require('./rules/no-head-element'), - 'no-unwanted-polyfillio': require('./rules/no-unwanted-polyfillio'), - 'no-page-custom-font': require('./rules/no-page-custom-font'), - 'no-title-in-document-head': require('./rules/no-title-in-document-head'), 'google-font-display': require('./rules/google-font-display'), 'google-font-preconnect': require('./rules/google-font-preconnect'), + 'inline-script-id': require('./rules/inline-script-id'), 'link-passhref': require('./rules/link-passhref'), + 'next-script-for-ga': require('./rules/next-script-for-ga'), + 'no-css-tags': require('./rules/no-css-tags'), 'no-document-import-in-page': require('./rules/no-document-import-in-page'), + 'no-duplicate-head': require('./rules/no-duplicate-head'), + 'no-head-element': require('./rules/no-head-element'), 'no-head-import-in-document': require('./rules/no-head-import-in-document'), - 'no-script-in-document': require('./rules/no-script-in-document'), + 'no-html-link-for-pages': require('./rules/no-html-link-for-pages'), + 'no-img-element': require('./rules/no-img-element'), + 'no-page-custom-font': require('./rules/no-page-custom-font'), 'no-script-component-in-head': require('./rules/no-script-component-in-head'), + 'no-script-in-document': require('./rules/no-script-in-document'), 'no-server-import-in-page': require('./rules/no-server-import-in-page'), + 'no-sync-scripts': require('./rules/no-sync-scripts'), + 'no-title-in-document-head': require('./rules/no-title-in-document-head'), 'no-typos': require('./rules/no-typos'), - 'no-duplicate-head': require('./rules/no-duplicate-head'), - 'inline-script-id': require('./rules/inline-script-id'), - 'next-script-for-ga': require('./rules/next-script-for-ga'), + 'no-unwanted-polyfillio': require('./rules/no-unwanted-polyfillio'), }, configs: { recommended: { plugins: ['@next/next'], rules: { - '@next/next/no-css-tags': 1, - '@next/next/no-sync-scripts': 1, - '@next/next/no-html-link-for-pages': 1, - '@next/next/no-img-element': 1, - '@next/next/no-head-element': 1, - '@next/next/no-unwanted-polyfillio': 1, - '@next/next/no-page-custom-font': 1, - '@next/next/no-title-in-document-head': 1, - '@next/next/google-font-display': 1, - '@next/next/google-font-preconnect': 1, - '@next/next/link-passhref': 1, - '@next/next/next-script-for-ga': 1, - '@next/next/no-document-import-in-page': 2, - '@next/next/no-head-import-in-document': 2, - '@next/next/no-script-in-document': 2, - '@next/next/no-script-component-in-head': 2, - '@next/next/no-server-import-in-page': 2, - '@next/next/no-typos': 1, - '@next/next/no-duplicate-head': 2, - '@next/next/inline-script-id': 2, + // Errors + '@next/next/google-font-display': 'error', + '@next/next/google-font-preconnect': 'error', + '@next/next/link-passhref': 'error', + '@next/next/next-script-for-ga': 'error', + '@next/next/no-css-tags': 'error', + '@next/next/no-head-element': 'error', + '@next/next/no-html-link-for-pages': 'error', + '@next/next/no-img-element': 'error', + '@next/next/no-page-custom-font': 'error', + '@next/next/no-sync-scripts': 'error', + '@next/next/no-title-in-document-head': 'error', + '@next/next/no-typos': 'error', + '@next/next/no-unwanted-polyfillio': 'error', + // Warnings + '@next/next/inline-script-id': 'warn', + '@next/next/no-document-import-in-page': 'warn', + '@next/next/no-duplicate-head': 'warn', + '@next/next/no-head-import-in-document': 'warn', + '@next/next/no-server-import-in-page': 'warn', + '@next/next/no-script-component-in-head': 'warn', + '@next/next/no-script-in-document': 'warn', }, }, 'core-web-vitals': { plugins: ['@next/next'], extends: ['plugin:@next/next/recommended'], rules: { - '@next/next/no-sync-scripts': 2, - '@next/next/no-html-link-for-pages': 2, + '@next/next/no-html-link-for-pages': 'warn', + '@next/next/no-sync-scripts': 'warn', }, }, }, diff --git a/packages/eslint-plugin-next/lib/rules/google-font-display.js b/packages/eslint-plugin-next/lib/rules/google-font-display.js index 7a0995eb7a6f..a1ca8a9a7a95 100644 --- a/packages/eslint-plugin-next/lib/rules/google-font-display.js +++ b/packages/eslint-plugin-next/lib/rules/google-font-display.js @@ -1,12 +1,13 @@ const NodeAttributes = require('../utils/node-attributes.js') +const url = 'https://nextjs.org/docs/messages/google-font-display' + module.exports = { meta: { docs: { - description: - 'Ensure correct font-display property is assigned for Google Fonts', + description: 'Enforce font-display behavior with Google Fonts.', recommended: true, - url: 'https://nextjs.org/docs/messages/google-font-display', + url, }, }, create: function (context) { @@ -33,22 +34,23 @@ module.exports = { const displayValue = params.get('display') if (!params.has('display')) { - message = 'Display parameter is missing.' + message = + 'A font-display parameter is missing (adding `&display=optional` is recommended).' } else if ( + displayValue === 'auto' || displayValue === 'block' || - displayValue === 'fallback' || - displayValue === 'auto' + displayValue === 'fallback' ) { message = `${ displayValue[0].toUpperCase() + displayValue.slice(1) - } behavior is not recommended.` + } is not recommended.` } } if (message) { context.report({ node, - message: `${message} See: https://nextjs.org/docs/messages/google-font-display`, + message: `${message} See: ${url}`, }) } }, diff --git a/packages/eslint-plugin-next/lib/rules/google-font-preconnect.js b/packages/eslint-plugin-next/lib/rules/google-font-preconnect.js index a217618905a5..cbc1a65ac682 100644 --- a/packages/eslint-plugin-next/lib/rules/google-font-preconnect.js +++ b/packages/eslint-plugin-next/lib/rules/google-font-preconnect.js @@ -1,11 +1,13 @@ const NodeAttributes = require('../utils/node-attributes.js') +const url = 'https://nextjs.org/docs/messages/google-font-preconnect' + module.exports = { meta: { docs: { - description: 'Ensure preconnect is used with Google Fonts', + description: 'Ensure `preconnect` is used with Google Fonts.', recommended: true, - url: 'https://nextjs.org/docs/messages/google-font-preconnect', + url, }, }, create: function (context) { @@ -33,7 +35,7 @@ module.exports = { ) { context.report({ node, - message: `Preconnect is missing. See: https://nextjs.org/docs/messages/google-font-preconnect`, + message: `\`rel="preconnect"\` is missing from Google Font. See: ${url}`, }) } }, diff --git a/packages/eslint-plugin-next/lib/rules/inline-script-id.js b/packages/eslint-plugin-next/lib/rules/inline-script-id.js index 20322f913c22..8c63eea45caa 100644 --- a/packages/eslint-plugin-next/lib/rules/inline-script-id.js +++ b/packages/eslint-plugin-next/lib/rules/inline-script-id.js @@ -1,10 +1,12 @@ +const url = 'https://nextjs.org/docs/messages/inline-script-id' + module.exports = { meta: { docs: { description: - 'next/script components with inline content must specify an `id` attribute.', + 'Enforce `id` attribute on `next/script` components with inline content.', recommended: true, - url: 'https://nextjs.org/docs/messages/inline-script-id', + url, }, }, create: function (context) { @@ -45,8 +47,7 @@ module.exports = { if (!attributeNames.has('id')) { context.report({ node, - message: - 'next/script components with inline content must specify an `id` attribute. See: https://nextjs.org/docs/messages/inline-script-id', + message: `\`next/script\` components with inline content must specify an \`id\` attribute. See: ${url}`, }) } } diff --git a/packages/eslint-plugin-next/lib/rules/link-passhref.js b/packages/eslint-plugin-next/lib/rules/link-passhref.js index 97c13029aff9..5c6d09768c37 100644 --- a/packages/eslint-plugin-next/lib/rules/link-passhref.js +++ b/packages/eslint-plugin-next/lib/rules/link-passhref.js @@ -1,13 +1,14 @@ const NodeAttributes = require('../utils/node-attributes.js') +const url = 'https://nextjs.org/docs/messages/link-passhref' + module.exports = { meta: { docs: { - description: - 'Ensure passHref is assigned if child of Link component is a custom component', + description: 'Ensure `passHref` is used with custom `Link` components.', category: 'HTML', recommended: true, - url: 'https://nextjs.org/docs/messages/link-passhref', + url, }, fixable: null, }, @@ -51,11 +52,11 @@ module.exports = { if (!hasAnchorChild && !hasPassHref) { context.report({ node, - message: `passHref ${ + message: `\`passHref\` ${ attributes.value('passHref') !== true - ? 'must be set to true' + ? 'must be set to `true`' : 'is missing' - }. See: https://nextjs.org/docs/messages/link-passhref`, + }. See: ${url}`, }) } }, diff --git a/packages/eslint-plugin-next/lib/rules/next-script-for-ga.js b/packages/eslint-plugin-next/lib/rules/next-script-for-ga.js index 6d934d3c567c..260ab65c17d8 100644 --- a/packages/eslint-plugin-next/lib/rules/next-script-for-ga.js +++ b/packages/eslint-plugin-next/lib/rules/next-script-for-ga.js @@ -8,8 +8,10 @@ const SUPPORTED_HTML_CONTENT_URLS = [ 'www.google-analytics.com/analytics.js', 'www.googletagmanager.com/gtm.js', ] -const ERROR_MSG = - 'Use the `next/script` component for loading third party scripts. See: https://nextjs.org/docs/messages/next-script-for-ga' +const description = + 'Prefer `next/script` component when using the inline script for Google Analytics.' +const url = 'https://nextjs.org/docs/messages/next-script-for-ga' +const ERROR_MSG = `${description} See: ${url}` // Check if one of the items in the list is a substring of the passed string const containsStr = (str, strList) => { @@ -19,12 +21,12 @@ const containsStr = (str, strList) => { module.exports = { meta: { docs: { - description: - 'Prefer next script component when using the inline script for Google Analytics', + description, recommended: true, - url: 'https://nextjs.org/docs/messages/next-script-for-ga', + url, }, }, + schema: [], create: function (context) { return { JSXOpeningElement(node) { @@ -74,5 +76,3 @@ module.exports = { } }, } - -module.exports.schema = [] diff --git a/packages/eslint-plugin-next/lib/rules/no-css-tags.js b/packages/eslint-plugin-next/lib/rules/no-css-tags.js index e361ab137d0d..765555853019 100644 --- a/packages/eslint-plugin-next/lib/rules/no-css-tags.js +++ b/packages/eslint-plugin-next/lib/rules/no-css-tags.js @@ -1,36 +1,45 @@ -module.exports = function (context) { - return { - JSXOpeningElement(node) { - if (node.name.name !== 'link') { - return - } - if (node.attributes.length === 0) { - return - } +const url = 'https://nextjs.org/docs/messages/no-css-tags' - const attributes = node.attributes.filter( - (attr) => attr.type === 'JSXAttribute' - ) - if ( - attributes.find( - (attr) => - attr.name.name === 'rel' && attr.value.value === 'stylesheet' - ) && - attributes.find( - (attr) => - attr.name.name === 'href' && - attr.value.type === 'Literal' && - !/^https?/.test(attr.value.value) - ) - ) { - context.report({ - node, - message: - 'Do not include stylesheets manually. See: https://nextjs.org/docs/messages/no-css-tags', - }) - } +module.exports = { + meta: { + docs: { + description: 'Prevent manual stylesheet tags.', + recommended: true, + url, }, - } -} + }, + schema: [], + create: function (context) { + return { + JSXOpeningElement(node) { + if (node.name.name !== 'link') { + return + } + if (node.attributes.length === 0) { + return + } -module.exports.schema = [] + const attributes = node.attributes.filter( + (attr) => attr.type === 'JSXAttribute' + ) + if ( + attributes.find( + (attr) => + attr.name.name === 'rel' && attr.value.value === 'stylesheet' + ) && + attributes.find( + (attr) => + attr.name.name === 'href' && + attr.value.type === 'Literal' && + !/^https?/.test(attr.value.value) + ) + ) { + context.report({ + node, + message: `Do not include stylesheets manually. See: ${url}`, + }) + } + }, + } + }, +} diff --git a/packages/eslint-plugin-next/lib/rules/no-document-import-in-page.js b/packages/eslint-plugin-next/lib/rules/no-document-import-in-page.js index 1b7fbeb8f051..76b46ed9dc1a 100644 --- a/packages/eslint-plugin-next/lib/rules/no-document-import-in-page.js +++ b/packages/eslint-plugin-next/lib/rules/no-document-import-in-page.js @@ -1,12 +1,14 @@ const path = require('path') +const url = 'https://nextjs.org/docs/messages/no-document-import-in-page' + module.exports = { meta: { docs: { description: - 'Disallow importing next/document outside of pages/document.js', + 'Prevent importing `next/document` outside of `pages/_document.js`.', recommended: true, - url: 'https://nextjs.org/docs/messages/no-document-import-in-page', + url, }, }, create: function (context) { @@ -29,7 +31,7 @@ module.exports = { context.report({ node, - message: `next/document should not be imported outside of pages/_document.js. See: https://nextjs.org/docs/messages/no-document-import-in-page`, + message: `\`<Document />\` from \`next/document\` should not be imported outside of \`pages/_document.js\`. See: ${url}`, }) }, } diff --git a/packages/eslint-plugin-next/lib/rules/no-duplicate-head.js b/packages/eslint-plugin-next/lib/rules/no-duplicate-head.js index cc15c27c83bb..a8b052141129 100644 --- a/packages/eslint-plugin-next/lib/rules/no-duplicate-head.js +++ b/packages/eslint-plugin-next/lib/rules/no-duplicate-head.js @@ -1,9 +1,12 @@ +const url = 'https://nextjs.org/docs/messages/no-duplicate-head' + module.exports = { meta: { docs: { - description: 'Enforce no duplicate usage of <Head> in pages/document.js', + description: + 'Prevent duplicate usage of `<Head>` in `pages/_document.js`.', recommended: true, - url: 'https://nextjs.org/docs/messages/no-duplicate-head', + url, }, }, create: function (context) { @@ -44,8 +47,7 @@ module.exports = { for (let i = 1; i < headComponents.length; i++) { context.report({ node: headComponents[i], - message: - 'Do not include multiple instances of <Head/>. See: https://nextjs.org/docs/messages/no-duplicate-head', + message: `Do not include multiple instances of \`<Head/>\`. See: ${url}`, }) } } diff --git a/packages/eslint-plugin-next/lib/rules/no-head-element.js b/packages/eslint-plugin-next/lib/rules/no-head-element.js index ae8def43c593..045e21a31131 100644 --- a/packages/eslint-plugin-next/lib/rules/no-head-element.js +++ b/packages/eslint-plugin-next/lib/rules/no-head-element.js @@ -1,14 +1,15 @@ +const url = 'https://nextjs.org/docs/messages/no-head-element' + module.exports = { meta: { docs: { - description: 'Prohibit usage of HTML <head> element', + description: 'Prevent usage of `<head>` element.', category: 'HTML', recommended: true, - url: 'https://nextjs.org/docs/messages/no-head-element', + url, }, fixable: 'code', }, - create: function (context) { return { JSXOpeningElement(node) { @@ -18,7 +19,7 @@ module.exports = { context.report({ node, - message: `Do not use <head>. Use Head from 'next/head' instead. See: https://nextjs.org/docs/messages/no-head-element`, + message: `Do not use \`<head>\` element. Use \`<Head />\` from \`next/head\` instead. See: ${url}`, }) }, } diff --git a/packages/eslint-plugin-next/lib/rules/no-head-import-in-document.js b/packages/eslint-plugin-next/lib/rules/no-head-import-in-document.js index e65deb425dc1..b5f00f036604 100644 --- a/packages/eslint-plugin-next/lib/rules/no-head-import-in-document.js +++ b/packages/eslint-plugin-next/lib/rules/no-head-import-in-document.js @@ -1,11 +1,13 @@ const path = require('path') +const url = 'https://nextjs.org/docs/messages/no-head-import-in-document' + module.exports = { meta: { docs: { - description: 'Disallow importing next/head in pages/document.js', + description: 'Prevent usage of `next/head` in `pages/_document.js`.', recommended: true, - url: 'https://nextjs.org/docs/messages/no-head-import-in-document', + url, }, }, create: function (context) { @@ -28,7 +30,7 @@ module.exports = { ) { context.report({ node, - message: `next/head should not be imported in pages${document}. Import Head from next/document instead. See: https://nextjs.org/docs/messages/no-head-import-in-document`, + message: `\`next/head\` should not be imported in \`pages/_document.js\`. Use \`<Head />\` from \`next/document\` instead. See: ${url}`, }) } }, diff --git a/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js b/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js index c26f72e851a0..fc631f018ef1 100644 --- a/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js +++ b/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js @@ -11,7 +11,7 @@ const { const pagesDirWarning = execOnce((pagesDirs) => { console.warn( `Pages directory cannot be found at ${pagesDirs.join(' or ')}. ` + - `If using a custom path, please configure with the no-html-link-for-pages rule in your eslint config file` + 'If using a custom path, please configure with the `no-html-link-for-pages` rule in your eslint config file.' ) }) @@ -19,13 +19,16 @@ const pagesDirWarning = execOnce((pagesDirs) => { // Prevent multiple blocking IO requests that have already been calculated. const fsExistsSyncCache = {} +const url = 'https://nextjs.org/docs/messages/no-html-link-for-pages' + module.exports = { meta: { docs: { - description: 'Prohibit full page refresh for Next.js pages', + description: + 'Prevent usage of `<a>` elements to navigate to Next.js pages.', category: 'HTML', recommended: true, - url: 'https://nextjs.org/docs/messages/no-html-link-for-pages', + url, }, fixable: null, // or "code" or "whitespace" schema: [ @@ -125,7 +128,7 @@ module.exports = { if (url.test(normalizeURL(hrefPath))) { context.report({ node, - message: `Do not use the HTML <a> tag to navigate to ${hrefPath}. Use Link from 'next/link' instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages`, + message: `Do not use an \`<a>\` element to navigate to \`${hrefPath}\`. Use \`<Link />\` from \`next/link\` instead. See: ${url}`, }) } }) diff --git a/packages/eslint-plugin-next/lib/rules/no-img-element.js b/packages/eslint-plugin-next/lib/rules/no-img-element.js index 8f015e59283a..d6eb7b4fc42b 100644 --- a/packages/eslint-plugin-next/lib/rules/no-img-element.js +++ b/packages/eslint-plugin-next/lib/rules/no-img-element.js @@ -1,10 +1,12 @@ +const url = 'https://nextjs.org/docs/messages/no-img-element' + module.exports = { meta: { docs: { - description: 'Prohibit usage of HTML <img> element', + description: 'Prevent usage of `<img>` element.', category: 'HTML', recommended: true, - url: 'https://nextjs.org/docs/messages/no-img-element', + url, }, fixable: 'code', }, @@ -22,7 +24,7 @@ module.exports = { context.report({ node, - message: `Do not use <img>. Use Image from 'next/image' instead. See: https://nextjs.org/docs/messages/no-img-element`, + message: `Do not use \`<img>\` element. Use \`<Image />\` from \`next/image\' instead. See: ${url}`, }) }, } diff --git a/packages/eslint-plugin-next/lib/rules/no-page-custom-font.js b/packages/eslint-plugin-next/lib/rules/no-page-custom-font.js index 7475bedf213b..61ecf534d8f3 100644 --- a/packages/eslint-plugin-next/lib/rules/no-page-custom-font.js +++ b/packages/eslint-plugin-next/lib/rules/no-page-custom-font.js @@ -1,13 +1,14 @@ const NodeAttributes = require('../utils/node-attributes.js') const { sep, posix } = require('path') +const url = 'https://nextjs.org/docs/messages/no-page-custom-font' + module.exports = { meta: { docs: { - description: - 'Recommend adding custom font in a custom document and not in a specific page', + description: 'Prevent page-only custom fonts.', recommended: true, - url: 'https://nextjs.org/docs/messages/no-page-custom-font', + url, }, }, create: function (context) { @@ -137,12 +138,11 @@ module.exports = { hrefValue.startsWith('https://fonts.googleapis.com/css') if (isGoogleFont) { - const end = - 'This is discouraged. See: https://nextjs.org/docs/messages/no-page-custom-font' + const end = `This is discouraged. See: ${url}` const message = is_Document - ? `Rendering this <link /> not inline within <Head> of Document disables font optimization. ${end}` - : `Custom fonts not added at the document level will only load for a single page. ${end}` + ? `Using \`<link />\` outside of \`<Head>\` will disable automatic font optimization. ${end}` + : `Custom fonts not added in \`pages/_document.js\` will only load for a single page. ${end}` context.report({ node, diff --git a/packages/eslint-plugin-next/lib/rules/no-script-component-in-head.js b/packages/eslint-plugin-next/lib/rules/no-script-component-in-head.js index 90e0fbe4bc8c..82dc94b7bff3 100644 --- a/packages/eslint-plugin-next/lib/rules/no-script-component-in-head.js +++ b/packages/eslint-plugin-next/lib/rules/no-script-component-in-head.js @@ -1,9 +1,12 @@ +const url = + 'https://nextjs.org/docs/messages/no-script-component-in-head-component' + module.exports = { meta: { docs: { - description: 'Disallow using next/script inside the next/head component', + description: 'Prevent usage of `next/script` in `next/head` component.', recommended: true, - url: 'https://nextjs.org/docs/messages/no-script-component-in-head-component', + url, }, }, create: function (context) { @@ -42,8 +45,7 @@ module.exports = { if (scriptTag) { context.report({ node, - message: - "next/script shouldn't be used inside next/head. See: https://nextjs.org/docs/messages/no-script-component-in-head-component", + message: `\`next/script\` should not be used in \`next/head\` component. Move \`<Script />\` outside of \`<Head>\` instead. See: ${url}`, }) } }, diff --git a/packages/eslint-plugin-next/lib/rules/no-script-in-document.js b/packages/eslint-plugin-next/lib/rules/no-script-in-document.js index a503975d812b..3acea7b8495f 100644 --- a/packages/eslint-plugin-next/lib/rules/no-script-in-document.js +++ b/packages/eslint-plugin-next/lib/rules/no-script-in-document.js @@ -1,11 +1,13 @@ const path = require('path') +const url = 'https://nextjs.org/docs/messages/no-script-in-document' + module.exports = { meta: { docs: { - description: 'Disallow importing next/script inside pages/_document.js', + description: 'Prevent usage of `next/script` in `pages/_document.js`.', recommended: true, - url: 'https://nextjs.org/docs/messages/no-script-in-document-page', + url, }, }, create: function (context) { @@ -22,7 +24,7 @@ module.exports = { context.report({ node, - message: `next/script should not be used in pages/_document.js. See: https://nextjs.org/docs/messages/no-script-in-document-page`, + message: `\`<Script />\` from \`next/script\` should not be used in \`pages/_document.js\`. Use in \`pages/_app.js\` instead. See: ${url}`, }) }, } diff --git a/packages/eslint-plugin-next/lib/rules/no-server-import-in-page.js b/packages/eslint-plugin-next/lib/rules/no-server-import-in-page.js index 3cec735da7d8..7f8b3d9a44ea 100644 --- a/packages/eslint-plugin-next/lib/rules/no-server-import-in-page.js +++ b/packages/eslint-plugin-next/lib/rules/no-server-import-in-page.js @@ -1,12 +1,14 @@ const path = require('path') +const url = 'https://nextjs.org/docs/messages/no-server-import-in-page' + module.exports = { meta: { docs: { description: - 'Disallow importing next/server outside of pages/_middleware.js', + 'Prevent usage of `next/server` outside of `pages/_middleware.js`.', recommended: true, - url: 'https://nextjs.org/docs/messages/no-server-import-in-page', + url, }, }, create: function (context) { @@ -29,7 +31,7 @@ module.exports = { context.report({ node, - message: `next/server should not be imported outside of pages/_middleware.js. See: https://nextjs.org/docs/messages/no-server-import-in-page`, + message: `\`next/server\` should not be used outside of \`pages/_middleware.js\`. See: ${url}`, }) }, } diff --git a/packages/eslint-plugin-next/lib/rules/no-sync-scripts.js b/packages/eslint-plugin-next/lib/rules/no-sync-scripts.js index ac3e21302895..2025750b0256 100644 --- a/packages/eslint-plugin-next/lib/rules/no-sync-scripts.js +++ b/packages/eslint-plugin-next/lib/rules/no-sync-scripts.js @@ -1,28 +1,37 @@ -module.exports = function (context) { - return { - JSXOpeningElement(node) { - if (node.name.name !== 'script') { - return - } - if (node.attributes.length === 0) { - return - } - const attributeNames = node.attributes - .filter((attr) => attr.type === 'JSXAttribute') - .map((attr) => attr.name.name) - if ( - attributeNames.includes('src') && - !attributeNames.includes('async') && - !attributeNames.includes('defer') - ) { - context.report({ - node, - message: - 'External synchronous scripts are forbidden. See: https://nextjs.org/docs/messages/no-sync-scripts', - }) - } +const url = 'https://nextjs.org/docs/messages/no-sync-scripts' + +module.exports = { + meta: { + docs: { + description: 'Prevent synchronous scripts.', + recommended: true, + url, }, - } + }, + schema: [], + create: function (context) { + return { + JSXOpeningElement(node) { + if (node.name.name !== 'script') { + return + } + if (node.attributes.length === 0) { + return + } + const attributeNames = node.attributes + .filter((attr) => attr.type === 'JSXAttribute') + .map((attr) => attr.name.name) + if ( + attributeNames.includes('src') && + !attributeNames.includes('async') && + !attributeNames.includes('defer') + ) { + context.report({ + node, + message: `Synchronous scripts should not be used. See: ${url}`, + }) + } + }, + } + }, } - -module.exports.schema = [] diff --git a/packages/eslint-plugin-next/lib/rules/no-title-in-document-head.js b/packages/eslint-plugin-next/lib/rules/no-title-in-document-head.js index 9d193362f954..f2eb7d162b50 100644 --- a/packages/eslint-plugin-next/lib/rules/no-title-in-document-head.js +++ b/packages/eslint-plugin-next/lib/rules/no-title-in-document-head.js @@ -1,8 +1,11 @@ +const url = 'https://nextjs.org/docs/messages/no-title-in-document-head' + module.exports = { meta: { docs: { - description: 'Disallow using <title> with Head from next/document', - url: 'https://nextjs.org/docs/messages/no-title-in-document-head', + description: + 'Prevent usage of `<title>` with `Head` component from `next/document`.', + url, }, }, create: function (context) { @@ -39,8 +42,7 @@ module.exports = { if (titleTag) { context.report({ node: titleTag, - message: - 'Titles should be defined at the page-level using next/head. See: https://nextjs.org/docs/messages/no-title-in-document-head', + message: `Do not use \`<title>\` element with \`<Head />\` component from \`next/document\`. Titles should defined at the page-level using \`<Head />\` from \`next/head\` instead. See: ${url}`, }) } }, diff --git a/packages/eslint-plugin-next/lib/rules/no-typos.js b/packages/eslint-plugin-next/lib/rules/no-typos.js index e517993c5704..22092912fcd5 100644 --- a/packages/eslint-plugin-next/lib/rules/no-typos.js +++ b/packages/eslint-plugin-next/lib/rules/no-typos.js @@ -42,7 +42,7 @@ function minDistance(a, b) { module.exports = { meta: { docs: { - description: 'Prevent common typos', + description: 'Prevent common typos in Next.js data fetching functions.', category: 'Stylistic Issues', recommended: true, }, diff --git a/packages/eslint-plugin-next/lib/rules/no-unwanted-polyfillio.js b/packages/eslint-plugin-next/lib/rules/no-unwanted-polyfillio.js index 891903d18977..f5751e0e2b6f 100644 --- a/packages/eslint-plugin-next/lib/rules/no-unwanted-polyfillio.js +++ b/packages/eslint-plugin-next/lib/rules/no-unwanted-polyfillio.js @@ -59,19 +59,20 @@ const NEXT_POLYFILLED_FEATURES = [ 'es7', // Should be covered by babel-preset-env instead. ] +const url = 'https://nextjs.org/docs/messages/no-unwanted-polyfillio' + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = { meta: { docs: { - description: - 'Prohibit unwanted features to be listed in Polyfill.io tag.', + description: 'Prevent duplicate polyfills from Polyfill.io.', category: 'HTML', recommended: true, - url: 'https://nextjs.org/docs/messages/no-unwanted-polyfillio', + url, }, - fixable: null, // or "code" or "whitespace" + fixable: null, }, create: function (context) { @@ -118,7 +119,7 @@ module.exports = { ', ' )} ${ unwantedFeatures.length > 1 ? 'are' : 'is' - } already shipped with Next.js. See: https://nextjs.org/docs/messages/no-unwanted-polyfillio`, + } already shipped with Next.js. See: ${url}`, }) } } From 75fb7e89be38622bdb49de6b28f7f7ab11d6b92c Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 14 Feb 2022 11:27:09 -0600 Subject: [PATCH 02/20] Fixes lint errors. --- .../eslint-plugin-next/lib/rules/no-html-link-for-pages.js | 6 +++--- packages/eslint-plugin-next/lib/rules/no-img-element.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js b/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js index fc631f018ef1..a77712779f14 100644 --- a/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js +++ b/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js @@ -82,7 +82,7 @@ module.exports = { return {} } - const urls = getUrlFromPagesDirectories('/', foundPagesDirs) + const pageUrls = getUrlFromPagesDirectories('/', foundPagesDirs) return { JSXOpeningElement(node) { if (node.name.name !== 'a') { @@ -124,8 +124,8 @@ module.exports = { return } - urls.forEach((url) => { - if (url.test(normalizeURL(hrefPath))) { + pageUrls.forEach((pageUrl) => { + if (pageUrl.test(normalizeURL(hrefPath))) { context.report({ node, message: `Do not use an \`<a>\` element to navigate to \`${hrefPath}\`. Use \`<Link />\` from \`next/link\` instead. See: ${url}`, diff --git a/packages/eslint-plugin-next/lib/rules/no-img-element.js b/packages/eslint-plugin-next/lib/rules/no-img-element.js index d6eb7b4fc42b..2f3cf148b95e 100644 --- a/packages/eslint-plugin-next/lib/rules/no-img-element.js +++ b/packages/eslint-plugin-next/lib/rules/no-img-element.js @@ -24,7 +24,7 @@ module.exports = { context.report({ node, - message: `Do not use \`<img>\` element. Use \`<Image />\` from \`next/image\' instead. See: ${url}`, + message: `Do not use \`<img>\` element. Use \`<Image />\` from \`next/image\` instead. See: ${url}`, }) }, } From 8b6305190f687e45576387763bcd4475c326b420 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 14 Feb 2022 11:29:34 -0600 Subject: [PATCH 03/20] Fixes manifest. --- errors/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/errors/manifest.json b/errors/manifest.json index 4a354c33a0f8..35381292bb95 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -553,7 +553,7 @@ "path": "/errors/no-script-in-document.md" }, { - "title": "script-component-in-head", + "title": "no-script-component-in-head", "path": "/errors/no-script-component-in-head.md" }, { From 5f5d4c781ed81af333ee9a187ca1bf99d5820126 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 14 Feb 2022 12:54:06 -0600 Subject: [PATCH 04/20] Adds missing title. --- errors/no-css-tags.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/errors/no-css-tags.md b/errors/no-css-tags.md index cb1664205983..c9926b25b81f 100644 --- a/errors/no-css-tags.md +++ b/errors/no-css-tags.md @@ -1,3 +1,5 @@ +# No CSS Tags + > Prevent manual stylesheet tags. ### Why This Error Occurred From 28815b93f31b803d36109e092e2cbabaaa754ec0 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 14 Feb 2022 12:54:41 -0600 Subject: [PATCH 05/20] Fixes copy / paste error. Co-authored-by: Lee Robinson <me@leerob.io> --- errors/no-head-import-in-document.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/errors/no-head-import-in-document.md b/errors/no-head-import-in-document.md index e2ef1c8dae95..b75f9c64ca26 100644 --- a/errors/no-head-import-in-document.md +++ b/errors/no-head-import-in-document.md @@ -4,7 +4,7 @@ ### Why This Error Occurred -`next/head` should not be imported in `pages/_document.js`. This can cause unexpected issues in your application.# No Head Import in Document +`next/head` should not be imported in `pages/_document.js`. This can cause unexpected issues in your application. ### Why This Error Occurred From 66bda56c2d048d03c4c8f0f1950df5e375c0ca66 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 14 Feb 2022 12:58:10 -0600 Subject: [PATCH 06/20] Update errors/no-script-in-document.md Co-authored-by: Lee Robinson <me@leerob.io> --- errors/no-script-in-document.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/errors/no-script-in-document.md b/errors/no-script-in-document.md index ae9155e72764..28479f64cab9 100644 --- a/errors/no-script-in-document.md +++ b/errors/no-script-in-document.md @@ -8,7 +8,7 @@ You should not use the `next/script` component in `pages/_document.js`. That's b #### Possible Ways to Fix It -If you want a global script, `pages/_app.js` instead. +If you want a global script, use `next/script` in `pages/_app.js` instead. ```jsx import Script from 'next/script' From c4f4225abf042f73b73bae1b9f5efae526564f68 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 14 Feb 2022 12:58:28 -0600 Subject: [PATCH 07/20] Update errors/no-sync-scripts.md Co-authored-by: Lee Robinson <me@leerob.io> --- errors/no-sync-scripts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/errors/no-sync-scripts.md b/errors/no-sync-scripts.md index 110e24564baf..36632536b9ae 100644 --- a/errors/no-sync-scripts.md +++ b/errors/no-sync-scripts.md @@ -28,8 +28,8 @@ export default Home #### Use `async` or `defer` ```html -<script src="https://third-party-script.js" async></script> -<script src="https://third-party-script.js" defer></script> +<script src="https://third-party-script.js" async /> +<script src="https://third-party-script.js" defer /> ``` ### Useful Links From 831afe21040ea56628588ecdcdfb539545212638 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 14 Feb 2022 12:59:31 -0600 Subject: [PATCH 08/20] Updates a couple of rule descriptions. --- docs/basic-features/eslint.md | 4 ++-- errors/no-html-link-for-pages.md | 2 +- errors/no-img-element.md | 2 +- .../eslint-plugin-next/lib/rules/no-html-link-for-pages.js | 2 +- packages/eslint-plugin-next/lib/rules/no-img-element.js | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/basic-features/eslint.md b/docs/basic-features/eslint.md index ad2e0d40d85e..569cb4fcb5fc 100644 --- a/docs/basic-features/eslint.md +++ b/docs/basic-features/eslint.md @@ -94,8 +94,8 @@ Next.js provides an ESLint plugin, [`eslint-plugin-next`](https://www.npmjs.com/ | ✔️ | [@next/next/no-duplicate-head](https://nextjs.org/docs/messages/no-duplicate-head) | Prevent duplicate usage of `<Head>` in `pages/_document.js`. | | ✔️ | [@next/next/no-head-element](https://nextjs.org/docs/messages/no-head-element) | Prevent usage of `<head>` element. | | ✔️ | [@next/next/no-head-import-in-document](https://nextjs.org/docs/messages/no-head-import-in-document) | Prevent usage of `next/head` in `pages/_document.js`. | -| ✔️ | [@next/next/no-html-link-for-pages](https://nextjs.org/docs/messages/no-html-link-for-pages) | Prevent usage of `<a>` elements to navigate to Next.js pages. | -| ✔️ | [@next/next/no-img-element](https://nextjs.org/docs/messages/no-img-element) | Prevent usage of `<img>` element. | +| ✔️ | [@next/next/no-html-link-for-pages](https://nextjs.org/docs/messages/no-html-link-for-pages) | Prevent usage of `<a>` elements to navigate to internal Next.js pages. | +| ✔️ | [@next/next/no-img-element](https://nextjs.org/docs/messages/no-img-element) | Prevent usage of `<img>` element to prevent layout shift. | | ✔️ | [@next/next/no-page-custom-font](https://nextjs.org/docs/messages/no-page-custom-font) | Prevent page-only custom fonts. | | ✔️ | [@next/next/no-script-in-document](https://nextjs.org/docs/messages/no-script-in-document) | Prevent usage of `next/script` in `pages/_document.js`. | | ✔️ | [@next/next/no-script-component-in-head](https://nextjs.org/docs/messages/no-script-component-in-head) | Prevent usage of `next/script` in `next/head` component. | diff --git a/errors/no-html-link-for-pages.md b/errors/no-html-link-for-pages.md index 28162132bc65..32e124dc11fd 100644 --- a/errors/no-html-link-for-pages.md +++ b/errors/no-html-link-for-pages.md @@ -1,6 +1,6 @@ # No HTML link for pages -> Prevent usage of `<a>` elements to navigate to Next.js pages. +> Prevent usage of `<a>` elements to navigate to internal Next.js pages. ### Why This Error Occurred diff --git a/errors/no-img-element.md b/errors/no-img-element.md index 1c1eee89573f..db4d31f363f2 100644 --- a/errors/no-img-element.md +++ b/errors/no-img-element.md @@ -1,6 +1,6 @@ # No Img Element -> Prevent usage of `<img>` element. +> Prevent usage of `<img>` element to prevent layout shift. ### Why This Error Occurred diff --git a/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js b/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js index a77712779f14..967984492d1f 100644 --- a/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js +++ b/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js @@ -25,7 +25,7 @@ module.exports = { meta: { docs: { description: - 'Prevent usage of `<a>` elements to navigate to Next.js pages.', + 'Prevent usage of `<a>` elements to navigate to internal Next.js pages.', category: 'HTML', recommended: true, url, diff --git a/packages/eslint-plugin-next/lib/rules/no-img-element.js b/packages/eslint-plugin-next/lib/rules/no-img-element.js index 2f3cf148b95e..a9fcbf2bb1c0 100644 --- a/packages/eslint-plugin-next/lib/rules/no-img-element.js +++ b/packages/eslint-plugin-next/lib/rules/no-img-element.js @@ -3,7 +3,7 @@ const url = 'https://nextjs.org/docs/messages/no-img-element' module.exports = { meta: { docs: { - description: 'Prevent usage of `<img>` element.', + description: 'Prevent usage of `<img>` element to prevent layout shift.', category: 'HTML', recommended: true, url, From 0468818b77614ded40177ee3711efe86befba814 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 14 Feb 2022 13:08:27 -0600 Subject: [PATCH 09/20] Adds redirects. --- errors/manifest.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/errors/manifest.json b/errors/manifest.json index 35381292bb95..b487af3f83a9 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -548,10 +548,28 @@ "title": "sharp-version-avif", "path": "/errors/sharp-version-avif.md" }, + { + "path": "/errors/no-script-in-document-page.md", + "redirect": { + "destination": "/errors/no-script-in-document.md" + } + }, { "title": "no-script-in-document", "path": "/errors/no-script-in-document.md" }, + { + "path": "/errors/no-script-in-head-component.md", + "redirect": { + "destination": "/errors/no-script-component-in-head.md" + } + }, + { + "path": "/errors/no-script-component-in-head-component.md", + "redirect": { + "destination": "/errors/no-script-component-in-head.md" + } + }, { "title": "no-script-component-in-head", "path": "/errors/no-script-component-in-head.md" From 1df47a8ab7bc0f7aaf08ce2f762ac744704fbe12 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 14 Feb 2022 14:08:40 -0600 Subject: [PATCH 10/20] Fixes unit tests. --- .../lib/rules/no-head-import-in-document.js | 2 +- .../google-font-display.test.ts | 10 +++---- .../google-font-preconnect.test.ts | 4 +-- .../inline-script-id.test.ts | 2 +- .../eslint-plugin-next/link-passhref.test.ts | 6 ++-- .../next-script-for-ga.test.ts | 2 +- .../no-document-import-in-page.test.ts | 6 ++-- .../no-duplicate-head.test.ts | 22 +++++++------- .../no-head-element.test.ts | 4 +-- .../no-head-import-in-document.test.ts | 30 +++++++++---------- .../no-html-link-for-pages.test.ts | 8 ++--- .../eslint-plugin-next/no-img-element.test.ts | 4 +-- .../no-page-custom-font.test.ts | 6 ++-- .../no-script-component-in-head.test.ts | 4 +-- .../no-script-in-document.test.ts | 20 ++++++------- .../no-server-import-in-page.test.ts | 6 ++-- .../no-sync-scripts.test.ts | 4 +-- .../no-title-in-document-head.test.ts | 4 +-- 18 files changed, 72 insertions(+), 72 deletions(-) diff --git a/packages/eslint-plugin-next/lib/rules/no-head-import-in-document.js b/packages/eslint-plugin-next/lib/rules/no-head-import-in-document.js index b5f00f036604..5a98ebd8497c 100644 --- a/packages/eslint-plugin-next/lib/rules/no-head-import-in-document.js +++ b/packages/eslint-plugin-next/lib/rules/no-head-import-in-document.js @@ -30,7 +30,7 @@ module.exports = { ) { context.report({ node, - message: `\`next/head\` should not be imported in \`pages/_document.js\`. Use \`<Head />\` from \`next/document\` instead. See: ${url}`, + message: `\`next/head\` should not be imported in \`pages${document}\`. Use \`<Head />\` from \`next/document\` instead. See: ${url}`, }) } }, diff --git a/test/unit/eslint-plugin-next/google-font-display.test.ts b/test/unit/eslint-plugin-next/google-font-display.test.ts index 75d40748c738..8754fc526c1a 100644 --- a/test/unit/eslint-plugin-next/google-font-display.test.ts +++ b/test/unit/eslint-plugin-next/google-font-display.test.ts @@ -53,7 +53,7 @@ ruleTester.run('google-font-display', rule, { ); } } - + export default MyDocument; `, ], @@ -76,7 +76,7 @@ ruleTester.run('google-font-display', rule, { errors: [ { message: - 'Display parameter is missing. See: https://nextjs.org/docs/messages/google-font-display', + 'A font-display parameter is missing (adding `&display=optional` is recommended). See: https://nextjs.org/docs/messages/google-font-display', type: 'JSXOpeningElement', }, ], @@ -98,7 +98,7 @@ ruleTester.run('google-font-display', rule, { errors: [ { message: - 'Block behavior is not recommended. See: https://nextjs.org/docs/messages/google-font-display', + 'Block is not recommended. See: https://nextjs.org/docs/messages/google-font-display', type: 'JSXOpeningElement', }, ], @@ -120,7 +120,7 @@ ruleTester.run('google-font-display', rule, { errors: [ { message: - 'Auto behavior is not recommended. See: https://nextjs.org/docs/messages/google-font-display', + 'Auto is not recommended. See: https://nextjs.org/docs/messages/google-font-display', type: 'JSXOpeningElement', }, ], @@ -142,7 +142,7 @@ ruleTester.run('google-font-display', rule, { errors: [ { message: - 'Fallback behavior is not recommended. See: https://nextjs.org/docs/messages/google-font-display', + 'Fallback is not recommended. See: https://nextjs.org/docs/messages/google-font-display', type: 'JSXOpeningElement', }, ], diff --git a/test/unit/eslint-plugin-next/google-font-preconnect.test.ts b/test/unit/eslint-plugin-next/google-font-preconnect.test.ts index e5669c91acaa..d5bbbc717335 100644 --- a/test/unit/eslint-plugin-next/google-font-preconnect.test.ts +++ b/test/unit/eslint-plugin-next/google-font-preconnect.test.ts @@ -42,7 +42,7 @@ ruleTester.run('google-font-preconnect', rule, { errors: [ { message: - 'Preconnect is missing. See: https://nextjs.org/docs/messages/google-font-preconnect', + '`rel="preconnect"` is missing from Google Font. See: https://nextjs.org/docs/messages/google-font-preconnect', type: 'JSXOpeningElement', }, ], @@ -58,7 +58,7 @@ ruleTester.run('google-font-preconnect', rule, { errors: [ { message: - 'Preconnect is missing. See: https://nextjs.org/docs/messages/google-font-preconnect', + '`rel="preconnect"` is missing from Google Font. See: https://nextjs.org/docs/messages/google-font-preconnect', type: 'JSXOpeningElement', }, ], diff --git a/test/unit/eslint-plugin-next/inline-script-id.test.ts b/test/unit/eslint-plugin-next/inline-script-id.test.ts index d584af36402a..a5195829a782 100644 --- a/test/unit/eslint-plugin-next/inline-script-id.test.ts +++ b/test/unit/eslint-plugin-next/inline-script-id.test.ts @@ -12,7 +12,7 @@ import { RuleTester } from 'eslint' }) const errorMessage = - 'next/script components with inline content must specify an `id` attribute. See: https://nextjs.org/docs/messages/inline-script-id' + '`next/script` components with inline content must specify an `id` attribute. See: https://nextjs.org/docs/messages/inline-script-id' const ruleTester = new RuleTester() ruleTester.run('inline-script-id', rule, { diff --git a/test/unit/eslint-plugin-next/link-passhref.test.ts b/test/unit/eslint-plugin-next/link-passhref.test.ts index 6b8f3668edf0..7f83cfe73713 100644 --- a/test/unit/eslint-plugin-next/link-passhref.test.ts +++ b/test/unit/eslint-plugin-next/link-passhref.test.ts @@ -66,7 +66,7 @@ ruleTester.run('link-passhref', rule, { errors: [ { message: - 'passHref is missing. See: https://nextjs.org/docs/messages/link-passhref', + '`passHref` is missing. See: https://nextjs.org/docs/messages/link-passhref', type: 'JSXOpeningElement', }, ], @@ -83,7 +83,7 @@ ruleTester.run('link-passhref', rule, { errors: [ { message: - 'passHref is missing. See: https://nextjs.org/docs/messages/link-passhref', + '`passHref` is missing. See: https://nextjs.org/docs/messages/link-passhref', type: 'JSXOpeningElement', }, ], @@ -100,7 +100,7 @@ ruleTester.run('link-passhref', rule, { errors: [ { message: - 'passHref must be set to true. See: https://nextjs.org/docs/messages/link-passhref', + '`passHref` must be set to `true`. See: https://nextjs.org/docs/messages/link-passhref', type: 'JSXOpeningElement', }, ], diff --git a/test/unit/eslint-plugin-next/next-script-for-ga.test.ts b/test/unit/eslint-plugin-next/next-script-for-ga.test.ts index a40772eeb2e7..cee8ceb4a092 100644 --- a/test/unit/eslint-plugin-next/next-script-for-ga.test.ts +++ b/test/unit/eslint-plugin-next/next-script-for-ga.test.ts @@ -12,7 +12,7 @@ import { RuleTester } from 'eslint' }) const ERROR_MSG = - 'Use the `next/script` component for loading third party scripts. See: https://nextjs.org/docs/messages/next-script-for-ga' + 'Prefer `next/script` component when using the inline script for Google Analytics. See: https://nextjs.org/docs/messages/next-script-for-ga' const ruleTester = new RuleTester() diff --git a/test/unit/eslint-plugin-next/no-document-import-in-page.test.ts b/test/unit/eslint-plugin-next/no-document-import-in-page.test.ts index 72ee7a7f3530..ad98e079309c 100644 --- a/test/unit/eslint-plugin-next/no-document-import-in-page.test.ts +++ b/test/unit/eslint-plugin-next/no-document-import-in-page.test.ts @@ -125,7 +125,7 @@ ruleTester.run('no-document-import-in-page', rule, { errors: [ { message: - 'next/document should not be imported outside of pages/_document.js. See: https://nextjs.org/docs/messages/no-document-import-in-page', + '`<Document />` from `next/document` should not be imported outside of `pages/_document.js`. See: https://nextjs.org/docs/messages/no-document-import-in-page', type: 'ImportDeclaration', }, ], @@ -139,7 +139,7 @@ ruleTester.run('no-document-import-in-page', rule, { errors: [ { message: - 'next/document should not be imported outside of pages/_document.js. See: https://nextjs.org/docs/messages/no-document-import-in-page', + '`<Document />` from `next/document` should not be imported outside of `pages/_document.js`. See: https://nextjs.org/docs/messages/no-document-import-in-page', type: 'ImportDeclaration', }, ], @@ -153,7 +153,7 @@ ruleTester.run('no-document-import-in-page', rule, { errors: [ { message: - 'next/document should not be imported outside of pages/_document.js. See: https://nextjs.org/docs/messages/no-document-import-in-page', + '`<Document />` from `next/document` should not be imported outside of `pages/_document.js`. See: https://nextjs.org/docs/messages/no-document-import-in-page', type: 'ImportDeclaration', }, ], diff --git a/test/unit/eslint-plugin-next/no-duplicate-head.test.ts b/test/unit/eslint-plugin-next/no-duplicate-head.test.ts index 194ea827f83c..c859e8029136 100644 --- a/test/unit/eslint-plugin-next/no-duplicate-head.test.ts +++ b/test/unit/eslint-plugin-next/no-duplicate-head.test.ts @@ -21,7 +21,7 @@ ruleTester.run('no-duplicate-head', rule, { static async getInitialProps(ctx) { //... } - + render() { return ( <Html> @@ -30,7 +30,7 @@ ruleTester.run('no-duplicate-head', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.js', @@ -38,7 +38,7 @@ ruleTester.run('no-duplicate-head', rule, { { code: `import Document, { Html, Head, Main, NextScript } from 'next/document' - class MyDocument extends Document { + class MyDocument extends Document { render() { return ( <Html> @@ -53,7 +53,7 @@ ruleTester.run('no-duplicate-head', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.tsx', @@ -64,7 +64,7 @@ ruleTester.run('no-duplicate-head', rule, { code: ` import Document, { Html, Main, NextScript } from 'next/document' import Head from 'next/head' - + class MyDocument extends Document { render() { return ( @@ -76,19 +76,19 @@ ruleTester.run('no-duplicate-head', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.js', errors: [ { message: - 'Do not include multiple instances of <Head/>. See: https://nextjs.org/docs/messages/no-duplicate-head', + 'Do not include multiple instances of `<Head/>`. See: https://nextjs.org/docs/messages/no-duplicate-head', type: 'JSXElement', }, { message: - 'Do not include multiple instances of <Head/>. See: https://nextjs.org/docs/messages/no-duplicate-head', + 'Do not include multiple instances of `<Head/>`. See: https://nextjs.org/docs/messages/no-duplicate-head', type: 'JSXElement', }, ], @@ -97,7 +97,7 @@ ruleTester.run('no-duplicate-head', rule, { code: ` import Document, { Html, Main, NextScript } from 'next/document' import Head from 'next/head' - + class MyDocument extends Document { render() { return ( @@ -124,14 +124,14 @@ ruleTester.run('no-duplicate-head', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.page.tsx', errors: [ { message: - 'Do not include multiple instances of <Head/>. See: https://nextjs.org/docs/messages/no-duplicate-head', + 'Do not include multiple instances of `<Head/>`. See: https://nextjs.org/docs/messages/no-duplicate-head', type: 'JSXElement', }, ], diff --git a/test/unit/eslint-plugin-next/no-head-element.test.ts b/test/unit/eslint-plugin-next/no-head-element.test.ts index d1014b9374ef..25034ab2f57e 100644 --- a/test/unit/eslint-plugin-next/no-head-element.test.ts +++ b/test/unit/eslint-plugin-next/no-head-element.test.ts @@ -67,7 +67,7 @@ ruleTester.run('no-head-element', rule, { errors: [ { message: - "Do not use <head>. Use Head from 'next/head' instead. See: https://nextjs.org/docs/messages/no-head-element", + 'Do not use `<head>` element. Use `<Head />` from `next/head` instead. See: https://nextjs.org/docs/messages/no-head-element', type: 'JSXOpeningElement', }, ], @@ -93,7 +93,7 @@ ruleTester.run('no-head-element', rule, { errors: [ { message: - "Do not use <head>. Use Head from 'next/head' instead. See: https://nextjs.org/docs/messages/no-head-element", + 'Do not use `<head>` element. Use `<Head />` from `next/head` instead. See: https://nextjs.org/docs/messages/no-head-element', type: 'JSXOpeningElement', }, ], diff --git a/test/unit/eslint-plugin-next/no-head-import-in-document.test.ts b/test/unit/eslint-plugin-next/no-head-import-in-document.test.ts index 8e6edbd7e4ea..4bcaed90b7a3 100644 --- a/test/unit/eslint-plugin-next/no-head-import-in-document.test.ts +++ b/test/unit/eslint-plugin-next/no-head-import-in-document.test.ts @@ -21,7 +21,7 @@ ruleTester.run('no-head-import-in-document', rule, { static async getInitialProps(ctx) { //... } - + render() { return ( <Html> @@ -31,7 +31,7 @@ ruleTester.run('no-head-import-in-document', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.tsx', @@ -46,7 +46,7 @@ ruleTester.run('no-head-import-in-document', rule, { <meta name="viewport" content="initial-scale=1.0, width=device-width" /> </Head> ); - } + } `, filename: 'pages/index.tsx', }, @@ -56,7 +56,7 @@ ruleTester.run('no-head-import-in-document', rule, { code: ` import Document, { Html, Main, NextScript } from 'next/document' import Head from 'next/head' - + class MyDocument extends Document { render() { return ( @@ -70,14 +70,14 @@ ruleTester.run('no-head-import-in-document', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.js', errors: [ { message: - 'next/head should not be imported in pages/_document.js. Import Head from next/document instead. See: https://nextjs.org/docs/messages/no-head-import-in-document', + '`next/head` should not be imported in `pages/_document.js`. Use `<Head />` from `next/document` instead. See: https://nextjs.org/docs/messages/no-head-import-in-document', type: 'ImportDeclaration', }, ], @@ -86,7 +86,7 @@ ruleTester.run('no-head-import-in-document', rule, { code: ` import Document, { Html, Main, NextScript } from 'next/document' import Head from 'next/head' - + class MyDocument extends Document { render() { return ( @@ -100,14 +100,14 @@ ruleTester.run('no-head-import-in-document', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.page.tsx', errors: [ { message: - 'next/head should not be imported in pages/_document.page.tsx. Import Head from next/document instead. See: https://nextjs.org/docs/messages/no-head-import-in-document', + '`next/head` should not be imported in `pages/_document.page.tsx`. Use `<Head />` from `next/document` instead. See: https://nextjs.org/docs/messages/no-head-import-in-document', type: 'ImportDeclaration', }, ], @@ -116,7 +116,7 @@ ruleTester.run('no-head-import-in-document', rule, { code: ` import Document, { Html, Main, NextScript } from 'next/document' import Head from 'next/head' - + class MyDocument extends Document { render() { return ( @@ -130,14 +130,14 @@ ruleTester.run('no-head-import-in-document', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document/index.js', errors: [ { message: - 'next/head should not be imported in pages/_document/index.js. Import Head from next/document instead. See: https://nextjs.org/docs/messages/no-head-import-in-document', + '`next/head` should not be imported in `pages/_document/index.js`. Use `<Head />` from `next/document` instead. See: https://nextjs.org/docs/messages/no-head-import-in-document', type: 'ImportDeclaration', }, ], @@ -146,7 +146,7 @@ ruleTester.run('no-head-import-in-document', rule, { code: ` import Document, { Html, Main, NextScript } from 'next/document' import Head from 'next/head' - + class MyDocument extends Document { render() { return ( @@ -160,14 +160,14 @@ ruleTester.run('no-head-import-in-document', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document/index.tsx', errors: [ { message: - 'next/head should not be imported in pages/_document/index.tsx. Import Head from next/document instead. See: https://nextjs.org/docs/messages/no-head-import-in-document', + '`next/head` should not be imported in `pages/_document/index.tsx`. Use `<Head />` from `next/document` instead. See: https://nextjs.org/docs/messages/no-head-import-in-document', type: 'ImportDeclaration', }, ], diff --git a/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts b/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts index 93cacf99edc7..e5aa38beecb1 100644 --- a/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts +++ b/test/unit/eslint-plugin-next/no-html-link-for-pages.test.ts @@ -246,7 +246,7 @@ describe('no-html-link-for-pages', function () { assert.notEqual(report, undefined, 'No lint errors found.') assert.equal( report.message, - "Do not use the HTML <a> tag to navigate to /. Use Link from 'next/link' instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages" + 'Do not use an `<a>` element to navigate to `/`. Use `<Link />` from `next/link` instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages' ) }) @@ -257,7 +257,7 @@ describe('no-html-link-for-pages', function () { assert.notEqual(report, undefined, 'No lint errors found.') assert.equal( report.message, - "Do not use the HTML <a> tag to navigate to /list/foo/bar/. Use Link from 'next/link' instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages" + 'Do not use an `<a>` element to navigate to `/list/foo/bar/`. Use `<Link />` from `next/link` instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages' ) const [secondReport] = linter.verify( secondInvalidDynamicCode, @@ -269,7 +269,7 @@ describe('no-html-link-for-pages', function () { assert.notEqual(secondReport, undefined, 'No lint errors found.') assert.equal( secondReport.message, - "Do not use the HTML <a> tag to navigate to /list/foo/. Use Link from 'next/link' instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages" + 'Do not use an `<a>` element to navigate to `/list/foo/`. Use `<Link />` from `next/link` instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages' ) const [thirdReport] = linter.verify(thirdInvalidDynamicCode, linterConfig, { filename: 'foo.js', @@ -277,7 +277,7 @@ describe('no-html-link-for-pages', function () { assert.notEqual(thirdReport, undefined, 'No lint errors found.') assert.equal( thirdReport.message, - "Do not use the HTML <a> tag to navigate to /list/lorem-ipsum/. Use Link from 'next/link' instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages" + 'Do not use an `<a>` element to navigate to `/list/lorem-ipsum/`. Use `<Link />` from `next/link` instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages' ) }) }) diff --git a/test/unit/eslint-plugin-next/no-img-element.test.ts b/test/unit/eslint-plugin-next/no-img-element.test.ts index 0db0d7f2a9a3..e9d255a64d5d 100644 --- a/test/unit/eslint-plugin-next/no-img-element.test.ts +++ b/test/unit/eslint-plugin-next/no-img-element.test.ts @@ -38,7 +38,7 @@ ruleTester.run('no-img-element', rule, { render() { return ( <div> - <img + <img src="/test.png" alt="Test picture" width={500} @@ -51,7 +51,7 @@ ruleTester.run('no-img-element', rule, { errors: [ { message: - "Do not use <img>. Use Image from 'next/image' instead. See: https://nextjs.org/docs/messages/no-img-element", + 'Do not use `<img>` element. Use `<Image />` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element', type: 'JSXOpeningElement', }, ], diff --git a/test/unit/eslint-plugin-next/no-page-custom-font.test.ts b/test/unit/eslint-plugin-next/no-page-custom-font.test.ts index 9318010ef262..8e2a5623c8ca 100644 --- a/test/unit/eslint-plugin-next/no-page-custom-font.test.ts +++ b/test/unit/eslint-plugin-next/no-page-custom-font.test.ts @@ -148,7 +148,7 @@ ruleTester.run('no-page-custom-font', rule, { errors: [ { message: - 'Custom fonts not added at the document level will only load for a single page. This is discouraged. See: https://nextjs.org/docs/messages/no-page-custom-font', + 'Custom fonts not added in `pages/_document.js` will only load for a single page. This is discouraged. See: https://nextjs.org/docs/messages/no-page-custom-font', type: 'JSXOpeningElement', }, ], @@ -188,11 +188,11 @@ ruleTester.run('no-page-custom-font', rule, { errors: [ { message: - 'Rendering this <link /> not inline within <Head> of Document disables font optimization. This is discouraged. See: https://nextjs.org/docs/messages/no-page-custom-font', + 'Using `<link />` outside of `<Head>` will disable automatic font optimization. This is discouraged. See: https://nextjs.org/docs/messages/no-page-custom-font', }, { message: - 'Rendering this <link /> not inline within <Head> of Document disables font optimization. This is discouraged. See: https://nextjs.org/docs/messages/no-page-custom-font', + 'Using `<link />` outside of `<Head>` will disable automatic font optimization. This is discouraged. See: https://nextjs.org/docs/messages/no-page-custom-font', }, ], }, diff --git a/test/unit/eslint-plugin-next/no-script-component-in-head.test.ts b/test/unit/eslint-plugin-next/no-script-component-in-head.test.ts index 3a1165213278..a6882b12b961 100644 --- a/test/unit/eslint-plugin-next/no-script-component-in-head.test.ts +++ b/test/unit/eslint-plugin-next/no-script-component-in-head.test.ts @@ -32,7 +32,7 @@ ruleTester.run('no-script-in-head', rule, { code: ` import Head from "next/head"; import Script from "next/script"; - + export default function Index() { return ( <Head> @@ -44,7 +44,7 @@ ruleTester.run('no-script-in-head', rule, { errors: [ { message: - "next/script shouldn't be used inside next/head. See: https://nextjs.org/docs/messages/no-script-component-in-head-component", + '`next/script` should not be used in `next/head` component. Move `<Script />` outside of `<Head>` instead. See: https://nextjs.org/docs/messages/no-script-component-in-head-component', }, ], }, diff --git a/test/unit/eslint-plugin-next/no-script-in-document.test.ts b/test/unit/eslint-plugin-next/no-script-in-document.test.ts index d019e6d0018c..7328d2304ddd 100644 --- a/test/unit/eslint-plugin-next/no-script-in-document.test.ts +++ b/test/unit/eslint-plugin-next/no-script-in-document.test.ts @@ -21,7 +21,7 @@ ruleTester.run('no-script-import-in-document', rule, { static async getInitialProps(ctx) { //... } - + render() { return ( <Html> @@ -30,7 +30,7 @@ ruleTester.run('no-script-import-in-document', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.js', @@ -38,7 +38,7 @@ ruleTester.run('no-script-import-in-document', rule, { { code: `import Document, { Html, Head, Main, NextScript } from 'next/document' - class MyDocument extends Document { + class MyDocument extends Document { render() { return ( <Html> @@ -49,7 +49,7 @@ ruleTester.run('no-script-import-in-document', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.tsx', @@ -60,7 +60,7 @@ ruleTester.run('no-script-import-in-document', rule, { code: ` import Document, { Html, Main, NextScript } from 'next/document' import Script from 'next/script' - + class MyDocument extends Document { render() { return ( @@ -70,13 +70,13 @@ ruleTester.run('no-script-import-in-document', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.js', errors: [ { - message: `next/script should not be used in pages/_document.js. See: https://nextjs.org/docs/messages/no-script-in-document-page`, + message: `\`<Script />\` from \`next/script\` should not be used in \`pages/_document.js\`. Use in \`pages/_app.js\` instead. See: https://nextjs.org/docs/messages/no-script-in-document`, }, ], }, @@ -84,7 +84,7 @@ ruleTester.run('no-script-import-in-document', rule, { code: ` import Document, { Html, Main, NextScript } from 'next/document' import NextScriptTag from 'next/script' - + class MyDocument extends Document { render() { return ( @@ -101,13 +101,13 @@ ruleTester.run('no-script-import-in-document', rule, { ) } } - + export default MyDocument `, filename: 'pages/_document.js', errors: [ { - message: `next/script should not be used in pages/_document.js. See: https://nextjs.org/docs/messages/no-script-in-document-page`, + message: `\`<Script />\` from \`next/script\` should not be used in \`pages/_document.js\`. Use in \`pages/_app.js\` instead. See: https://nextjs.org/docs/messages/no-script-in-document`, }, ], }, diff --git a/test/unit/eslint-plugin-next/no-server-import-in-page.test.ts b/test/unit/eslint-plugin-next/no-server-import-in-page.test.ts index da1dbad31d23..82abba79fce7 100644 --- a/test/unit/eslint-plugin-next/no-server-import-in-page.test.ts +++ b/test/unit/eslint-plugin-next/no-server-import-in-page.test.ts @@ -98,7 +98,7 @@ ruleTester.run('no-server-import-in-page', rule, { errors: [ { message: - 'next/server should not be imported outside of pages/_middleware.js. See: https://nextjs.org/docs/messages/no-server-import-in-page', + '`next/server` should not be used outside of `pages/_middleware.js`. See: https://nextjs.org/docs/messages/no-server-import-in-page', type: 'ImportDeclaration', }, ], @@ -112,7 +112,7 @@ ruleTester.run('no-server-import-in-page', rule, { errors: [ { message: - 'next/server should not be imported outside of pages/_middleware.js. See: https://nextjs.org/docs/messages/no-server-import-in-page', + '`next/server` should not be used outside of `pages/_middleware.js`. See: https://nextjs.org/docs/messages/no-server-import-in-page', type: 'ImportDeclaration', }, ], @@ -126,7 +126,7 @@ ruleTester.run('no-server-import-in-page', rule, { errors: [ { message: - 'next/server should not be imported outside of pages/_middleware.js. See: https://nextjs.org/docs/messages/no-server-import-in-page', + '`next/server` should not be used outside of `pages/_middleware.js`. See: https://nextjs.org/docs/messages/no-server-import-in-page', type: 'ImportDeclaration', }, ], diff --git a/test/unit/eslint-plugin-next/no-sync-scripts.test.ts b/test/unit/eslint-plugin-next/no-sync-scripts.test.ts index bf006441cd5c..90d4267efa8c 100644 --- a/test/unit/eslint-plugin-next/no-sync-scripts.test.ts +++ b/test/unit/eslint-plugin-next/no-sync-scripts.test.ts @@ -58,7 +58,7 @@ ruleTester.run('sync-scripts', rule, { errors: [ { message: - 'External synchronous scripts are forbidden. See: https://nextjs.org/docs/messages/no-sync-scripts', + 'Synchronous scripts should not be used. See: https://nextjs.org/docs/messages/no-sync-scripts', type: 'JSXOpeningElement', }, ], @@ -80,7 +80,7 @@ ruleTester.run('sync-scripts', rule, { errors: [ { message: - 'External synchronous scripts are forbidden. See: https://nextjs.org/docs/messages/no-sync-scripts', + 'Synchronous scripts should not be used. See: https://nextjs.org/docs/messages/no-sync-scripts', type: 'JSXOpeningElement', }, ], diff --git a/test/unit/eslint-plugin-next/no-title-in-document-head.test.ts b/test/unit/eslint-plugin-next/no-title-in-document-head.test.ts index d0630191a47c..8877d0c1343d 100644 --- a/test/unit/eslint-plugin-next/no-title-in-document-head.test.ts +++ b/test/unit/eslint-plugin-next/no-title-in-document-head.test.ts @@ -38,7 +38,7 @@ ruleTester.run('no-title-in-document-head', rule, { ); } } - + export default MyDocument; `, ], @@ -60,7 +60,7 @@ ruleTester.run('no-title-in-document-head', rule, { errors: [ { message: - 'Titles should be defined at the page-level using next/head. See: https://nextjs.org/docs/messages/no-title-in-document-head', + 'Do not use `<title>` element with `<Head />` component from `next/document`. Titles should defined at the page-level using `<Head />` from `next/head` instead. See: https://nextjs.org/docs/messages/no-title-in-document-head', type: 'JSXElement', }, ], From d16be8bfdce8c73c0c4eb80d48cdfb85de6b8bae Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Thu, 14 Apr 2022 17:12:26 -0500 Subject: [PATCH 11/20] Removes duplicated section. --- errors/no-head-import-in-document.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/errors/no-head-import-in-document.md b/errors/no-head-import-in-document.md index b75f9c64ca26..cb9c18e08eb8 100644 --- a/errors/no-head-import-in-document.md +++ b/errors/no-head-import-in-document.md @@ -4,10 +4,6 @@ ### Why This Error Occurred -`next/head` should not be imported in `pages/_document.js`. This can cause unexpected issues in your application. - -### Why This Error Occurred - `next/head` was imported in `pages/_document.js`. This can cause unexpected issues in your application. ### Possible Ways to Fix It From 37a09c0abf8aedec15128c24e7c264a6bbc249a8 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Fri, 22 Apr 2022 18:03:23 -0500 Subject: [PATCH 12/20] Updates `no-before-interactive-script-outside-document` description. --- docs/basic-features/eslint.md | 44 +++++++++---------- ...ore-interactive-script-outside-document.js | 9 ++-- ...ore-interactive-script-outside-document.ts | 2 +- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/docs/basic-features/eslint.md b/docs/basic-features/eslint.md index eea12c1b2f8a..dc03fd5d19bf 100644 --- a/docs/basic-features/eslint.md +++ b/docs/basic-features/eslint.md @@ -82,28 +82,28 @@ Next.js provides an ESLint plugin, [`eslint-plugin-next`](https://www.npmjs.com/ - ✔: Enabled in the recommended configuration -| | Rule | Description | -| :-: | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -| ✔️ | [@next/next/google-font-display](/docs/messages/google-font-display.md) | Enforce font-display behavior with Google Fonts. | -| ✔️ | [@next/next/google-font-preconnect](/docs/messages/google-font-preconnect.md) | Ensure `preconnect` is used with Google Fonts. | -| ✔️ | [@next/next/inline-script-id](/docs/messages/inline-script-id.md) | Enforce `id` attribute on `next/script` components with inline content. | -| ✔️ | [@next/next/link-passhref](/docs/messages/link-passhref.md) | Ensure `passHref` is used with custom `Link` components. | -| ✔️ | [@next/next/next-script-for-ga](/docs/messages/next-script-for-ga.md) | Prefer `next/script` component when using the inline script for Google Analytics. | -| ✔️ | [@next/next/no-css-tags](/docs/messages/no-css-tags.md) | Prevent manual stylesheet tags. | -| ✔️ | [@next/next/no-document-import-in-page](/docs/messages/no-document-import-in-page.md) | Prevent importing `next/document` outside of `pages/_document.js`. | -| ✔️ | [@next/next/no-duplicate-head](/docs/messages/no-duplicate-head.md) | Prevent duplicate usage of `<Head>` in `pages/_document.js`. | -| ✔️ | [@next/next/no-head-element](/docs/messages/no-head-element.md) | Prevent usage of `<head>` element. | -| ✔️ | [@next/next/no-head-import-in-document](/docs/messages/no-head-import-in-document.md) | Prevent usage of `next/head` in `pages/_document.js`. | -| ✔️ | [@next/next/no-html-link-for-pages](/docs/messages/no-html-link-for-pages.md) | Prevent usage of `<a>` elements to navigate to internal Next.js pages. | -| ✔️ | [@next/next/no-img-element](/docs/messages/no-img-element.md) | Prevent usage of `<img>` element to prevent layout shift. | -| ✔️ | [@next/next/no-page-custom-font](/docs/messages/no-page-custom-font.md) | Prevent page-only custom fonts. | -| ✔️ | [@next/next/no-script-in-document](/docs/messages/no-script-in-document.md) | Prevent usage of `next/script` in `pages/_document.js`. | -| ✔️ | [@next/next/no-script-component-in-head](/docs/messages/no-script-component-in-head.md) | Prevent usage of `next/script` in `next/head` component. | -| ✔️ | [@next/next/no-server-import-in-page](/docs/messages/no-server-import-in-page.md) | Prevent usage of `next/server` outside of `pages/_middleware.js`. | -| ✔️ | [@next/next/no-sync-scripts](/docs/messages/no-sync-scripts.md) | Prevent synchronous scripts. | -| ✔️ | [@next/next/no-title-in-document-head](/docs/messages/no-title-in-document-head.md) | Prevent usage of `<title>` with `Head` component from `next/document`. | -| ✔️ | @next/next/no-typos | Prevent common typos in [Next.js's data fetching functions](/docs/basic-features/data-fetching.md) | -| ✔️ | [@next/next/no-unwanted-polyfillio](/docs/messages/no-unwanted-polyfillio.md) | Prevent duplicate polyfills from Polyfill.io. | +| | Rule | Description | +| :-: | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | +| ✔️ | [@next/next/google-font-display](/docs/messages/google-font-display.md) | Enforce font-display behavior with Google Fonts. | +| ✔️ | [@next/next/google-font-preconnect](/docs/messages/google-font-preconnect.md) | Ensure `preconnect` is used with Google Fonts. | +| ✔️ | [@next/next/inline-script-id](/docs/messages/inline-script-id.md) | Enforce `id` attribute on `next/script` components with inline content. | +| ✔️ | [@next/next/link-passhref](/docs/messages/link-passhref.md) | Ensure `passHref` is used with custom `Link` components. | +| ✔️ | [@next/next/next-script-for-ga](/docs/messages/next-script-for-ga.md) | Prefer `next/script` component when using the inline script for Google Analytics. | +| ✔️ | [@next/next/no-before-interactive-script-outside-document](/docs/messages/no-before-interactive-script-outside-document.md) | Prevent usage of `next/script`'s `beforeInteractive` strategy outside of `pages/_document.js`. | +| ✔️ | [@next/next/no-css-tags](/docs/messages/no-css-tags.md) | Prevent manual stylesheet tags. | +| ✔️ | [@next/next/no-document-import-in-page](/docs/messages/no-document-import-in-page.md) | Prevent importing `next/document` outside of `pages/_document.js`. | +| ✔️ | [@next/next/no-duplicate-head](/docs/messages/no-duplicate-head.md) | Prevent duplicate usage of `<Head>` in `pages/_document.js`. | +| ✔️ | [@next/next/no-head-element](/docs/messages/no-head-element.md) | Prevent usage of `<head>` element. | +| ✔️ | [@next/next/no-head-import-in-document](/docs/messages/no-head-import-in-document.md) | Prevent usage of `next/head` in `pages/_document.js`. | +| ✔️ | [@next/next/no-html-link-for-pages](/docs/messages/no-html-link-for-pages.md) | Prevent usage of `<a>` elements to navigate to internal Next.js pages. | +| ✔️ | [@next/next/no-img-element](/docs/messages/no-img-element.md) | Prevent usage of `<img>` element to prevent layout shift. | +| ✔️ | [@next/next/no-page-custom-font](/docs/messages/no-page-custom-font.md) | Prevent page-only custom fonts. | +| ✔️ | [@next/next/no-script-component-in-head](/docs/messages/no-script-component-in-head.md) | Prevent usage of `next/script` in `next/head` component. | +| ✔️ | [@next/next/no-server-import-in-page](/docs/messages/no-server-import-in-page.md) | Prevent usage of `next/server` outside of `pages/_middleware.js`. | +| ✔️ | [@next/next/no-sync-scripts](/docs/messages/no-sync-scripts.md) | Prevent synchronous scripts. | +| ✔️ | [@next/next/no-title-in-document-head](/docs/messages/no-title-in-document-head.md) | Prevent usage of `<title>` with `Head` component from `next/document`. | +| ✔️ | @next/next/no-typos | Prevent common typos in [Next.js's data fetching functions](/docs/basic-features/data-fetching.md) | +| ✔️ | [@next/next/no-unwanted-polyfillio](/docs/messages/no-unwanted-polyfillio.md) | Prevent duplicate polyfills from Polyfill.io. | If you already have ESLint configured in your application, we recommend extending from this plugin directly instead of including `eslint-config-next` unless a few conditions are met. Refer to the [Recommended Plugin Ruleset](/docs/basic-features/eslint.md#recommended-plugin-ruleset) to learn more. diff --git a/packages/eslint-plugin-next/lib/rules/no-before-interactive-script-outside-document.js b/packages/eslint-plugin-next/lib/rules/no-before-interactive-script-outside-document.js index 0eeaf97cdd18..060a1c54f1b5 100644 --- a/packages/eslint-plugin-next/lib/rules/no-before-interactive-script-outside-document.js +++ b/packages/eslint-plugin-next/lib/rules/no-before-interactive-script-outside-document.js @@ -1,12 +1,15 @@ const path = require('path') +const url = + 'https://nextjs.org/docs/messages/no-before-interactive-script-outside-document' + module.exports = { meta: { docs: { description: - 'Disallow using next/script beforeInteractive strategy outside the next/_document component', + "Prevent usage of `next/script`'s `beforeInteractive` strategy outside of `pages/_document.js`.", recommended: true, - url: 'https://nextjs.org/docs/messages/no-before-interactive-script-outside-document', + url, }, }, create: function (context) { @@ -43,7 +46,7 @@ module.exports = { context.report({ node, message: - 'next/script beforeInteractive strategy should only be used inside next/_document. See: https://nextjs.org/docs/messages/no-before-interactive-script-outside-document', + "`next/script`'s `beforeInteractive` strategy should not be used outside of `pages/_document.js`. See: ${url}", }) }, } diff --git a/test/unit/eslint-plugin-next/no-before-interactive-script-outside-document.ts b/test/unit/eslint-plugin-next/no-before-interactive-script-outside-document.ts index bd5eb6d8184c..35d2b6835b59 100644 --- a/test/unit/eslint-plugin-next/no-before-interactive-script-outside-document.ts +++ b/test/unit/eslint-plugin-next/no-before-interactive-script-outside-document.ts @@ -95,7 +95,7 @@ ruleTester.run('no-before-interactive-script-outside-document', rule, { errors: [ { message: - 'next/script beforeInteractive strategy should only be used inside next/_document. See: https://nextjs.org/docs/messages/no-before-interactive-script-outside-document', + "`next/script`'s `beforeInteractive` strategy should not be used outside of `pages/_document.js`. See: https://nextjs.org/docs/messages/no-before-interactive-script-outside-document", }, ], }, From c60ba226ed5369f4427eb701259331c5d225a165 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Fri, 22 Apr 2022 18:12:25 -0500 Subject: [PATCH 13/20] Fixes lint. --- .../lib/rules/no-before-interactive-script-outside-document.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/eslint-plugin-next/lib/rules/no-before-interactive-script-outside-document.js b/packages/eslint-plugin-next/lib/rules/no-before-interactive-script-outside-document.js index 060a1c54f1b5..62e81f0cfa33 100644 --- a/packages/eslint-plugin-next/lib/rules/no-before-interactive-script-outside-document.js +++ b/packages/eslint-plugin-next/lib/rules/no-before-interactive-script-outside-document.js @@ -45,8 +45,7 @@ module.exports = { context.report({ node, - message: - "`next/script`'s `beforeInteractive` strategy should not be used outside of `pages/_document.js`. See: ${url}", + message: `\`next/script\`'s \`beforeInteractive\` strategy should not be used outside of \`pages/_document.js\`. See: ${url}`, }) }, } From 75dc0fa4de47ac8d89409393848d227e40bfce13 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Fri, 22 Apr 2022 19:46:10 -0500 Subject: [PATCH 14/20] Fixes integration tests. --- test/integration/eslint/test/index.test.js | 48 ++++++++++------------ 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/test/integration/eslint/test/index.test.js b/test/integration/eslint/test/index.test.js index 31c7be989885..1ded794432b0 100644 --- a/test/integration/eslint/test/index.test.js +++ b/test/integration/eslint/test/index.test.js @@ -59,7 +59,7 @@ describe('ESLint', () => { const output = stdout + stderr expect(output).toContain( - 'Warning: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) expect(output).toContain( 'Error: Comments inside children section of tag should be placed inside braces' @@ -90,9 +90,7 @@ describe('ESLint', () => { expect(output).toContain( 'Error: Comments inside children section of tag should be placed inside braces' ) - expect(output).toContain( - 'Warning: External synchronous scripts are forbidden' - ) + expect(output).toContain('Error: Synchronous scripts should not be used.') }) test('invalid older eslint version', async () => { @@ -121,7 +119,7 @@ describe('ESLint', () => { expect(output).not.toContain('Build error occurred') expect(output).not.toContain('NoFilesFoundError') expect(output).toContain( - 'Warning: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) expect(output).toContain('Compiled successfully') }) @@ -136,7 +134,7 @@ describe('ESLint', () => { expect(output).not.toContain('Build error occurred') expect(output).not.toContain('AllFilesIgnoredError') expect(output).toContain( - 'Warning: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) expect(output).toContain('Compiled successfully') }) @@ -270,7 +268,7 @@ describe('ESLint', () => { const output = stdout + stderr expect(output).toContain( - 'Warning: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) expect(output).toContain( 'Error: Comments inside children section of tag should be placed inside braces' @@ -285,10 +283,10 @@ describe('ESLint', () => { const output = stdout + stderr expect(output).toContain( - "Warning: Do not use <img>. Use Image from 'next/image' instead." + 'Error: Do not use `<img>` element. Use `<Image />` from `next/image` instead.' ) expect(output).toContain( - 'Error: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) }) @@ -303,11 +301,9 @@ describe('ESLint', () => { ) const output = stdout + stderr + expect(output).toContain('Error: Synchronous scripts should not be used.') expect(output).toContain( - 'Warning: External synchronous scripts are forbidden' - ) - expect(output).toContain( - 'Error: next/document should not be imported outside of pages/_document.js.' + 'Warning: `<Document />` from `next/document` should not be imported outside of `pages/_document.js`.' ) }) @@ -323,10 +319,10 @@ describe('ESLint', () => { const output = stdout + stderr expect(output).toContain( - "Warning: Do not use <img>. Use Image from 'next/image' instead." + 'Error: Do not use `<img>` element. Use `<Image />` from `next/image` instead.' ) expect(output).toContain( - 'Error: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) }) @@ -393,7 +389,7 @@ describe('ESLint', () => { 'Error: Comments inside children section of tag should be placed inside braces' ) expect(output).not.toContain( - 'Warning: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) }) @@ -407,9 +403,7 @@ describe('ESLint', () => { expect(output).toContain( 'Error: Comments inside children section of tag should be placed inside braces' ) - expect(output).toContain( - 'Warning: External synchronous scripts are forbidden' - ) + expect(output).toContain('Error: Synchronous scripts should not be used.') }) test('max warnings flag errors when warnings exceed threshold', async () => { @@ -424,10 +418,10 @@ describe('ESLint', () => { expect(stderr).not.toEqual('') expect(stderr).toContain( - 'Warning: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) expect(stdout).not.toContain( - 'Warning: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) }) @@ -443,10 +437,10 @@ describe('ESLint', () => { expect(stderr).toEqual('') expect(stderr).not.toContain( - 'Warning: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) expect(stdout).toContain( - 'Warning: External synchronous scripts are forbidden' + 'Warning: Synchronous scripts should not be used.' ) }) @@ -462,7 +456,7 @@ describe('ESLint', () => { const output = stdout + stderr expect(output).toContain( - 'warning: External synchronous scripts are forbidden' + 'warning: Synchronous scripts should not be used.' ) expect(stdout).toContain('<script src="https://example.com" />') expect(stdout).toContain('2 warnings found') @@ -576,7 +570,7 @@ describe('ESLint', () => { ) expect(output).not.toContain('pages/') - expect(output).not.toContain('External synchronous scripts are forbidden') + expect(output).not.toContain('Synchronous scripts should not be used.') }) test('file flag can selectively lints multiple files', async () => { @@ -598,11 +592,11 @@ describe('ESLint', () => { expect(output).toContain('pages/bar.js') expect(output).toContain( - "Do not use <img>. Use Image from 'next/image' instead" + 'Do not use `<img>` element. Use `<Image />` from `next/image` instead.' ) expect(output).not.toContain('pages/index.js') - expect(output).not.toContain('External synchronous scripts are forbidden') + expect(output).not.toContain('Synchronous scripts should not be used.') }) }) }) From c91b6483d4889fc8e043c9d849902ffc52ba9916 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Fri, 22 Apr 2022 22:16:44 -0500 Subject: [PATCH 15/20] Adds description to `no-before-interactive-script-outside-document` documentation. --- .../no-before-interactive-script-outside-document.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/errors/no-before-interactive-script-outside-document.md b/errors/no-before-interactive-script-outside-document.md index 9ba97c59e805..e40c3f67129c 100644 --- a/errors/no-before-interactive-script-outside-document.md +++ b/errors/no-before-interactive-script-outside-document.md @@ -1,15 +1,17 @@ -# beforeInteractive Script component outside \_document.js +# No Before Interactive Script Outside Document + +> Prevent usage of `next/script`'s `beforeInteractive` strategy outside of `pages/_document.js`. #### Why This Error Occurred -You can't use the `next/script` component with the `beforeInteractive` strategy outside the `_document.js` page. That's because `beforeInteractive` strategy only works inside **\_document.js** and is designed to load scripts that are needed by the entire site (i.e. the script will load when any page in the application has been loaded server-side). +You cannot use the `next/script` component with the `beforeInteractive` strategy outside `pages/_document.js`. That's because `beforeInteractive` strategy only works inside **`pages/_document.js`** and is designed to load scripts that are needed by the entire site (i.e. the script will load when any page in the application has been loaded server-side). #### Possible Ways to Fix It -If you want a global script, move the script inside `_document.js` page. +If you want a global script, move the script inside `pages/_document.js`. ```jsx -// In _document.js +// In `pages/_document.js` import { Html, Head, Main, NextScript } from 'next/document' import Script from 'next/script' From 490e77a4c609577f83a23e73e2c93ce82d2c4c7e Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Thu, 5 May 2022 11:38:11 -0400 Subject: [PATCH 16/20] Removes `link-passhref` from rules list. --- docs/basic-features/eslint.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/basic-features/eslint.md b/docs/basic-features/eslint.md index dc03fd5d19bf..ca5a7df2228e 100644 --- a/docs/basic-features/eslint.md +++ b/docs/basic-features/eslint.md @@ -87,7 +87,6 @@ Next.js provides an ESLint plugin, [`eslint-plugin-next`](https://www.npmjs.com/ | ✔️ | [@next/next/google-font-display](/docs/messages/google-font-display.md) | Enforce font-display behavior with Google Fonts. | | ✔️ | [@next/next/google-font-preconnect](/docs/messages/google-font-preconnect.md) | Ensure `preconnect` is used with Google Fonts. | | ✔️ | [@next/next/inline-script-id](/docs/messages/inline-script-id.md) | Enforce `id` attribute on `next/script` components with inline content. | -| ✔️ | [@next/next/link-passhref](/docs/messages/link-passhref.md) | Ensure `passHref` is used with custom `Link` components. | | ✔️ | [@next/next/next-script-for-ga](/docs/messages/next-script-for-ga.md) | Prefer `next/script` component when using the inline script for Google Analytics. | | ✔️ | [@next/next/no-before-interactive-script-outside-document](/docs/messages/no-before-interactive-script-outside-document.md) | Prevent usage of `next/script`'s `beforeInteractive` strategy outside of `pages/_document.js`. | | ✔️ | [@next/next/no-css-tags](/docs/messages/no-css-tags.md) | Prevent manual stylesheet tags. | From 8093af965a8aa69490e869bf4b65c02d8e1bae81 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Thu, 19 May 2022 17:15:52 -0500 Subject: [PATCH 17/20] Updates remaining `pages/_middleware.js` references. --- docs/basic-features/eslint.md | 2 +- errors/no-server-import-in-page.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/basic-features/eslint.md b/docs/basic-features/eslint.md index ca5a7df2228e..50537ae52ac7 100644 --- a/docs/basic-features/eslint.md +++ b/docs/basic-features/eslint.md @@ -98,7 +98,7 @@ Next.js provides an ESLint plugin, [`eslint-plugin-next`](https://www.npmjs.com/ | ✔️ | [@next/next/no-img-element](/docs/messages/no-img-element.md) | Prevent usage of `<img>` element to prevent layout shift. | | ✔️ | [@next/next/no-page-custom-font](/docs/messages/no-page-custom-font.md) | Prevent page-only custom fonts. | | ✔️ | [@next/next/no-script-component-in-head](/docs/messages/no-script-component-in-head.md) | Prevent usage of `next/script` in `next/head` component. | -| ✔️ | [@next/next/no-server-import-in-page](/docs/messages/no-server-import-in-page.md) | Prevent usage of `next/server` outside of `pages/_middleware.js`. | +| ✔️ | [@next/next/no-server-import-in-page](/docs/messages/no-server-import-in-page.md) | Prevent usage of `next/server` outside of `middleware.js`. | | ✔️ | [@next/next/no-sync-scripts](/docs/messages/no-sync-scripts.md) | Prevent synchronous scripts. | | ✔️ | [@next/next/no-title-in-document-head](/docs/messages/no-title-in-document-head.md) | Prevent usage of `<title>` with `Head` component from `next/document`. | | ✔️ | @next/next/no-typos | Prevent common typos in [Next.js's data fetching functions](/docs/basic-features/data-fetching.md) | diff --git a/errors/no-server-import-in-page.md b/errors/no-server-import-in-page.md index 7cb7d19d12d5..84a1c3e75759 100644 --- a/errors/no-server-import-in-page.md +++ b/errors/no-server-import-in-page.md @@ -1,6 +1,6 @@ # No Server Import In Page -> Prevent usage of `next/server` outside of `pages/_middleware.js`. +> Prevent usage of `next/server` outside of `middleware.js`. ### Why This Error Occurred From 0acdf1b1d47b69fcab6005ea8304b97c6c2e7bb4 Mon Sep 17 00:00:00 2001 From: Michael Novotny <manovotny@gmail.com> Date: Mon, 23 May 2022 12:57:23 -0500 Subject: [PATCH 18/20] Adds consistancy to messaging in new `no-styled-jsx-in-document` rule. --- errors/no-styled-jsx-in-document.md | 2 ++ .../lib/rules/no-styled-jsx-in-document.js | 8 +++++--- .../eslint-plugin-next/no-styled-jsx-in-document.test.ts | 9 ++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/errors/no-styled-jsx-in-document.md b/errors/no-styled-jsx-in-document.md index 4c9dbf613338..e7660d73cbb3 100644 --- a/errors/no-styled-jsx-in-document.md +++ b/errors/no-styled-jsx-in-document.md @@ -1,5 +1,7 @@ # No styled-jsx in Document +> Prevent usage of `styled-jsx` in `pages/_document.js`. + ### Why This Error Occurred Custom CSS like `styled-jsx` is not allowed in a [Custom Document](https://nextjs.org/docs/advanced-features/custom-document). diff --git a/packages/eslint-plugin-next/lib/rules/no-styled-jsx-in-document.js b/packages/eslint-plugin-next/lib/rules/no-styled-jsx-in-document.js index 5851c80cb1e8..0b0efea0e0e0 100644 --- a/packages/eslint-plugin-next/lib/rules/no-styled-jsx-in-document.js +++ b/packages/eslint-plugin-next/lib/rules/no-styled-jsx-in-document.js @@ -1,11 +1,13 @@ const path = require('path') +const url = 'https://nextjs.org/docs/messages/no-styled-jsx-in-document' + module.exports = { meta: { docs: { - description: 'Disallow using custom styled-jsx inside pages/_document.js', + description: 'Prevent usage of `styled-jsx` in `pages/_document.js`.', recommended: true, - url: 'https://nextjs.org/docs/messages/no-styled-jsx-in-document', + url, }, fixable: 'code', }, @@ -35,7 +37,7 @@ module.exports = { ) { context.report({ node, - message: `styled-jsx can not be used inside pages/_document.js. See https://nextjs.org/docs/messages/no-styled-jsx-in-document.`, + message: `\`styled-jsx\` should not be used in \`pages/_document.js\`. See: ${url}`, }) } }, diff --git a/test/unit/eslint-plugin-next/no-styled-jsx-in-document.test.ts b/test/unit/eslint-plugin-next/no-styled-jsx-in-document.test.ts index b6cce7043dbe..5a91d5f0bafd 100644 --- a/test/unit/eslint-plugin-next/no-styled-jsx-in-document.test.ts +++ b/test/unit/eslint-plugin-next/no-styled-jsx-in-document.test.ts @@ -23,7 +23,7 @@ ruleTester.run('no-styled-jsx-in-document', rule, { const initialProps = await Document.getInitialProps(ctx) return { ...initialProps } } - + render() { return ( <Html> @@ -46,7 +46,7 @@ ruleTester.run('no-styled-jsx-in-document', rule, { const initialProps = await Document.getInitialProps(ctx) return { ...initialProps } } - + render() { return ( <Html> @@ -96,7 +96,7 @@ ruleTester.run('no-styled-jsx-in-document', rule, { const initialProps = await Document.getInitialProps(ctx) return { ...initialProps } } - + render() { return ( <Html> @@ -116,8 +116,7 @@ ruleTester.run('no-styled-jsx-in-document', rule, { }`, errors: [ { - message: - 'styled-jsx can not be used inside pages/_document.js. See https://nextjs.org/docs/messages/no-styled-jsx-in-document.', + message: `\`styled-jsx\` should not be used in \`pages/_document.js\`. See: https://nextjs.org/docs/messages/no-styled-jsx-in-document`, }, ], }, From 057806521efbaf16376dc0b1d4282e8a69b71293 Mon Sep 17 00:00:00 2001 From: JJ Kasper <jj@jjsweb.site> Date: Mon, 13 Jun 2022 20:46:51 -0500 Subject: [PATCH 19/20] Apply suggestions from code review --- errors/google-font-display.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/errors/google-font-display.md b/errors/google-font-display.md index 16088335c29c..bd01159cba2e 100644 --- a/errors/google-font-display.md +++ b/errors/google-font-display.md @@ -31,10 +31,10 @@ Specifying `display=optional` minimizes the risk of invisible text or layout shi ### When Not To Use It -If you want to specifically display a font using a `auto, `block`, or `fallback` strategy, then you can disable this rule. +If you want to specifically display a font using an `auto`, `block`, or `fallback` strategy, then you can disable this rule. ### Useful Links -- [Controlling Font Performance with font-display](https://developers.google.com/web/updates/2016/02/font-display) +- [Controlling Font Performance with font-display](https://developer.chrome.com/blog/font-display/) - [Google Fonts API Docs](https://developers.google.com/fonts/docs/css2#use_font-display) - [CSS `font-display` property](https://www.w3.org/TR/css-fonts-4/#font-display-desc) From 031ba7029649b5e7ae324868f9734cccc6046c7d Mon Sep 17 00:00:00 2001 From: JJ Kasper <jj@jjsweb.site> Date: Mon, 13 Jun 2022 20:49:27 -0500 Subject: [PATCH 20/20] Apply suggestions from code review --- errors/manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/errors/manifest.json b/errors/manifest.json index 505c9b42bbaf..4205dc491e8f 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -565,7 +565,7 @@ { "path": "/errors/no-script-in-document-page.md", "redirect": { - "destination": "/errors/no-script-in-document.md" + "destination": "/errors/no-script-in-document" } }, { @@ -579,13 +579,13 @@ { "path": "/errors/no-script-in-head-component.md", "redirect": { - "destination": "/errors/no-script-component-in-head.md" + "destination": "/errors/no-script-component-in-head" } }, { "path": "/errors/no-script-component-in-head-component.md", "redirect": { - "destination": "/errors/no-script-component-in-head.md" + "destination": "/errors/no-script-component-in-head" } }, {