Fix handling subpath for server components externals (#62150)
Follow up of #61986 where we didn't handle the subpath externals very well, found by @sokra Closes NEXT-2517
This commit is contained in:
parent
646a3d99db
commit
cbdd1d2654
7 changed files with 45 additions and 8 deletions
|
@ -25,6 +25,15 @@ const externalPattern = new RegExp(
|
|||
|
||||
const nodeModulesRegex = /node_modules[/\\].*\.[mc]?js$/
|
||||
|
||||
function containsImportInPackages(
|
||||
request: string,
|
||||
packages: string[]
|
||||
): boolean {
|
||||
return packages.some(
|
||||
(pkg) => request === pkg || request.startsWith(pkg + '/')
|
||||
)
|
||||
}
|
||||
|
||||
export function isResourceInPackages(
|
||||
resource: string,
|
||||
packageNames?: string[],
|
||||
|
@ -74,7 +83,7 @@ export async function resolveExternal(
|
|||
// For package that marked as externals that should be not bundled,
|
||||
// we don't resolve them as ESM since it could be resolved as async module,
|
||||
// such as `import(external package)` in the bundle, valued as a `Promise`.
|
||||
!optOutBundlingPackages.some((optOut) => request.startsWith(optOut))
|
||||
!containsImportInPackages(request, optOutBundlingPackages)
|
||||
? [true, false]
|
||||
: [false]
|
||||
|
||||
|
@ -151,7 +160,6 @@ export function makeExternalHandler({
|
|||
}) {
|
||||
let resolvedExternalPackageDirs: Map<string, string>
|
||||
const looseEsmExternals = config.experimental?.esmExternals === 'loose'
|
||||
const optOutBundlingPackagesSet = new Set(optOutBundlingPackages)
|
||||
|
||||
return async function handleExternals(
|
||||
context: string,
|
||||
|
@ -276,7 +284,7 @@ export function makeExternalHandler({
|
|||
: request
|
||||
|
||||
// Check if it's opt out bundling package first
|
||||
if (optOutBundlingPackagesSet.has(fullRequest)) {
|
||||
if (containsImportInPackages(fullRequest, optOutBundlingPackages)) {
|
||||
return fullRequest
|
||||
}
|
||||
return resolveNextExternal(fullRequest)
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
'use client'
|
||||
|
||||
import { dir } from 'external-package'
|
||||
import { dir as subDir } from 'external-package/subpath'
|
||||
|
||||
export default function Page() {
|
||||
return <div id="directory-ssr">{dir}</div>
|
||||
return (
|
||||
<>
|
||||
<div id="directory-ssr">{dir}</div>
|
||||
<div id="subdirectory-ssr">{subDir}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import { dir } from 'external-package'
|
||||
import { dir as subDir } from 'external-package/subpath'
|
||||
|
||||
export default function Page() {
|
||||
return <div id="directory">{dir}</div>
|
||||
return (
|
||||
<>
|
||||
<div id="directory">{dir}</div>
|
||||
<div id="subdirectory">{subDir}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,9 +11,13 @@ createNextDescribe(
|
|||
const $ = await next.render$('/')
|
||||
|
||||
const text = $('#directory').text()
|
||||
const subpath = $('#subdirectory').text()
|
||||
expect(text).toBe(
|
||||
path.join(next.testDir, 'node_modules', 'external-package')
|
||||
)
|
||||
expect(subpath).toBe(
|
||||
path.join(next.testDir, 'node_modules', 'external-package', 'subpath')
|
||||
)
|
||||
})
|
||||
|
||||
it('uses externals for predefined list in server-external-packages.json', async () => {
|
||||
|
@ -28,7 +32,13 @@ createNextDescribe(
|
|||
it('should externalize serverComponentsExternalPackages for server rendering layer', async () => {
|
||||
await next.fetch('/client')
|
||||
const ssrBundle = await next.readFile('.next/server/app/client/page.js')
|
||||
expect(ssrBundle).not.toContain('external-package-mark')
|
||||
expect(ssrBundle).not.toContain('external-package-mark:index')
|
||||
expect(ssrBundle).not.toContain('external-package-mark:subpath')
|
||||
|
||||
await next.fetch('/')
|
||||
const rscBundle = await next.readFile('.next/server/app/page.js')
|
||||
expect(rscBundle).not.toContain('external-package-mark:index')
|
||||
expect(rscBundle).not.toContain('external-package-mark:subpath')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
2
test/e2e/app-dir/server-components-externals/node_modules/external-package/index.js
generated
vendored
2
test/e2e/app-dir/server-components-externals/node_modules/external-package/index.js
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
module.exports = {
|
||||
dir: __dirname,
|
||||
value: 'external-package-mark',
|
||||
value: 'external-package-mark:index',
|
||||
}
|
||||
|
|
|
@ -2,5 +2,10 @@
|
|||
"name": "external-package",
|
||||
"version": "1.0.0",
|
||||
"description": "External package",
|
||||
"main": "index.js"
|
||||
"main": "index.js",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": "./index.js",
|
||||
"./subpath": "./subpath/index.js"
|
||||
}
|
||||
}
|
||||
|
|
2
test/e2e/app-dir/server-components-externals/node_modules/external-package/subpath/index.js
generated
vendored
Normal file
2
test/e2e/app-dir/server-components-externals/node_modules/external-package/subpath/index.js
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
exports.value = 'external-package-mark:subpath'
|
||||
exports.dir = __dirname
|
Loading…
Reference in a new issue