Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promote and rename server bundling options serverComponentsExternalPackages and bundlePagesExternals #65421

Merged
merged 13 commits into from
May 7, 2024
Merged
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: serverComponentsExternalPackages
title: serverExternalPackages
description: Opt-out specific dependencies from the Server Components bundling and use native Node.js `require`.
---

Expand All @@ -10,9 +10,7 @@ If a dependency is using Node.js specific features, you can choose to opt-out sp
```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverComponentsExternalPackages: ['@acme/ui'],
},
serverExternalPackages: ['@acme/ui'],
}

module.exports = nextConfig
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: bundlePagesRouterDependencies
description: Enable automatic dependency bundling for Pages Router
---

Enable automatic server-side dependency bundling for Pages Router applications. Matches the automatic dependency bundling in App Router.

```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
bundlePagesRouterDependencies: true,
}

module.exports = nextConfig
```

Explicitly opt-out certain packages from being bundled using the [`serverExternalPackages`](/docs/pages/api-reference/next-config-js/serverExternalPackages) option.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: serverExternalPackages
description: Opt-out specific dependencies from the dependency bundling enabled by `bundlePagesRouterDependencies`.
---

Opt-out specific dependencies from being included in the automatic bundling of the [`bundlePagesRouterDependencies`](/docs/pages/api-reference/next-config-js/bundlePagesRouterDependencies) option.

These pages will then use native Node.js `require` to resolve the dependency.

```js filename="next.config.js"
/** @type {import('next').NextConfig} */
const nextConfig = {
serverExternalPackages: ['@acme/ui'],
}

module.exports = nextConfig
```

Next.js includes a [short list of popular packages](https://github.com/vercel/next.js/blob/canary/packages/next/src/lib/server-external-packages.json) that currently are working on compatibility and automatically opt-ed out:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since it's an mdx file so u can import the json file where these deps names are written and map to display it here. This way both the lists will stay synced

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd consider that out of scope for this PR. We have the validate script that manages it for now. It'd be a good follow up change!

- `@appsignal/nodejs`
- `@aws-sdk/client-s3`
- `@aws-sdk/s3-presigned-post`
- `@blockfrost/blockfrost-js`
- `@highlight-run/node`
- `@jpg-store/lucid-cardano`
- `@libsql/client`
- `@mikro-orm/core`
- `@mikro-orm/knex`
- `@node-rs/argon2`
- `@node-rs/bcrypt`
- `@prisma/client`
- `@react-pdf/renderer`
- `@sentry/profiling-node`
- `@swc/core`
- `argon2`
- `autoprefixer`
- `aws-crt`
- `bcrypt`
- `better-sqlite3`
- `canvas`
- `cpu-features`
- `cypress`
- `eslint`
- `express`
- `firebase-admin`
- `isolated-vm`
- `jest`
- `jsdom`
- `libsql`
- `mdx-bundler`
- `mongodb`
- `mongoose`
- `next-mdx-remote`
- `next-seo`
- `node-pty`
- `node-web-audio-api`
- `oslo`
- `pg`
- `playwright`
- `postcss`
- `prettier`
- `prisma`
- `puppeteer-core`
- `puppeteer`
- `rimraf`
- `sharp`
- `shiki`
- `sqlite3`
- `tailwindcss`
- `ts-node`
- `typescript`
- `vscode-oniguruma`
- `undici`
- `webpack`
- `websocket`
- `zeromq`
11 changes: 5 additions & 6 deletions packages/next-swc/crates/next-core/src/next_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ pub struct NextConfig {
typescript: TypeScriptConfig,
use_file_system_public_routes: bool,
webpack: Option<serde_json::Value>,
/// A list of packages that should be treated as external in the RSC server
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment probably needs to be changed

/// build. @see [api reference](https://nextjs.org/docs/app/api-reference/next-config-js/server_external_packages)
pub server_external_packages: Option<Vec<String>>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TraceRawVcs)]
Expand Down Expand Up @@ -460,9 +463,6 @@ pub struct ExperimentalConfig {
/// For use with `@next/mdx`. Compile MDX files using the new Rust compiler.
/// @see [api reference](https://nextjs.org/docs/app/api-reference/next-config-js/mdxRs)
mdx_rs: Option<MdxRsOptions>,
/// A list of packages that should be treated as external in the RSC server
/// build. @see [api reference](https://nextjs.org/docs/app/api-reference/next-config-js/server_components_external_packages)
pub server_components_external_packages: Option<Vec<String>>,
pub strict_next_head: Option<bool>,
pub swc_plugins: Option<Vec<(String, serde_json::Value)>>,
pub turbo: Option<ExperimentalTurboConfig>,
Expand Down Expand Up @@ -737,11 +737,10 @@ impl NextConfig {
}

#[turbo_tasks::function]
pub async fn server_component_externals(self: Vc<Self>) -> Result<Vc<Vec<String>>> {
pub async fn server_external_packages(self: Vc<Self>) -> Result<Vc<Vec<String>>> {
Ok(Vc::cell(
self.await?
.experimental
.server_components_external_packages
.server_external_packages
.as_ref()
.cloned()
.unwrap_or_default(),
Expand Down
6 changes: 3 additions & 3 deletions packages/next-swc/crates/next-core/src/next_server/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,12 @@ pub async fn get_server_resolve_options_context(

// Add the config's own list of external packages.
external_packages.extend(
(*next_config.server_component_externals().await?)
(*next_config.server_external_packages().await?)
.iter()
.cloned(),
);

let server_component_externals_plugin = ExternalCjsModulesResolvePlugin::new(
let server_external_packages_plugin = ExternalCjsModulesResolvePlugin::new(
project_path,
project_path.root(),
ExternalPredicate::Only(Vc::cell(external_packages)).cell(),
Expand Down Expand Up @@ -196,7 +196,7 @@ pub async fn get_server_resolve_options_context(
Vc::upcast(module_feature_report_resolve_plugin),
Vc::upcast(unsupported_modules_resolve_plugin),
Vc::upcast(next_node_shared_runtime_plugin),
Vc::upcast(server_component_externals_plugin),
Vc::upcast(server_external_packages_plugin),
Vc::upcast(next_external_plugin),
]
}
Expand Down
9 changes: 4 additions & 5 deletions packages/next-swc/crates/next-core/src/next_server/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,8 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin {
"The request could not be resolved by Node.js from the importing module. The \
way Node.js resolves modules is slightly different from the way Next.js \
resolves modules. Next.js was able to resolve it, while Node.js would not be \
able to.\nTry to remove this package from \
serverComponentsExternalPackages.\nOr update the import side to use a \
compatible request that can be resolved by Node.js.",
able to.\nTry to remove this package from serverExternalPackages.\nOr update \
the import side to use a compatible request that can be resolved by Node.js.",
);
};
break result_from_original_location;
Expand Down Expand Up @@ -486,7 +485,7 @@ impl Issue for UnableToExternalize {
StyledString::Text("Package ".to_string()),
StyledString::Code(package),
StyledString::Text(" (".to_string()),
StyledString::Code("serverComponentsExternalPackages".to_string()),
StyledString::Code("serverExternalPackages".to_string()),
StyledString::Text(" or default list) can't be external".to_string()),
])
.cell())
Expand All @@ -510,7 +509,7 @@ impl Issue for UnableToExternalize {
StyledString::Text("The request ".to_string()),
StyledString::Code(self.request.to_string()),
StyledString::Text(" matches ".to_string()),
StyledString::Code("serverComponentsExternalPackages".to_string()),
StyledString::Code("serverExternalPackages".to_string()),
StyledString::Text(
" (or the default list), but it can't be external:".to_string(),
),
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/build/handle-externals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ function resolveBundlingOptOutPackages({
resolvedExternalPackageDirs
) ||
(isEsm && isAppLayer) ||
(!isAppLayer && config.experimental.bundlePagesExternals)
(!isAppLayer && config.bundlePagesRouterDependencies)

if (nodeModulesRegex.test(resolvedRes)) {
const isOptOutBundling = optOutBundlingPackageRegex.test(resolvedRes)
Expand Down
13 changes: 5 additions & 8 deletions packages/next/src/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -775,18 +775,15 @@ export default async function getBaseWebpackConfig(

const crossOrigin = config.crossOrigin

// The `serverComponentsExternalPackages` should not conflict with
// The `serverExternalPackages` should not conflict with
// the `transpilePackages`.
if (
config.experimental.serverComponentsExternalPackages &&
finalTranspilePackages
) {
if (config.serverExternalPackages && finalTranspilePackages) {
const externalPackageConflicts = finalTranspilePackages.filter((pkg) =>
config.experimental.serverComponentsExternalPackages?.includes(pkg)
config.serverExternalPackages?.includes(pkg)
)
if (externalPackageConflicts.length > 0) {
throw new Error(
`The packages specified in the 'transpilePackages' conflict with the 'serverComponentsExternalPackages': ${externalPackageConflicts.join(
`The packages specified in the 'transpilePackages' conflict with the 'serverExternalPackages': ${externalPackageConflicts.join(
', '
)}`
)
Expand All @@ -795,7 +792,7 @@ export default async function getBaseWebpackConfig(

// For original request, such as `package name`
const optOutBundlingPackages = EXTERNAL_PACKAGES.concat(
...(config.experimental.serverComponentsExternalPackages || [])
...(config.serverExternalPackages || [])
).filter((pkg) => !finalTranspilePackages?.includes(pkg))
// For resolved request, such as `absolute path/package name/foo/bar.js`
const optOutBundlingPackageRegex = new RegExp(
Expand Down
1 change: 0 additions & 1 deletion packages/next/src/lib/turbopack-warning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const unsupportedTurbopackNextConfigOptions = [
'experimental.adjustFontFallbacks',
'experimental.adjustFontFallbacksWithSizeAdjust',
'experimental.allowedRevalidateHeaderKeys',
'experimental.bundlePagesExternals',
'experimental.extensionAlias',
'experimental.fallbackNodePolyfills',

Expand Down
4 changes: 2 additions & 2 deletions packages/next/src/server/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
.optional(),
assetPrefix: z.string().optional(),
basePath: z.string().optional(),
bundlePagesRouterDependencies: z.boolean().optional(),
cacheHandler: z.string().min(1).optional(),
cacheMaxMemorySize: z.number().optional(),
cleanDistDir: z.boolean().optional(),
Expand Down Expand Up @@ -320,7 +321,6 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
taint: z.boolean().optional(),
prerenderEarlyExit: z.boolean().optional(),
proxyTimeout: z.number().gte(0).optional(),
serverComponentsExternalPackages: z.array(z.string()).optional(),
scrollRestoration: z.boolean().optional(),
sri: z
.object({
Expand Down Expand Up @@ -414,7 +414,6 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
.optional(),
serverMinification: z.boolean().optional(),
serverSourceMaps: z.boolean().optional(),
bundlePagesExternals: z.boolean().optional(),
staticWorkerRequestDeduping: z.boolean().optional(),
useWasmBinary: z.boolean().optional(),
useLightningcss: z.boolean().optional(),
Expand Down Expand Up @@ -571,6 +570,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
.optional(),
// saas option is unknown, use z.any() here
sassOptions: z.record(z.string(), z.any()).optional(),
serverExternalPackages: z.array(z.string()).optional(),
serverRuntimeConfig: z.record(z.string(), z.any()).optional(),
skipMiddlewareUrlNormalize: z.boolean().optional(),
skipTrailingSlashRedirect: z.boolean().optional(),
Expand Down
24 changes: 13 additions & 11 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,6 @@ export interface ExperimentalConfig {
adjustFontFallbacks?: boolean
adjustFontFallbacksWithSizeAdjust?: boolean

/**
* A list of packages that should be treated as external in the RSC server build.
* @see https://nextjs.org/docs/app/api-reference/next-config-js/serverComponentsExternalPackages
*/
serverComponentsExternalPackages?: string[]

webVitalsAttribution?: Array<(typeof WEB_VITALS)[number]>

/**
Expand Down Expand Up @@ -420,10 +414,7 @@ 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

/**
* Uses an IPC server to dedupe build-time requests to the cache handler
*/
Expand Down Expand Up @@ -838,6 +829,17 @@ export interface NextConfig extends Record<string, any> {
* Enable experimental features. Note that all experimental features are subject to breaking changes in the future.
*/
experimental?: ExperimentalConfig

/**
* Enables the bundling of node_modules packages (externals) for pages server-side bundles.
*/
bundlePagesRouterDependencies?: boolean

/**
* A list of packages that should be treated as external in the RSC server build.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment needs to be changed

* @see https://nextjs.org/docs/app/api-reference/next-config-js/serverExternalPackages
*/
serverExternalPackages?: string[]
}

export const defaultConfig: NextConfig = {
Expand Down Expand Up @@ -942,7 +944,6 @@ export const defaultConfig: NextConfig = {
turbotrace: undefined,
typedRoutes: false,
instrumentationHook: false,
bundlePagesExternals: false,
parallelServerCompiles: false,
parallelServerBuildTraces: false,
ppr:
Expand All @@ -963,6 +964,7 @@ export const defaultConfig: NextConfig = {
static: 300,
},
},
bundlePagesRouterDependencies: false,
}

export async function normalizeConfig(phase: string, config: any) {
Expand Down
Loading
Loading