-
Notifications
You must be signed in to change notification settings - Fork 26.7k
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 not allowing styled-jsx in _document.js (#32678)
## Bug - [ ] Related issues linked fixes #32656 Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
- Loading branch information
Showing
6 changed files
with
219 additions
and
0 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,41 @@ | ||
# No styled-jsx in Document | ||
|
||
### Why This Error Occurred | ||
|
||
Custom CSS like `styled-jsx` is not allowed in a [Custom Document](https://nextjs.org/docs/advanced-features/custom-document). | ||
|
||
### Possible Ways to Fix It | ||
|
||
If you need shared CSS for all of your pages, take a look at the [Custom `App`](https://nextjs.org/docs/advanced-features/custom-app) file or define a custom layout. | ||
|
||
For example, consider the following stylesheet named `styles.css`: | ||
|
||
```css | ||
body { | ||
font-family: 'SF Pro Text', 'SF Pro Icons', 'Helvetica Neue', 'Helvetica', | ||
'Arial', sans-serif; | ||
padding: 20px 20px 60px; | ||
max-width: 680px; | ||
margin: 0 auto; | ||
} | ||
``` | ||
|
||
Create a `pages/_app.{js,tsx}` file if not already present. Then, import the `styles.css` file. | ||
|
||
```jsx | ||
import '../styles.css' | ||
|
||
// This default export is required in a new `pages/_app.js` file. | ||
export default function MyApp({ Component, pageProps }) { | ||
return <Component {...pageProps} /> | ||
} | ||
``` | ||
|
||
These styles (`styles.css`) will apply to all pages and components in your application. | ||
|
||
### Useful links | ||
|
||
- [Custom Document Caveats](https://nextjs.org/docs/advanced-features/custom-document#caveats) | ||
- [Layouts](https://nextjs.org/docs/basic-features/layouts) | ||
- [Built in CSS Support](https://nextjs.org/docs/basic-features/built-in-css-support) | ||
- [Custom `App`](https://nextjs.org/docs/advanced-features/custom-app) |
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
46 changes: 46 additions & 0 deletions
46
packages/eslint-plugin-next/lib/rules/no-styled-jsx-in-document.js
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,46 @@ | ||
const path = require('path') | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: 'Disallow using custom styled-jsx inside pages/_document.js', | ||
recommended: true, | ||
url: 'https://nextjs.org/docs/messages/no-styled-jsx-in-document', | ||
}, | ||
fixable: 'code', | ||
}, | ||
create: function (context) { | ||
return { | ||
JSXOpeningElement(node) { | ||
const document = context.getFilename().split('pages')[1] | ||
if (!document) { | ||
return | ||
} | ||
const { name, dir } = path.parse(document) | ||
|
||
if ( | ||
!( | ||
name.startsWith('_document') || | ||
(dir === '/_document' && name === 'index') | ||
) | ||
) { | ||
return | ||
} | ||
|
||
if ( | ||
node.name.name === 'style' && | ||
node.attributes.find( | ||
(attr) => attr.type === 'JSXAttribute' && attr.name.name === 'jsx' | ||
) | ||
) { | ||
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.`, | ||
}) | ||
} | ||
}, | ||
} | ||
}, | ||
} | ||
|
||
module.exports.schema = [] |
125 changes: 125 additions & 0 deletions
125
test/unit/eslint-plugin-next/no-styled-jsx-in-document.test.ts
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,125 @@ | ||
import rule from '@next/eslint-plugin-next/lib/rules/no-styled-jsx-in-document' | ||
import { RuleTester } from 'eslint' | ||
;(RuleTester as any).setDefaultConfig({ | ||
parserOptions: { | ||
ecmaVersion: 2018, | ||
sourceType: 'module', | ||
ecmaFeatures: { | ||
modules: true, | ||
jsx: true, | ||
}, | ||
}, | ||
}) | ||
const ruleTester = new RuleTester() | ||
|
||
ruleTester.run('no-styled-jsx-in-document', rule, { | ||
valid: [ | ||
{ | ||
filename: 'pages/_document.js', | ||
code: `import Document, { Html, Head, Main, NextScript } from 'next/document' | ||
export class MyDocument extends Document { | ||
static async getInitialProps(ctx) { | ||
const initialProps = await Document.getInitialProps(ctx) | ||
return { ...initialProps } | ||
} | ||
render() { | ||
return ( | ||
<Html> | ||
<Head /> | ||
<body> | ||
<Main /> | ||
<NextScript /> | ||
</body> | ||
</Html> | ||
) | ||
} | ||
}`, | ||
}, | ||
{ | ||
filename: 'pages/_document.js', | ||
code: `import Document, { Html, Head, Main, NextScript } from 'next/document' | ||
export class MyDocument extends Document { | ||
static async getInitialProps(ctx) { | ||
const initialProps = await Document.getInitialProps(ctx) | ||
return { ...initialProps } | ||
} | ||
render() { | ||
return ( | ||
<Html> | ||
<Head /> | ||
<style>{"\ | ||
body{\ | ||
color:red;\ | ||
}\ | ||
"}</style> | ||
<style {...{nonce: '123' }}></style> | ||
<body> | ||
<Main /> | ||
<NextScript /> | ||
</body> | ||
</Html> | ||
) | ||
} | ||
}`, | ||
}, | ||
{ | ||
filename: 'pages/index.js', | ||
code: ` | ||
export default function Page() { | ||
return ( | ||
<> | ||
<p>Hello world</p> | ||
<style jsx>{\` | ||
p { | ||
color: orange; | ||
} | ||
\`}</style> | ||
</> | ||
) | ||
} | ||
`, | ||
}, | ||
], | ||
|
||
invalid: [ | ||
{ | ||
filename: 'pages/_document.js', | ||
code: ` | ||
import Document, { Html, Head, Main, NextScript } from 'next/document' | ||
export class MyDocument extends Document { | ||
static async getInitialProps(ctx) { | ||
const initialProps = await Document.getInitialProps(ctx) | ||
return { ...initialProps } | ||
} | ||
render() { | ||
return ( | ||
<Html> | ||
<Head /> | ||
<style jsx>{"\ | ||
body{\ | ||
color:red;\ | ||
}\ | ||
"}</style> | ||
<body> | ||
<Main /> | ||
<NextScript /> | ||
</body> | ||
</Html> | ||
) | ||
} | ||
}`, | ||
errors: [ | ||
{ | ||
message: | ||
'styled-jsx can not be used inside pages/_document.js. See https://nextjs.org/docs/messages/no-styled-jsx-in-document.', | ||
}, | ||
], | ||
}, | ||
], | ||
}) |