diff --git a/errors/import-next.md b/errors/import-next.md new file mode 100644 index 000000000000000..4c9aa89f6a551da --- /dev/null +++ b/errors/import-next.md @@ -0,0 +1,17 @@ +# Invalid "next" Import + +#### Why This Error Occurred + +Somewhere in your application, you imported `next` directly which is only meant to be used with legacy custom servers. + +You should not import `next` inside of pages or components. + +#### Possible Ways to Fix It + +Ensure any usage of `import next from "next"` is specific to custom server usage and isn't included in your pages or components. + +Also ensure any type imports are kept inside of TypeScript files e.g. ensure `import { PageConfig } from 'next'` isn't used in JavaScript files. + +### Useful Links + +- [Custom Server Documentation](https://nextjs.org/docs/advanced-features/custom-server) diff --git a/errors/manifest.json b/errors/manifest.json index ae234227e64723d..6ac9cdfca23f19c 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -641,6 +641,10 @@ { "title": "client-flush-effects", "path": "/errors/client-flush-effects.md" + }, + { + "title": "import-next", + "path": "/errors/import-next.md" } ] } diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 2e058db57250116..5e8dd5048ca267d 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -841,6 +841,12 @@ export default async function getBaseWebpackConfig( // absolute paths. (process.platform === 'win32' && path.win32.isAbsolute(request)) + // make sure import "next" shows a warning when imported + // in pages/components + if (request === 'next') { + return `commonjs next/dist/lib/import-next-warning` + } + // Relative requires don't need custom resolution, because they // are relative to requests we've already resolved here. // Absolute requires (require('/foo')) are extremely uncommon, but diff --git a/packages/next/lib/import-next-warning.ts b/packages/next/lib/import-next-warning.ts new file mode 100644 index 000000000000000..d3a3f8358d76124 --- /dev/null +++ b/packages/next/lib/import-next-warning.ts @@ -0,0 +1,5 @@ +import * as Log from '../build/output/log' + +Log.warn( + `"next" should not be imported directly, imported in ${module.parent?.filename}\nSee more info here: https://nextjs.org/docs/messages/import-next` +) diff --git a/test/production/required-server-files.test.ts b/test/production/required-server-files.test.ts index 7acbe9f022852db..b9fe52eab61774d 100644 --- a/test/production/required-server-files.test.ts +++ b/test/production/required-server-files.test.ts @@ -19,6 +19,7 @@ describe('should set-up next', () => { let server let appPort let errors = [] + let stderr = '' let requiredFilesManifest beforeAll(async () => { @@ -109,6 +110,7 @@ describe('should set-up next', () => { if (msg.includes('top-level')) { errors.push(msg) } + stderr += msg }, } ) @@ -118,6 +120,14 @@ describe('should set-up next', () => { if (server) await killApp(server) }) + it('should warn when "next" is imported directly', async () => { + await renderViaHTTP(appPort, '/gssp') + await check( + () => stderr, + /"next" should not be imported directly, imported in/ + ) + }) + it('`compress` should be `true` by default', async () => { expect( await fs.readFileSync(join(next.testDir, 'standalone/server.js'), 'utf8') diff --git a/test/production/required-server-files/pages/gssp.js b/test/production/required-server-files/pages/gssp.js index 625cfb7c5138642..a7c8b1be1428d1d 100644 --- a/test/production/required-server-files/pages/gssp.js +++ b/test/production/required-server-files/pages/gssp.js @@ -1,5 +1,7 @@ import fs from 'fs' import path from 'path' +// eslint-disable-next-line +import next from 'next' // force a warning during `next build` import { useRouter } from 'next/router' export async function getServerSideProps({ res }) {