Skip to content

Commit f6d8a11

Browse files
authored
fix esm externals edge case with "module" condition (#28612)
prefer commonjs externals even if "module" condition is used in package.json ## Bug - [ ] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md`
1 parent 71771df commit f6d8a11

File tree

10 files changed

+47
-30
lines changed

10 files changed

+47
-30
lines changed

packages/next/build/webpack-config.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -173,28 +173,14 @@ export function attachReactRefresh(
173173
}
174174
}
175175

176-
const WEBPACK_RESOLVE_OPTIONS = {
177-
// This always uses commonjs resolving, assuming API is identical
178-
// between ESM and CJS in a package
179-
// Otherwise combined ESM+CJS packages will never be external
180-
// as resolving mismatch would lead to opt-out from being external.
181-
dependencyType: 'commonjs',
182-
symlinks: true,
183-
}
184-
185-
const WEBPACK_ESM_RESOLVE_OPTIONS = {
186-
dependencyType: 'esm',
187-
symlinks: true,
188-
}
189-
190176
const NODE_RESOLVE_OPTIONS = {
191177
dependencyType: 'commonjs',
192178
modules: ['node_modules'],
193179
alias: false,
194180
fallback: false,
195181
exportsFields: ['exports'],
196182
importsFields: ['imports'],
197-
conditionNames: ['node', 'require', 'module'],
183+
conditionNames: ['node', 'require'],
198184
descriptionFiles: ['package.json'],
199185
extensions: ['.js', '.json', '.node'],
200186
enforceExtensions: false,
@@ -211,7 +197,7 @@ const NODE_RESOLVE_OPTIONS = {
211197
const NODE_ESM_RESOLVE_OPTIONS = {
212198
...NODE_RESOLVE_OPTIONS,
213199
dependencyType: 'esm',
214-
conditionNames: ['node', 'import', 'module'],
200+
conditionNames: ['node', 'import'],
215201
fullySpecified: true,
216202
}
217203

@@ -754,7 +740,7 @@ export default async function getBaseWebpackConfig(
754740
const preferEsm = esmExternals && isEsmRequested
755741

756742
const resolve = getResolve(
757-
preferEsm ? WEBPACK_ESM_RESOLVE_OPTIONS : WEBPACK_RESOLVE_OPTIONS
743+
preferEsm ? NODE_ESM_RESOLVE_OPTIONS : NODE_RESOLVE_OPTIONS
758744
)
759745

760746
// Resolve the import with the webpack provided context, this
@@ -772,7 +758,7 @@ export default async function getBaseWebpackConfig(
772758
// try the alternative resolving options.
773759
if (!res && (isEsmRequested || looseEsmExternals)) {
774760
const resolveAlternative = getResolve(
775-
preferEsm ? WEBPACK_RESOLVE_OPTIONS : WEBPACK_ESM_RESOLVE_OPTIONS
761+
preferEsm ? NODE_RESOLVE_OPTIONS : NODE_ESM_RESOLVE_OPTIONS
776762
)
777763
try {
778764
;[res, isEsm] = await resolveAlternative(context, request)

test/integration/externals-esm-loose/test/index.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const appDir = join(__dirname, '../')
1515
let appPort
1616
let app
1717

18-
describe('Valid resolve alias', () => {
18+
describe("Handle ESM externals with esmExternals: 'loose'", () => {
1919
beforeAll(async () => {
2020
await fs.remove(join(appDir, '.next'))
2121
await nextBuild(appDir)

test/integration/externals-esm/test/index.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const appDir = join(__dirname, '../')
1515
let appPort
1616
let app
1717

18-
describe('Valid resolve alias', () => {
18+
describe('Handle ESM externals with esmExternals: true', () => {
1919
beforeAll(async () => {
2020
await fs.remove(join(appDir, '.next'))
2121
await nextBuild(appDir)

test/integration/externals/node_modules/module-package/correct.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/integration/externals/node_modules/module-package/package.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/integration/externals/node_modules/module-package/wrong.mjs

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'preact/compat'
2-
import World from 'esm-package/entry'
2+
import World1 from 'esm-package/entry'
3+
import World2 from 'module-package'
34

45
export async function getStaticProps() {
56
return {
@@ -8,5 +9,9 @@ export async function getStaticProps() {
89
}
910

1011
export default function Index(props) {
11-
return <div>Hello {World}</div>
12+
return (
13+
<div>
14+
Hello {World1}+{World2}
15+
</div>
16+
)
1217
}
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import React from 'preact/compat'
2-
import World from 'esm-package/entry'
2+
import World1 from 'esm-package/entry'
3+
import World2 from 'module-package'
34

45
export function getServerSideProps() {
56
return {}
67
}
78

89
export default function Index(props) {
9-
return <div>Hello {World}</div>
10+
return (
11+
<div>
12+
Hello {World1}+{World2}
13+
</div>
14+
)
1015
}
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import React from 'preact/compat'
2-
import World from 'esm-package/entry'
2+
import World1 from 'esm-package/entry'
3+
import World2 from 'module-package'
34

45
export default function Index(props) {
5-
return <div>Hello {World}</div>
6+
return (
7+
<div>
8+
Hello {World1}+{World2}
9+
</div>
10+
)
611
}

test/integration/externals/test/index.test.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const appDir = join(__dirname, '../')
1515
let appPort
1616
let app
1717

18-
describe('Valid resolve alias', () => {
18+
describe('Handle ESM externals', () => {
1919
beforeAll(async () => {
2020
await fs.remove(join(appDir, '.next'))
2121
await nextBuild(appDir)
@@ -24,18 +24,20 @@ describe('Valid resolve alias', () => {
2424
})
2525
afterAll(() => killApp(app))
2626

27+
const expected = /Hello <!-- -->World<!-- -->\+<!-- -->World/
28+
2729
it('should render the static page', async () => {
2830
const html = await renderViaHTTP(appPort, '/static')
29-
expect(html).toMatch(/Hello <!-- -->World/)
31+
expect(html).toMatch(expected)
3032
})
3133

3234
it('should render the ssr page', async () => {
3335
const html = await renderViaHTTP(appPort, '/ssr')
34-
expect(html).toMatch(/Hello <!-- -->World/)
36+
expect(html).toMatch(expected)
3537
})
3638

3739
it('should render the ssg page', async () => {
3840
const html = await renderViaHTTP(appPort, '/ssg')
39-
expect(html).toMatch(/Hello <!-- -->World/)
41+
expect(html).toMatch(expected)
4042
})
4143
})

0 commit comments

Comments
 (0)