misc: fix serverComponentsExternalPackages usage for experimental.bundlePagesExternals (#57954)

This PR fixes a bug where Next.js would not use the serverComponentsExternalPackages config when opting into the `experimental.bundlePagesExternals` flag.

The fix consists of just adding a check for the externals config.
This commit is contained in:
Jimmy Lai
2023-11-02 23:57:52 +00:00
committed by GitHub
parent 8014866cac
commit 82d1b57721
6 changed files with 39 additions and 22 deletions
+10 -19
View File
@@ -22,6 +22,8 @@ const externalPattern = new RegExp(
`${nextDist}${optionalEsmPart}.*${externalFileEnd}`
)
const nodeModulesRegex = /node_modules[/\\].*\.[mc]?js$/
export function isResourceInPackages(
resource: string,
packageNames?: string[],
@@ -355,9 +357,6 @@ export function makeExternalHandler({
}
}
// If a package is included in `transpilePackages`, we don't want to make it external.
// And also, if that resource is an ES module, we bundle it too because we can't
// rely on the require hook to alias `react` to our precompiled version.
const shouldBeBundled =
isResourceInPackages(
res,
@@ -367,27 +366,19 @@ export function makeExternalHandler({
(isEsm && isAppLayer) ||
(!isAppLayer && config.experimental.bundlePagesExternals)
if (/node_modules[/\\].*\.[mc]?js$/.test(res)) {
if (nodeModulesRegex.test(res)) {
if (isWebpackServerLayer(layer)) {
// All packages should be bundled for the server layer if they're not opted out.
// This option takes priority over the transpilePackages option.
if (optOutBundlingPackageRegex.test(res)) {
return `${externalType} ${request}`
if (!optOutBundlingPackageRegex.test(res)) {
return // Bundle for server layer
}
return
return `${externalType} ${request}` // Externalize if opted out
}
if (shouldBeBundled) return
// Anything else that is standard JavaScript within `node_modules`
// can be externalized.
return `${externalType} ${request}`
if (!shouldBeBundled || optOutBundlingPackageRegex.test(res)) {
return `${externalType} ${request}` // Externalize if not bundled or opted out
}
}
if (shouldBeBundled) return
// Default behavior: bundle the code!
// if here, we default to bundling the file
}
}
@@ -1,5 +1,6 @@
module.exports = {
experimental: {
bundlePagesExternals: true,
serverComponentsExternalPackages: ['opted-out-external-package'],
},
}
@@ -0,0 +1,3 @@
module.exports = {
bar: 'baz',
}
@@ -0,0 +1,6 @@
{
"name": "opted-out-external-package",
"version": "1.0.0",
"description": "External package",
"main": "index.js"
}
@@ -1,13 +1,19 @@
import { foo } from 'external-package'
import { bar } from 'opted-out-external-package'
export async function getServerSideProps() {
return {
props: {
foo,
bar,
},
}
}
export default function Index({ foo }) {
return <div>{foo}</div>
return (
<div>
{foo}
{bar}
</div>
)
}
@@ -8,13 +8,23 @@ const appDir = join(__dirname, '../')
describe('bundle pages externals with config.experimental.bundlePagesExternals', () => {
;(process.env.TURBOPACK ? describe.skip : describe)('production mode', () => {
it('should have no externals with the config set', async () => {
beforeAll(async () => {
await nextBuild(appDir, [], { stdout: true })
})
it('should have no externals with the config set', async () => {
const output = await fs.readFile(
join(appDir, '.next/server/pages/index.js'),
'utf8'
)
expect(output).not.toContain('require("external-package")')
})
it('should respect the serverComponentsExternals config', async () => {
const output = await fs.readFile(
join(appDir, '.next/server/pages/index.js'),
'utf8'
)
expect(output).toContain('require("opted-out-external-package")')
})
})
})