eslint rule for script strategy should work properly in app/ (#46609)

fixes https://github.com/vercel/next.js/issues/46549

The docs are wrong for now, this limitation is just in `pages/`, you can
use it anywhere in `app/`.

Since `app/` is still not stable we will emit that warning in all files
outside of `app/`.
This commit is contained in:
Jan Kaifer 2023-03-08 11:28:52 +01:00 committed by GitHub
parent bfc3849b1f
commit 8b50b80cde
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 2 deletions

View file

@ -4,6 +4,11 @@ import * as path from 'path'
const url =
'https://nextjs.org/docs/messages/no-before-interactive-script-outside-document'
const startsWithUsingCorrectSeparators = (str: string, start: string) =>
[path.sep, path.posix.sep].some((sep) =>
str.startsWith(start.replace(/\//g, sep))
)
export = defineRule({
meta: {
docs: {
@ -25,6 +30,17 @@ export = defineRule({
scriptImportName = node.local.name
},
JSXOpeningElement(node) {
let pathname = context.getFilename()
if (startsWithUsingCorrectSeparators(pathname, 'src/')) {
pathname = pathname.slice(4)
}
// This rule shouldn't fire in `app/`
if (startsWithUsingCorrectSeparators(pathname, 'app/')) {
return
}
if (!scriptImportName) {
return
}

View file

@ -103,7 +103,72 @@ ruleTester.run('no-before-interactive-script-outside-document', rule, {
`,
filename: 'pages/_document.tsx',
},
],
{
code: `
import Script from "next/script";
export default function Index() {
return (
<Script
id="scriptBeforeInteractive"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforeInteractive"
strategy="beforeInteractive"
></Script>
);
}`,
filename: 'app/deep/root/layout.tsx',
},
{
code: `
import Script from "next/script";
export default function Index() {
return (
<Script
id="scriptBeforeInteractive"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforeInteractive"
strategy="beforeInteractive"
></Script>
);
}`,
filename: 'app/deep/page.tsx',
},
{
code: `
import Script from "next/script";
export default function Index() {
return (
<Script
id="scriptBeforeInteractive"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforeInteractive"
strategy="beforeInteractive"
></Script>
);
}`,
filename: 'app/deep/randomFile.tsx',
},
{
code: `
import Script from "next/script";
export default function Index() {
return (
<Script
id="scriptBeforeInteractive"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforeInteractive"
strategy="beforeInteractive"
></Script>
);
}`,
filename: 'src/app/deep/randomFile.tsx',
},
].map((obj, idx) => ({
...obj,
code: `// valid-${idx}
${obj.code}
`,
})),
invalid: [
{
@ -128,5 +193,32 @@ ruleTester.run('no-before-interactive-script-outside-document', rule, {
},
],
},
],
{
code: `
import Head from "next/head";
import Script from "next/script";
export default function Index() {
return (
<Script
id="scriptBeforeInteractive"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js?a=scriptBeforeInteractive"
strategy="beforeInteractive"
></Script>
);
}`,
filename: 'components/outside-known-dirs.js',
errors: [
{
message:
"`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",
},
],
},
].map((obj, idx) => ({
...obj,
code: `// invalid-${idx}
${obj.code}
`,
})),
})