Skip to content

Commit

Permalink
Pick esm main fields and condition names first for RSC server layer
Browse files Browse the repository at this point in the history
  • Loading branch information
huozhi committed May 30, 2023
1 parent 0539b9c commit 71edd68
Show file tree
Hide file tree
Showing 13 changed files with 72 additions and 26 deletions.
24 changes: 13 additions & 11 deletions packages/next/src/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ const reactPackagesRegex = /^(react|react-dom|react-server-dom-webpack)($|\/)/
const asyncStoragesRegex =
/next[\\/]dist[\\/]client[\\/]components[\\/](static-generation-async-storage|action-async-storage|request-async-storage)/

// exports.<conditionName>
const edgeConditionNames = [
'edge-light',
'worker',
'browser',
'import',
'module',
'default',
]

// packageJson.<mainField>
const mainFieldsPerCompiler: Record<CompilerNameValues, string[]> = {
[COMPILER_NAMES.server]: ['main', 'module'],
[COMPILER_NAMES.client]: ['browser', 'module', 'main'],
Expand Down Expand Up @@ -908,12 +919,7 @@ export default async function getBaseWebpackConfig(

const reactServerCondition = [
'react-server',
...mainFieldsPerCompiler[
isEdgeServer ? COMPILER_NAMES.edgeServer : COMPILER_NAMES.server
],
'node',
'import',
'require',
...(isEdgeServer ? edgeConditionNames : ['import', 'module', 'default']),
]

const clientEntries = isClient
Expand Down Expand Up @@ -1149,11 +1155,7 @@ export default async function getBaseWebpackConfig(
: undefined),
mainFields: mainFieldsPerCompiler[compilerType],
...(isEdgeServer && {
conditionNames: [
...mainFieldsPerCompiler[COMPILER_NAMES.edgeServer],
'import',
'node',
],
conditionNames: edgeConditionNames,
}),
plugins: [],
}
Expand Down
23 changes: 18 additions & 5 deletions test/e2e/app-dir/app-external/app-external.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ createNextDescribe(
const v1 = html.match(/App React Version: ([^<]+)</)[1]
const v2 = html.match(/External React Version: ([^<]+)</)[1]
expect(v1).toBe(v2)

// Should work with both esm and cjs imports
expect(html).toContain(
'CJS-ESM Compat package: cjs-esm-compat/index.mjs'
)
expect(html).toContain('CJS package: cjs-lib')
})

it('should use the same react in server app', async () => {
Expand All @@ -167,6 +173,12 @@ createNextDescribe(
const v1 = html.match(/App React Version: ([^<]+)</)[1]
const v2 = html.match(/External React Version: ([^<]+)</)[1]
expect(v1).toBe(v2)

// Should work with both esm and cjs imports
expect(html).toContain(
'CJS-ESM Compat package: cjs-esm-compat/index.mjs'
)
expect(html).toContain('CJS package: cjs-lib')
})

it('should use the same react in pages', async () => {
Expand All @@ -190,24 +202,25 @@ createNextDescribe(

if (isNextDev) {
it('should error for wildcard exports of client module references in esm', async () => {
const page = 'app/esm-client-ref/page.js'
const pageSource = await next.readFile(page)
const page = 'app/cjs-import-esm/page.js'
// reuse esm-client-ref/page.js
const pageSource = await next.readFile('app/esm-client-ref/page.js')

try {
await next.patchFile(
page,
pageSource.replace(
"'client-esm-module'",
"'client-esm-module-wildcard'"
"'client-cjs-import-esm-wildcard'"
)
)
await next.render('/esm-client-ref')
await next.render('/cjs-import-esm')
} finally {
await next.patchFile(page, pageSource)
}

expect(next.cliOutput).toInclude(
`It's currently unsupported to use "export *" in a client boundary. Please use named exports instead.`
`ESM packages (client-esm-module-wildcard) need to be imported`
)
})
}
Expand Down
6 changes: 5 additions & 1 deletion test/e2e/app-dir/app-external/app/esm/client/page.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
'use client'
import { version, useValue } from 'esm-with-react'

import React from 'react'
import { version, useValue } from 'esm-with-react'
import { packageEntry as compatPackageEntry } from 'cjs-esm-compat'
import { packageName } from 'cjs-lib'

export default function Index() {
const value = useValue()
Expand All @@ -10,6 +12,8 @@ export default function Index() {
<h2>{'App React Version: ' + React.version}</h2>
<h2>{'External React Version: ' + version}</h2>
<h2>{'Test: ' + value}</h2>
<h2>{`CJS-ESM Compat package: ${compatPackageEntry}`}</h2>
<h2>{`CJS package: ${packageName}`}</h2>
</div>
)
}
4 changes: 4 additions & 0 deletions test/e2e/app-dir/app-external/app/esm/server/page.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { version } from 'esm-with-react'
import { packageEntry as compatPackageEntry } from 'cjs-esm-compat'
import { packageName } from 'cjs-lib'

import React from 'react'

Expand All @@ -7,6 +9,8 @@ export default function Index() {
<div>
<h2>{'App React Version: ' + React.version}</h2>
<h2>{'External React Version: ' + version}</h2>
<h2>{`CJS-ESM Compat package: ${compatPackageEntry}`}</h2>
<h2>{`CJS package: ${packageName}`}</h2>
</div>
)
}
2 changes: 1 addition & 1 deletion test/e2e/app-dir/app-external/middleware.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createResponse } from 'cjs-lib'
import { createResponse } from 'next-server-cjs-lib'
import { respond } from 'compat-next-server-module'

export async function middleware(request) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.packageEntry = 'cjs-esm-compat/index.cjs'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const packageEntry = 'cjs-esm-compat/index.mjs'
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"exports": {
"import": "./index.mjs",
"require": "./index.cjs",
"default": "./index.cjs"
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1 @@
Object.defineProperty(exports, '__esModule', { value: true })
const server_1 = require('next/server')
const createResponse = (...args) => {
return new server_1.NextResponse(...args)
}
exports.createResponse = createResponse

// Note: this is a CJS library that used the `NextResponse` export from `next/server`.
exports.packageName = 'cjs-lib'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use client'

module.exports = require('client-esm-module-wildcard')
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "client-cjs-import-esm-wildcard",
"type": "commonjs",
"exports": "./index.js"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Object.defineProperty(exports, '__esModule', { value: true })
const server_1 = require('next/server')
const createResponse = (...args) => {
return new server_1.NextResponse(...args)
}
exports.createResponse = createResponse

exports.packageName = 'cjs-lib'
// Note: this is a CJS library that used the `NextResponse` export from `next/server`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "next-server-cjs-lib",
"exports": "./index.js"
}

0 comments on commit 71edd68

Please sign in to comment.