diff --git a/packages/next/src/build/handle-externals.ts b/packages/next/src/build/handle-externals.ts index 36d203f1f6981..a52f9dea1a021 100644 --- a/packages/next/src/build/handle-externals.ts +++ b/packages/next/src/build/handle-externals.ts @@ -372,7 +372,8 @@ export function makeExternalHandler({ config.transpilePackages, resolvedExternalPackageDirs ) || - (isEsm && isAppLayer) + (isEsm && isAppLayer) || + (!isAppLayer && config.experimental.bundlePagesExternals) if (/node_modules[/\\].*\.[mc]?js$/.test(res)) { if (isWebpackServerLayer(layer)) { diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index 5c6a3834172c1..565bfd4d65350 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -520,6 +520,9 @@ const configSchema = { serverSourceMaps: { type: 'boolean', }, + bundlePagesExternals: { + type: 'boolean', + }, }, type: 'object', }, diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 3c3c46690e10c..a304452f462ca 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -330,6 +330,10 @@ export interface ExperimentalConfig { * @internal Used by the Next.js internals only. */ trustHostHeader?: boolean + /** + * Enables the bundling of node_modules packages (externals) for pages server-side bundles. + */ + bundlePagesExternals?: boolean } export type ExportPathMap = { @@ -769,6 +773,7 @@ export const defaultConfig: NextConfig = { turbotrace: undefined, typedRoutes: false, instrumentationHook: false, + bundlePagesExternals: false, }, } diff --git a/test/integration/externals-pages-bundle/next.config.js b/test/integration/externals-pages-bundle/next.config.js new file mode 100644 index 0000000000000..fa42806a761b9 --- /dev/null +++ b/test/integration/externals-pages-bundle/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + experimental: { + bundlePagesExternals: true, + }, +} diff --git a/test/integration/externals-pages-bundle/node_modules/external-package/index.js b/test/integration/externals-pages-bundle/node_modules/external-package/index.js new file mode 100644 index 0000000000000..ca285d93526b1 --- /dev/null +++ b/test/integration/externals-pages-bundle/node_modules/external-package/index.js @@ -0,0 +1,3 @@ +module.exports = { + foo: 'bar', +} diff --git a/test/integration/externals-pages-bundle/node_modules/external-package/package.json b/test/integration/externals-pages-bundle/node_modules/external-package/package.json new file mode 100644 index 0000000000000..6ae6da1a7ada2 --- /dev/null +++ b/test/integration/externals-pages-bundle/node_modules/external-package/package.json @@ -0,0 +1,6 @@ +{ + "name": "external-package", + "version": "1.0.0", + "description": "External package", + "main": "index.js" +} diff --git a/test/integration/externals-pages-bundle/pages/index.js b/test/integration/externals-pages-bundle/pages/index.js new file mode 100644 index 0000000000000..5816c0c3377e1 --- /dev/null +++ b/test/integration/externals-pages-bundle/pages/index.js @@ -0,0 +1,13 @@ +import { foo } from 'external-package' + +export async function getServerSideProps() { + return { + props: { + foo, + }, + } +} + +export default function Index({ foo }) { + return
{foo}
+} diff --git a/test/integration/externals-pages-bundle/test/index.test.js b/test/integration/externals-pages-bundle/test/index.test.js new file mode 100644 index 0000000000000..9ada207985f70 --- /dev/null +++ b/test/integration/externals-pages-bundle/test/index.test.js @@ -0,0 +1,18 @@ +/* eslint-env jest */ + +import fs from 'fs-extra' +import { join } from 'path' +import { nextBuild } from 'next-test-utils' + +const appDir = join(__dirname, '../') + +describe('bundle pages externals with config.experimental.bundlePagesExternals', () => { + it('should have no externals with the config set', async () => { + await nextBuild(appDir, [], { stdout: true }) + const output = await fs.readFile( + join(appDir, '.next/server/pages/index.js'), + 'utf8' + ) + expect(output).not.toContain('require("external-package")') + }) +})