Skip to content

Commit

Permalink
Add eslint rule to prevent importing next/server outside of _middlewa…
Browse files Browse the repository at this point in the history
…re (#30973)

* Add eslint rule to prevent importing next/server outside of _middleware

* add error to manifest.json

Co-authored-by: Javi Velasco <javier.velasco86@gmail.com>
  • Loading branch information
thibautsabot and javivelasco committed Nov 12, 2021
1 parent 4a22059 commit d1adf1d
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 0 deletions.
4 changes: 4 additions & 0 deletions errors/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@
"title": "no-router-instance",
"path": "/errors/no-router-instance.md"
},
{
"title": "no-server-import-in-page",
"path": "/errors/no-server-import-in-page.md"
},
{
"title": "no-sync-scripts",
"path": "/errors/no-sync-scripts.md"
Expand Down
23 changes: 23 additions & 0 deletions errors/no-server-import-in-page.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# No Server Import In Page

### Why This Error Occurred

`next/server` was imported in a page outside of `pages/_middleware.js` (or `pages/_middleware.tsx` if you are using TypeScript)

### Possible Ways to Fix It

Only import and use `next/server` within `pages/_middleware.js` (or `pages/_middleware.tsx`) to add middlewares.

```jsx
// pages/_middleware.ts

import type { NextFetchEvent, NextRequest } from 'next/server'

export function middleware(req: NextRequest, ev: NextFetchEvent) {
return new Response('Hello, world!')
}
```

### Useful Links

- [Middleware](https://nextjs.org/docs/middleware)
37 changes: 37 additions & 0 deletions packages/eslint-plugin-next/lib/rules/no-server-import-in-page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const path = require('path')

module.exports = {
meta: {
docs: {
description:
'Disallow importing next/server outside of pages/_middleware.js',
recommended: true,
url: 'https://nextjs.org/docs/messages/no-server-import-in-page',
},
},
create: function (context) {
return {
ImportDeclaration(node) {
if (node.source.value !== 'next/server') {
return
}

const paths = context.getFilename().split('pages')
const page = paths[paths.length - 1]

if (
!page ||
page.startsWith(`${path.sep}_middleware`) ||
page.startsWith(`${path.posix.sep}_middleware`)
) {
return
}

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.`,
})
},
}
},
}
126 changes: 126 additions & 0 deletions test/unit/eslint-plugin-next/no-server-import-in-page.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { RuleTester } from 'eslint'
import path from 'path'
import rule from '@next/eslint-plugin-next/lib/rules/no-server-import-in-page'
;(RuleTester as any).setDefaultConfig({
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
modules: true,
jsx: true,
},
},
})
const ruleTester = new RuleTester()

ruleTester.run('no-server-import-in-page', rule, {
valid: [
{
code: `import { NextFetchEvent, NextRequest } from "next/server"
export function middleware(req, ev) {
return new Response('Hello, world!')
}
`,
filename: 'pages/_middleware.js',
},
{
code: `import { NextFetchEvent, NextRequest } from "next/server"
export function middleware(req, ev) {
return new Response('Hello, world!')
}
`,
filename: `pages${path.sep}_middleware.js`,
},
{
code: `import NextDocument from "next/document"
export function middleware(req, ev) {
return new Response('Hello, world!')
}
`,
filename: `pages${path.posix.sep}_middleware.tsx`,
},
{
code: `import { NextFetchEvent, NextRequest } from "next/server"
export function middleware(req, ev) {
return new Response('Hello, world!')
}
`,
filename: 'pages/_middleware.page.tsx',
},
{
code: `import { NextFetchEvent, NextRequest } from "next/server"
export function middleware(req, ev) {
return new Response('Hello, world!')
}
`,
filename: 'pages/_middleware/index.js',
},
{
code: `import { NextFetchEvent, NextRequest } from "next/server"
export function middleware(req, ev) {
return new Response('Hello, world!')
}
`,
filename: 'pages/_middleware/index.tsx',
},
{
code: `import { NextFetchEvent, NextRequest } from "next/server"
export function middleware(req, ev) {
return new Response('Hello, world!')
}
`,
filename: 'pagesapp/src/pages/_middleware.js',
},
],
invalid: [
{
code: `import { NextFetchEvent, NextRequest } from "next/server"
export const Test = () => <p>Test</p>
`,
filename: 'components/test.js',
errors: [
{
message:
'next/server should not be imported outside of pages/_middleware.js. See https://nextjs.org/docs/messages/no-server-import-in-page.',
type: 'ImportDeclaration',
},
],
},
{
code: `import { NextFetchEvent, NextRequest } from "next/server"
export const Test = () => <p>Test</p>
`,
filename: 'pages/test.js',
errors: [
{
message:
'next/server should not be imported outside of pages/_middleware.js. See https://nextjs.org/docs/messages/no-server-import-in-page.',
type: 'ImportDeclaration',
},
],
},
{
code: `import { NextFetchEvent, NextRequest } from "next/server"
export const Test = () => <p>Test</p>
`,
filename: `pages${path.sep}test.js`,
errors: [
{
message:
'next/server should not be imported outside of pages/_middleware.js. See https://nextjs.org/docs/messages/no-server-import-in-page.',
type: 'ImportDeclaration',
},
],
},
],
})

0 comments on commit d1adf1d

Please sign in to comment.