forked from vercel/next.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add eslint rule for id attribute on inline next/script (vercel#27853)
This adds a new ESLint rule to `eslint-plugin-next` to check that `next/script` components with inline content have the required `id` attribute. Also adjusted the code example for inline scripts in the `next/script` docs, which were actually missing an `id` attribute. And also updated the `next/scripts` integration test to also have the required `id` attribute. Unsure about the required heading levels in the errors .md document (other examples have h1 and h4??) ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [x] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [x] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes
- Loading branch information
1 parent
52b858a
commit da4203d
Showing
10 changed files
with
250 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# next/script components with inline content require an `id` attribute | ||
|
||
## Why This Error Occurred | ||
|
||
`next/script` components with inline content require an `id` attribute to be defined to track and optimize the script. | ||
|
||
## Possible Ways to Fix It | ||
|
||
Add an `id` attribute to the `next/script` component. | ||
|
||
```jsx | ||
import Script from 'next/script' | ||
|
||
export default function App({ Component, pageProps }) { | ||
return ( | ||
<> | ||
<Script id="my-script">{`console.log('Hello world!');`}</Script> | ||
<Component {...pageProps} /> | ||
</> | ||
) | ||
} | ||
``` | ||
|
||
## Useful links | ||
|
||
- [Docs for Next.js Script component](https://nextjs.org/docs/basic-features/script) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: | ||
'next/script components with inline content must specify an `id` attribute.', | ||
recommended: true, | ||
}, | ||
}, | ||
create: function (context) { | ||
let nextScriptImportName = null | ||
|
||
return { | ||
ImportDeclaration(node) { | ||
if (node.source.value === 'next/script') { | ||
nextScriptImportName = node.specifiers[0].local.name | ||
} | ||
}, | ||
JSXElement(node) { | ||
if (nextScriptImportName == null) return | ||
|
||
if ( | ||
node.openingElement && | ||
node.openingElement.name && | ||
node.openingElement.name.name !== nextScriptImportName | ||
) { | ||
return | ||
} | ||
|
||
const attributes = node.openingElement.attributes | ||
|
||
if ( | ||
node.children.length > 0 || | ||
attributes.some( | ||
(attribute) => attribute.name.name === 'dangerouslySetInnerHTML' | ||
) | ||
) { | ||
if (!attributes.some((attribute) => attribute.name.name === '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', | ||
}) | ||
} | ||
} | ||
}, | ||
} | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
const rule = require('@next/eslint-plugin-next/lib/rules/inline-script-id') | ||
|
||
const RuleTester = require('eslint').RuleTester | ||
|
||
RuleTester.setDefaultConfig({ | ||
parserOptions: { | ||
ecmaVersion: 2018, | ||
sourceType: 'module', | ||
ecmaFeatures: { | ||
modules: true, | ||
jsx: true, | ||
}, | ||
}, | ||
}) | ||
|
||
const errorMessage = | ||
'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, { | ||
valid: [ | ||
{ | ||
code: `import Script from 'next/script'; | ||
export default function TestPage() { | ||
return ( | ||
<Script id="test-script"> | ||
{\`console.log('Hello world');\`} | ||
</Script> | ||
) | ||
}`, | ||
}, | ||
{ | ||
code: `import Script from 'next/script'; | ||
export default function TestPage() { | ||
return ( | ||
<Script | ||
id="test-script" | ||
dangerouslySetInnerHTML={{ | ||
__html: \`console.log('Hello world');\` | ||
}} | ||
/> | ||
) | ||
}`, | ||
}, | ||
{ | ||
code: `import Script from 'next/script'; | ||
export default function TestPage() { | ||
return ( | ||
<Script src="https://example.com" /> | ||
) | ||
}`, | ||
}, | ||
{ | ||
code: `import MyScript from 'next/script'; | ||
export default function TestPage() { | ||
return ( | ||
<MyScript id="test-script"> | ||
{\`console.log('Hello world');\`} | ||
</MyScript> | ||
) | ||
}`, | ||
}, | ||
{ | ||
code: `import MyScript from 'next/script'; | ||
export default function TestPage() { | ||
return ( | ||
<MyScript | ||
id="test-script" | ||
dangerouslySetInnerHTML={{ | ||
__html: \`console.log('Hello world');\` | ||
}} | ||
/> | ||
) | ||
}`, | ||
}, | ||
], | ||
invalid: [ | ||
{ | ||
code: `import Script from 'next/script'; | ||
export default function TestPage() { | ||
return ( | ||
<Script> | ||
{\`console.log('Hello world');\`} | ||
</Script> | ||
) | ||
}`, | ||
errors: [ | ||
{ | ||
message: errorMessage, | ||
type: 'JSXElement', | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import Script from 'next/script'; | ||
export default function TestPage() { | ||
return ( | ||
<Script | ||
dangerouslySetInnerHTML={{ | ||
__html: \`console.log('Hello world');\` | ||
}} | ||
/> | ||
) | ||
}`, | ||
errors: [ | ||
{ | ||
message: errorMessage, | ||
type: 'JSXElement', | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import MyScript from 'next/script'; | ||
export default function TestPage() { | ||
return ( | ||
<MyScript> | ||
{\`console.log('Hello world');\`} | ||
</MyScript> | ||
) | ||
}`, | ||
errors: [ | ||
{ | ||
message: errorMessage, | ||
type: 'JSXElement', | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `import MyScript from 'next/script'; | ||
export default function TestPage() { | ||
return ( | ||
<MyScript | ||
dangerouslySetInnerHTML={{ | ||
__html: \`console.log('Hello world');\` | ||
}} | ||
/> | ||
) | ||
}`, | ||
errors: [ | ||
{ | ||
message: errorMessage, | ||
type: 'JSXElement', | ||
}, | ||
], | ||
}, | ||
], | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters