diff --git a/crates/napi/src/next_api/project.rs b/crates/napi/src/next_api/project.rs index d8b0e99de13d7..70917b4d8d02d 100644 --- a/crates/napi/src/next_api/project.rs +++ b/crates/napi/src/next_api/project.rs @@ -9,6 +9,7 @@ use napi::{ }; use next_api::{ entrypoints::Entrypoints, + next_server_nft::next_server_nft_assets, operation::{ EntrypointsOperation, InstrumentationOperation, MiddlewareOperation, OptionEndpoint, RouteOperation, @@ -988,7 +989,14 @@ async fn output_assets_operation( .flat_map(|assets| assets.iter().copied()) .collect(); - Ok(Vc::cell(output_assets.into_iter().collect())) + let nft = next_server_nft_assets(container.project()).await?; + + Ok(Vc::cell( + output_assets + .into_iter() + .chain(nft.iter().copied()) + .collect(), + )) } #[napi(ts_return_type = "{ __napiType: \"RootTask\" }")] diff --git a/crates/next-api/src/lib.rs b/crates/next-api/src/lib.rs index 17360fdb01d21..84499a4a5488b 100644 --- a/crates/next-api/src/lib.rs +++ b/crates/next-api/src/lib.rs @@ -13,6 +13,7 @@ mod instrumentation; mod loadable_manifest; mod middleware; mod module_graph; +pub mod next_server_nft; mod nft_json; pub mod operation; mod pages; diff --git a/crates/next-api/src/next_server_nft.rs b/crates/next-api/src/next_server_nft.rs new file mode 100644 index 0000000000000..f31e0534446df --- /dev/null +++ b/crates/next-api/src/next_server_nft.rs @@ -0,0 +1,354 @@ +use std::collections::BTreeSet; + +use anyhow::{Context, Result, bail}; +use either::Either; +use next_core::{get_next_package, next_server::get_tracing_compile_time_info}; +use serde::{Deserialize, Serialize}; +use serde_json::{Value, json}; +use turbo_rcstr::RcStr; +use turbo_tasks::{ + NonLocalValue, ResolvedVc, TaskInput, TryFlatJoinIterExt, TryJoinIterExt, Vc, + trace::TraceRawVcs, +}; +use turbo_tasks_fs::{DirectoryContent, DirectoryEntry, File, FileSystemPath, glob::Glob}; +use turbopack::externals_tracing_module_context; +use turbopack_core::{ + asset::{Asset, AssetContent}, + context::AssetContext, + file_source::FileSource, + output::{OutputAsset, OutputAssets}, + reference_type::{CommonJsReferenceSubType, ReferenceType}, + resolve::{ExternalType, origin::PlainResolveOrigin, parse::Request}, + traced_asset::TracedAsset, +}; +use turbopack_ecmascript::resolve::cjs_resolve; + +use crate::{ + nft_json::{all_assets_from_entries_filtered, relativize_glob}, + project::Project, +}; + +#[derive( + PartialEq, Eq, TraceRawVcs, NonLocalValue, Deserialize, Serialize, Debug, Clone, Hash, TaskInput, +)] +enum ServerNftType { + Minimal, + Full, +} + +#[turbo_tasks::function] +pub async fn next_server_nft_assets(project: Vc) -> Result> { + Ok(Vc::cell(vec![ + ResolvedVc::upcast( + ServerNftJsonAsset::new(project, ServerNftType::Full) + .to_resolved() + .await?, + ), + ResolvedVc::upcast( + ServerNftJsonAsset::new(project, ServerNftType::Minimal) + .to_resolved() + .await?, + ), + ])) +} + +#[turbo_tasks::value] +pub struct ServerNftJsonAsset { + project: ResolvedVc, + ty: ServerNftType, +} + +#[turbo_tasks::value_impl] +impl ServerNftJsonAsset { + #[turbo_tasks::function] + pub fn new(project: ResolvedVc, ty: ServerNftType) -> Vc { + ServerNftJsonAsset { project, ty }.cell() + } +} + +#[turbo_tasks::value_impl] +impl OutputAsset for ServerNftJsonAsset { + #[turbo_tasks::function] + async fn path(&self) -> Result> { + let name = match self.ty { + ServerNftType::Minimal => "next-minimal-server.js.nft.json", + ServerNftType::Full => "next-server.js.nft.json", + }; + + Ok(self.project.node_root().await?.join(name)?.cell()) + } +} + +#[turbo_tasks::value_impl] +impl Asset for ServerNftJsonAsset { + #[turbo_tasks::function] + async fn content(self: Vc) -> Result> { + let this = self.await?; + // Example: [project]/apps/my-website/.next/ + let base_dir = this + .project + .project_root_path() + .await? + .join(&this.project.node_root().await?.path)?; + + let mut server_output_assets = + all_assets_from_entries_filtered(self.entries(), None, Some(self.ignores())) + .await? + .iter() + .map(async |m| { + base_dir + .get_relative_path_to(&*m.path().await?) + .context("failed to compute relative path for server NFT JSON") + }) + .try_join() + .await?; + + // A few hardcoded files (not recursive) + server_output_assets.push("./package.json".into()); + + let next_dir = get_next_package(this.project.project_path().owned().await?).await?; + for ty in ["app-page", "pages"] { + let dir = next_dir.join(&format!("dist/server/route-modules/{ty}"))?; + let module_path = dir.join("module.compiled.js")?; + server_output_assets.push( + base_dir + .get_relative_path_to(&module_path) + .context("failed to compute relative path for server NFT JSON")?, + ); + + let contexts_dir = dir.join("vendored/contexts")?; + let DirectoryContent::Entries(contexts_files) = &*contexts_dir.read_dir().await? else { + bail!( + "Expected contexts directory to be a directory, found: {:?}", + contexts_dir + ); + }; + for (_, entry) in contexts_files { + let DirectoryEntry::File(file) = entry else { + continue; + }; + if file.extension() == "js" { + server_output_assets.push( + base_dir + .get_relative_path_to(file) + .context("failed to compute relative path for server NFT JSON")?, + ) + } + } + } + + server_output_assets.sort(); + // Dedupe as some entries may be duplicates: a file might be referenced multiple times, + // e.g. as a RawModule (from an FS operation) and as an EcmascriptModuleAsset because it + // was required. + server_output_assets.dedup(); + + let json = json!({ + "version": 1, + "files": server_output_assets + }); + + Ok(AssetContent::file(File::from(json.to_string()).into())) + } +} + +#[turbo_tasks::value_impl] +impl ServerNftJsonAsset { + #[turbo_tasks::function] + async fn entries(&self) -> Result> { + let is_standalone = *self.project.next_config().is_standalone().await?; + + let asset_context = Vc::upcast(externals_tracing_module_context( + ExternalType::CommonJs, + get_tracing_compile_time_info(), + )); + + let project_path = self.project.project_path().owned().await?; + + let next_resolve_origin = Vc::upcast(PlainResolveOrigin::new( + asset_context, + get_next_package(project_path.clone()).await?.join("_")?, + )); + + let cache_handler = self + .project + .next_config() + .cache_handler(project_path.clone()) + .await?; + let cache_handlers = self + .project + .next_config() + .experimental_cache_handlers(project_path.clone()) + .await?; + + // These are used by packages/next/src/server/require-hook.ts + let shared_entries = ["styled-jsx", "styled-jsx/style", "styled-jsx/style.js"]; + + let cache_handler_entries = cache_handler + .into_iter() + .chain(cache_handlers.into_iter()) + .map(|f| { + asset_context + .process( + Vc::upcast(FileSource::new(f.clone())), + ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined), + ) + .module() + }); + + let entries = match self.ty { + ServerNftType::Full => Either::Left( + if is_standalone { + Either::Left( + [ + "next/dist/server/lib/start-server", + "next/dist/server/next", + "next/dist/server/require-hook", + ] + .into_iter(), + ) + } else { + Either::Right(std::iter::empty()) + } + .chain(std::iter::once("next/dist/server/next-server")), + ), + ServerNftType::Minimal => Either::Right(std::iter::once( + "next/dist/compiled/next-server/server.runtime.prod", + )), + }; + + Ok(Vc::cell( + cache_handler_entries + .chain( + shared_entries + .into_iter() + .chain(entries) + .map(async |path| { + Ok(cjs_resolve( + next_resolve_origin, + Request::parse_string(path.into()), + CommonJsReferenceSubType::Undefined, + None, + false, + ) + .primary_modules() + .await? + .into_iter() + .map(|m| **m)) + }) + .try_flat_join() + .await?, + ) + .map(|m| Vc::upcast::>(TracedAsset::new(m)).to_resolved()) + .try_join() + .await?, + )) + } + + #[turbo_tasks::function] + async fn ignores(&self) -> Result> { + let is_standalone = *self.project.next_config().is_standalone().await?; + let has_next_support = *self.project.next_config().ci_has_next_support().await?; + let project_path = self.project.project_path().owned().await?; + + let output_file_tracing_excludes = self + .project + .next_config() + .output_file_tracing_excludes() + .await?; + let mut additional_ignores = BTreeSet::new(); + if let Some(output_file_tracing_excludes) = output_file_tracing_excludes + .as_ref() + .and_then(Value::as_object) + { + for (glob_pattern, exclude_patterns) in output_file_tracing_excludes { + // Check if the route matches the glob pattern + let glob = Glob::new(RcStr::from(glob_pattern.clone()), Default::default()).await?; + if glob.matches("next-server") + && let Some(patterns) = exclude_patterns.as_array() + { + for pattern in patterns { + if let Some(pattern_str) = pattern.as_str() { + let (glob, root) = relativize_glob(pattern_str, project_path.clone())?; + let glob = if root.path.is_empty() { + glob.to_string() + } else { + format!("{root}/{glob}") + }; + additional_ignores.insert(glob); + } + } + } + } + } + + let server_ignores_glob = [ + "**/node_modules/react{,-dom,-server-dom-turbopack}/**/*.development.js", + "**/*.d.ts", + "**/*.map", + "**/next/dist/pages/**/*", + "**/next/dist/compiled/next-server/**/*.dev.js", + "**/next/dist/compiled/webpack/*", + "**/node_modules/webpack5/**/*", + "**/next/dist/server/lib/route-resolver*", + "**/next/dist/compiled/semver/semver/**/*.js", + "**/next/dist/compiled/jest-worker/**/*", + // Turbopack doesn't support AMP + "**/next/dist/compiled/@ampproject/toolbox-optimizer/**/*", + // -- The following were added for Turbopack specifically -- + // client/components/use-action-queue.ts has a process.env.NODE_ENV guard, but we can't set that due to React: https://github.com/vercel/next.js/pull/75254 + "**/next/dist/next-devtools/userspace/use-app-dev-rendering-indicator.js", + // client/components/app-router.js has a process.env.NODE_ENV guard, but we + // can't set that. + "**/next/dist/client/dev/hot-reloader/app/hot-reloader-app.js", + // server/lib/router-server.js doesn't guard this require: + "**/next/dist/server/lib/router-utils/setup-dev-bundler.js", + // server/next.js doesn't guard this require + "**/next/dist/server/dev/next-dev-server.js", + // next/dist/compiled/babel* pulls in this, but we never actually transpile at + // deploy-time + "**/next/dist/compiled/browserslist/**", + ] + .into_iter() + .chain(additional_ignores.iter().map(|s| s.as_str())) + // only ignore image-optimizer code when + // this is being handled outside of next-server + .chain(if has_next_support { + Either::Left( + [ + "**/node_modules/sharp/**/*", + "**/@img/sharp-libvips*/**/*", + "**/next/dist/server/image-optimizer.js", + ] + .into_iter(), + ) + } else { + Either::Right(std::iter::empty()) + }) + .chain(if is_standalone { + Either::Left(std::iter::empty()) + } else { + Either::Right(["**/*/next/dist/server/next.js", "**/*/next/dist/bin/next"].into_iter()) + }) + .map(|g| Glob::new(g.into(), Default::default())) + .collect::>(); + + Ok(match self.ty { + ServerNftType::Full => Glob::alternatives(server_ignores_glob), + ServerNftType::Minimal => Glob::alternatives( + server_ignores_glob + .into_iter() + .chain( + [ + "**/next/dist/compiled/edge-runtime/**/*", + "**/next/dist/server/web/sandbox/**/*", + "**/next/dist/server/post-process.js", + ] + .into_iter() + .map(|g| Glob::new(g.into(), Default::default())), + ) + .collect(), + ), + }) + } +} diff --git a/crates/next-api/src/nft_json.rs b/crates/next-api/src/nft_json.rs index 9160e079b8704..a25cfa5b97b70 100644 --- a/crates/next-api/src/nft_json.rs +++ b/crates/next-api/src/nft_json.rs @@ -350,7 +350,10 @@ impl Asset for NftJsonAsset { /// traversal doesn't need to consider them and can just traverse 'down' the tree. /// The main alternative is to merge glob evaluation with directory traversal which is what the npm /// `glob` package does, but this would be a substantial rewrite.` -fn relativize_glob(glob: &str, relative_to: FileSystemPath) -> Result<(&str, FileSystemPath)> { +pub(crate) fn relativize_glob( + glob: &str, + relative_to: FileSystemPath, +) -> Result<(&str, FileSystemPath)> { let mut relative_to = relative_to; let mut processed_glob = glob; loop { diff --git a/crates/next-core/src/next_client_reference/visit_client_reference.rs b/crates/next-core/src/next_client_reference/visit_client_reference.rs index 614f3d6efeb23..f0a2862e2c2df 100644 --- a/crates/next-core/src/next_client_reference/visit_client_reference.rs +++ b/crates/next-core/src/next_client_reference/visit_client_reference.rs @@ -266,13 +266,13 @@ impl Visit for FindServerEntries { tracing::info_span!("client reference") } FindServerEntriesNode::Internal(_, name) => { - tracing::info_span!("module", name = name.to_string()) + tracing::info_span!("module", name = display(name)) } FindServerEntriesNode::ServerUtilEntry(_, name) => { - tracing::info_span!("server util", name = name.to_string()) + tracing::info_span!("server util", name = display(name)) } FindServerEntriesNode::ServerComponentEntry(_, name) => { - tracing::info_span!("layout segment", name = name.to_string()) + tracing::info_span!("layout segment", name = display(name)) } } } diff --git a/crates/next-core/src/next_config.rs b/crates/next-core/src/next_config.rs index ed9221b9b2bdc..8c129230b6aa3 100644 --- a/crates/next-core/src/next_config.rs +++ b/crates/next-core/src/next_config.rs @@ -1330,6 +1330,11 @@ impl NextConfig { Vc::cell(self.output == Some(OutputType::Standalone)) } + #[turbo_tasks::function] + pub fn ci_has_next_support(&self) -> Vc { + Vc::cell(self.env.contains_key("NOW_BUILDER")) + } + #[turbo_tasks::function] pub fn cache_handler(&self, project_path: FileSystemPath) -> Result> { if let Some(handler) = &self.cache_handler { diff --git a/crates/next-core/src/next_server/mod.rs b/crates/next-core/src/next_server/mod.rs index c2f97a515ecdb..6980c2a73b8b1 100644 --- a/crates/next-core/src/next_server/mod.rs +++ b/crates/next-core/src/next_server/mod.rs @@ -6,5 +6,5 @@ pub use context::{ ServerChunkingContextOptions, ServerContextType, get_server_chunking_context, get_server_chunking_context_with_client_assets, get_server_compile_time_info, get_server_module_options_context, get_server_resolve_options_context, - get_server_runtime_entries, + get_server_runtime_entries, get_tracing_compile_time_info, }; diff --git a/packages/next/src/build/collect-build-traces.ts b/packages/next/src/build/collect-build-traces.ts index df7307f34e5ab..4f9efd7fa51d6 100644 --- a/packages/next/src/build/collect-build-traces.ts +++ b/packages/next/src/build/collect-build-traces.ts @@ -82,7 +82,6 @@ export async function collectBuildTraces({ hasSsrAmpPages, buildTraceContext, outputFileTracingRoot, - isTurbopack, }: { dir: string distDir: string @@ -94,7 +93,6 @@ export async function collectBuildTraces({ nextBuildSpan?: Span config: NextConfigComplete buildTraceContext?: BuildTraceContext - isTurbopack: boolean }) { const startTime = Date.now() debug('starting build traces') @@ -280,11 +278,6 @@ export async function collectBuildTraces({ ) } - if (isTurbopack) { - addToTracedFiles(distDir, './package.json', serverTracedFiles) - addToTracedFiles(distDir, './package.json', minimalServerTracedFiles) - } - { const chunksToTrace: string[] = [ ...(buildTraceContext?.chunksTrace?.action.input || []), diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 98445016602e5..77122300b9549 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -1748,7 +1748,6 @@ export default async function build( hasSsrAmpPages: false, buildTraceContext, outputFileTracingRoot, - isTurbopack: false, }) .catch((err) => { console.error(err) @@ -2642,7 +2641,7 @@ export default async function build( await writeFunctionsConfigManifest(distDir, functionsConfigManifest) - if (!isGenerateMode && !buildTracesPromise) { + if (!isTurbopack && !isGenerateMode && !buildTracesPromise) { buildTracesPromise = collectBuildTraces({ dir, config, @@ -2653,7 +2652,6 @@ export default async function build( hasSsrAmpPages, buildTraceContext, outputFileTracingRoot, - isTurbopack: true, }).catch((err) => { console.error(err) process.exit(1) @@ -3935,7 +3933,10 @@ export default async function build( } const postBuildSpinner = createSpinner('Finalizing page optimization') - let buildTracesSpinner = createSpinner(`Collecting build traces`) + let buildTracesSpinner + if (buildTracesPromise) { + buildTracesSpinner = createSpinner('Collecting build traces') + } // ensure the worker is not left hanging worker.end() diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 82c0c2d6a8dc3..2731f1fa53f77 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -45,6 +45,7 @@ import type { TLSSocket } from 'tls' import type { PathnameNormalizer } from './normalizers/request/pathname-normalizer' import type { InstrumentationModule } from './instrumentation/types' +import * as path from 'path' import { format as formatUrl, parse as parseUrl } from 'url' import { formatHostname } from './lib/format-hostname' import { @@ -444,7 +445,7 @@ export default abstract class Server< this.experimentalTestProxy = experimentalTestProxy this.serverOptions = options - this.dir = (require('path') as typeof import('path')).resolve(dir) + this.dir = path.resolve(/* turbopackIgnore: true */ dir) this.quiet = quiet this.loadEnvConfig({ dev }) @@ -458,8 +459,8 @@ export default abstract class Server< this.fetchHostname = formatHostname(this.hostname) } this.port = port - this.distDir = (require('path') as typeof import('path')).join( - this.dir, + this.distDir = path.join( + /* turbopackIgnore: true */ this.dir, this.nextConfig.distDir ) this.publicDir = this.getPublicDir() @@ -2416,19 +2417,19 @@ export default abstract class Server< return null } - private stripNextDataPath(path: string, stripLocale = true) { - if (path.includes(this.buildId)) { - const splitPath = path.substring( - path.indexOf(this.buildId) + this.buildId.length + private stripNextDataPath(filePath: string, stripLocale = true) { + if (filePath.includes(this.buildId)) { + const splitPath = filePath.substring( + filePath.indexOf(this.buildId) + this.buildId.length ) - path = denormalizePagePath(splitPath.replace(/\.json$/, '')) + filePath = denormalizePagePath(splitPath.replace(/\.json$/, '')) } if (this.localeNormalizer && stripLocale) { - return this.localeNormalizer.normalize(path) + return this.localeNormalizer.normalize(filePath) } - return path + return filePath } // map the route to the actual bundle name diff --git a/packages/next/src/server/image-optimizer.ts b/packages/next/src/server/image-optimizer.ts index 1d9f79b014a83..727e812b6ae7d 100644 --- a/packages/next/src/server/image-optimizer.ts +++ b/packages/next/src/server/image-optimizer.ts @@ -142,6 +142,7 @@ async function writeToCacheDir( upstreamEtag: string ) { const filename = join( + /* turbopackIgnore: true */ dir, `${maxAge}.${expireAt}.${etag}.${upstreamEtag}.${extension}` ) @@ -494,20 +495,25 @@ export class ImageOptimizerCache { distDir: string nextConfig: NextConfigComplete }) { - this.cacheDir = join(distDir, 'cache', 'images') + this.cacheDir = join(/* turbopackIgnore: true */ distDir, 'cache', 'images') this.nextConfig = nextConfig } async get(cacheKey: string): Promise { try { - const cacheDir = join(this.cacheDir, cacheKey) + const cacheDir = join(/* turbopackIgnore: true */ this.cacheDir, cacheKey) const files = await promises.readdir(cacheDir) const now = Date.now() for (const file of files) { const [maxAgeSt, expireAtSt, etag, upstreamEtag, extension] = file.split('.', 5) - const buffer = await promises.readFile(join(cacheDir, file)) + const buffer = await promises.readFile( + /* turbopackIgnore: true */ join( + /* turbopackIgnore: true */ cacheDir, + file + ) + ) const expireAt = Number(expireAtSt) const maxAge = Number(maxAgeSt) @@ -560,7 +566,7 @@ export class ImageOptimizerCache { try { await writeToCacheDir( - join(this.cacheDir, cacheKey), + join(/* turbopackIgnore: true */ this.cacheDir, cacheKey), value.extension, revalidate, expireAt, diff --git a/packages/next/src/server/load-components.ts b/packages/next/src/server/load-components.ts index 83b9483e82eb8..904c5f27ae29d 100644 --- a/packages/next/src/server/load-components.ts +++ b/packages/next/src/server/load-components.ts @@ -177,9 +177,13 @@ async function loadComponentsImpl({ let reactLoadableManifestPath if (!process.env.TURBOPACK) { - reactLoadableManifestPath = join(distDir, REACT_LOADABLE_MANIFEST) + reactLoadableManifestPath = join( + /* turbopackIgnore: true */ distDir, + REACT_LOADABLE_MANIFEST + ) } else if (isAppPath) { reactLoadableManifestPath = join( + /* turbopackIgnore: true */ distDir, 'server', 'app', @@ -188,6 +192,7 @@ async function loadComponentsImpl({ ) } else { reactLoadableManifestPath = join( + /* turbopackIgnore: true */ distDir, 'server', 'pages', @@ -213,7 +218,7 @@ async function loadComponentsImpl({ subresourceIntegrityManifest, ] = await Promise.all([ loadManifestWithRetries( - join(distDir, BUILD_MANIFEST), + join(/* turbopackIgnore: true */ distDir, BUILD_MANIFEST), manifestLoadAttempts ), tryLoadManifestWithRetries( @@ -224,12 +229,16 @@ async function loadComponentsImpl({ isAppPath || process.env.TURBOPACK ? undefined : loadManifestWithRetries( - join(distDir, `${DYNAMIC_CSS_MANIFEST}.json`), + join( + /* turbopackIgnore: true */ distDir, + `${DYNAMIC_CSS_MANIFEST}.json` + ), manifestLoadAttempts ).catch(() => undefined), isAppPath && hasClientManifest ? tryLoadClientReferenceManifest( join( + /* turbopackIgnore: true */ distDir, 'server', 'app', @@ -241,13 +250,21 @@ async function loadComponentsImpl({ : undefined, isAppPath ? loadManifestWithRetries( - join(distDir, 'server', SERVER_REFERENCE_MANIFEST + '.json'), + join( + /* turbopackIgnore: true */ distDir, + 'server', + SERVER_REFERENCE_MANIFEST + '.json' + ), manifestLoadAttempts ).catch(() => null) : null, sriEnabled ? loadManifestWithRetries>>( - join(distDir, 'server', SUBRESOURCE_INTEGRITY_MANIFEST + '.json') + join( + /* turbopackIgnore: true */ distDir, + 'server', + SUBRESOURCE_INTEGRITY_MANIFEST + '.json' + ) ).catch(() => undefined) : undefined, ]) diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index 1d795882c6e28..0e66b2a10e4c5 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -327,7 +327,10 @@ export default class NextNodeServer extends BaseServer< interceptTestApis() } - this.middlewareManifestPath = join(this.serverDistDir, MIDDLEWARE_MANIFEST) + this.middlewareManifestPath = join( + /* turbopackIgnore: true */ this.serverDistDir, + MIDDLEWARE_MANIFEST + ) // This is just optimization to fire prepare as soon as possible. It will be // properly awaited later. We add the catch here to ensure that it does not @@ -509,16 +512,21 @@ export default class NextNodeServer extends BaseServer< } protected getPublicDir(): string { - return join(this.dir, CLIENT_PUBLIC_FILES_PATH) + return join(/* turbopackIgnore: true */ this.dir, CLIENT_PUBLIC_FILES_PATH) } protected getHasStaticDir(): boolean { - return fs.existsSync(join(this.dir, 'static')) + return fs.existsSync( + /* turbopackIgnore: true */ join( + /* turbopackIgnore: true */ this.dir, + 'static' + ) + ) } protected getPagesManifest(): PagesManifest | undefined { return loadManifest( - join(this.serverDistDir, PAGES_MANIFEST) + join(/* turbopackIgnore: true */ this.serverDistDir, PAGES_MANIFEST) ) as PagesManifest } @@ -526,7 +534,7 @@ export default class NextNodeServer extends BaseServer< if (!this.enabledDirectories.app) return undefined return loadManifest( - join(this.serverDistDir, APP_PATHS_MANIFEST) + join(/* turbopackIgnore: true */ this.serverDistDir, APP_PATHS_MANIFEST) ) as PagesManifest } @@ -551,9 +559,14 @@ export default class NextNodeServer extends BaseServer< } protected getBuildId(): string { - const buildIdFile = join(this.distDir, BUILD_ID_FILE) + const buildIdFile = join( + /* turbopackIgnore: true */ this.distDir, + BUILD_ID_FILE + ) try { - return fs.readFileSync(buildIdFile, 'utf8').trim() + return fs + .readFileSync(/* turbopackIgnore: true */ buildIdFile, 'utf8') + .trim() } catch (err: any) { if (err.code === 'ENOENT') { throw new Error( @@ -931,7 +944,11 @@ export default class NextNodeServer extends BaseServer< protected getNextFontManifest(): NextFontManifest | undefined { return loadManifest( - join(this.distDir, 'server', NEXT_FONT_MANIFEST + '.json') + join( + /* turbopackIgnore: true */ this.distDir, + 'server', + NEXT_FONT_MANIFEST + '.json' + ) ) as NextFontManifest } @@ -1495,17 +1512,25 @@ export default class NextNodeServer extends BaseServer< return { name: pageInfo.name, - paths: pageInfo.files.map((file) => join(this.distDir, file)), + paths: pageInfo.files.map((file) => + join(/* turbopackIgnore: true */ this.distDir, file) + ), wasm: (pageInfo.wasm ?? []).map((binding) => ({ ...binding, - filePath: join(this.distDir, binding.filePath), + filePath: join( + /* turbopackIgnore: true */ this.distDir, + binding.filePath + ), })), assets: pageInfo.assets && pageInfo.assets.map((binding) => { return { ...binding, - filePath: join(this.distDir, binding.filePath), + filePath: join( + /* turbopackIgnore: true */ this.distDir, + binding.filePath + ), } }), env: pageInfo.env, @@ -1517,14 +1542,26 @@ export default class NextNodeServer extends BaseServer< try { const functionsConfig = this.renderOpts.dev ? {} - : require(join(this.distDir, 'server', FUNCTIONS_CONFIG_MANIFEST)) + : require( + join( + /* turbopackIgnore: true */ this.distDir, + 'server', + FUNCTIONS_CONFIG_MANIFEST + ) + ) if ( this.renderOpts.dev || functionsConfig?.functions?.['/_middleware'] ) { // if used with top level await, this will be a promise - return require(join(this.distDir, 'server', 'middleware.js')) + return require( + join( + /* turbopackIgnore: true */ this.distDir, + 'server', + 'middleware.js' + ) + ) } } catch (err) { if ( @@ -1861,7 +1898,7 @@ export default class NextNodeServer extends BaseServer< } this._cachedPreviewManifest = loadManifest( - join(this.distDir, PRERENDER_MANIFEST) + join(/* turbopackIgnore: true */ this.distDir, PRERENDER_MANIFEST) ) as PrerenderManifest return this._cachedPreviewManifest @@ -1870,7 +1907,10 @@ export default class NextNodeServer extends BaseServer< protected getRoutesManifest(): NormalizedRouteManifest | undefined { return getTracer().trace( NextNodeServerSpan.getRoutesManifest, - () => loadManifest(join(this.distDir, ROUTES_MANIFEST)) as RoutesManifest + () => + loadManifest( + join(/* turbopackIgnore: true */ this.distDir, ROUTES_MANIFEST) + ) as RoutesManifest ) } @@ -2032,7 +2072,10 @@ export default class NextNodeServer extends BaseServer< if (this._serverDistDir) { return this._serverDistDir } - const serverDistDir = join(this.distDir, SERVER_DIRECTORY) + const serverDistDir = join( + /* turbopackIgnore: true */ this.distDir, + SERVER_DIRECTORY + ) this._serverDistDir = serverDistDir return serverDistDir } diff --git a/packages/next/src/server/next.ts b/packages/next/src/server/next.ts index 14d457f485918..1c6c807d7ddf6 100644 --- a/packages/next/src/server/next.ts +++ b/packages/next/src/server/next.ts @@ -14,7 +14,7 @@ import './node-polyfill-crypto' import type { default as NextNodeServer } from './next-server' import * as log from '../build/output/log' import loadConfig from './config' -import path, { resolve } from 'path' +import path from 'path' import { NON_STANDARD_NODE_ENV } from '../lib/constants' import { PHASE_DEVELOPMENT_SERVER, @@ -247,7 +247,9 @@ export class NextServer implements NextWrapperServer { } private async [SYMBOL_LOAD_CONFIG]() { - const dir = resolve(this.options.dir || '.') + const dir = path.resolve( + /* turbopackIgnore: true */ this.options.dir || '.' + ) const config = await loadConfig( this.options.dev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_SERVER, @@ -262,7 +264,12 @@ export class NextServer implements NextWrapperServer { if (!this.options.dev) { try { const serializedConfig = require( - path.join(dir, config.distDir, SERVER_FILES_MANIFEST) + /* turbopackIgnore: true */ + path.join( + /* turbopackIgnore: true */ dir, + config.distDir, + SERVER_FILES_MANIFEST + ) ).config config.experimental.isExperimentalCompile = @@ -549,7 +556,7 @@ function createServer( // When the caller is a custom server (using next()). if (options.customServer !== false) { - const dir = resolve(options.dir || '.') + const dir = path.resolve(/* turbopackIgnore: true */ options.dir || '.') return new NextCustomServer({ ...options, diff --git a/packages/next/src/server/require.ts b/packages/next/src/server/require.ts index 67e692bc23d30..9bcda1c14cdd3 100644 --- a/packages/next/src/server/require.ts +++ b/packages/next/src/server/require.ts @@ -29,17 +29,23 @@ export function getMaybePagePath( // If we have a cached path, we can return it directly. if (pagePath) return pagePath - const serverBuildPath = path.join(distDir, SERVER_DIRECTORY) + const serverBuildPath = path.join( + /* turbopackIgnore: true */ distDir, + SERVER_DIRECTORY + ) let appPathsManifest: undefined | PagesManifest if (isAppPath) { appPathsManifest = loadManifest( - path.join(serverBuildPath, APP_PATHS_MANIFEST), + path.join( + /* turbopackIgnore: true */ serverBuildPath, + APP_PATHS_MANIFEST + ), !isDev ) as PagesManifest } const pagesManifest = loadManifest( - path.join(serverBuildPath, PAGES_MANIFEST), + path.join(/* turbopackIgnore: true */ serverBuildPath, PAGES_MANIFEST), !isDev ) as PagesManifest @@ -85,7 +91,7 @@ export function getMaybePagePath( return pagePath } - pagePath = path.join(serverBuildPath, pagePath) + pagePath = path.join(/* turbopackIgnore: true */ serverBuildPath, pagePath) pagePathCache?.set(cacheKey, pagePath) return pagePath @@ -113,14 +119,16 @@ export async function requirePage( ): Promise { const pagePath = getPagePath(page, distDir, undefined, isAppPath) if (pagePath.endsWith('.html')) { - return promises.readFile(pagePath, 'utf8').catch((err) => { - throw new MissingStaticPage(page, err.message) - }) + return promises + .readFile(/* turbopackIgnore: true */ pagePath, 'utf8') + .catch((err) => { + throw new MissingStaticPage(page, err.message) + }) } const mod = process.env.NEXT_MINIMAL ? // @ts-ignore __non_webpack_require__(pagePath) - : require(pagePath) + : require(/* turbopackIgnore: true */ pagePath) return mod } diff --git a/packages/next/src/server/route-modules/route-module.ts b/packages/next/src/server/route-modules/route-module.ts index 635837ec9f7a4..5992a6ed9728b 100644 --- a/packages/next/src/server/route-modules/route-module.ts +++ b/packages/next/src/server/route-modules/route-module.ts @@ -152,6 +152,7 @@ export abstract class RouteModule< } else { const { join } = require('node:path') as typeof import('node:path') const absoluteProjectDir = join( + /* turbopackIgnore: true */ process.cwd(), getRequestMeta(req, 'relativeProjectDir') || this.relativeProjectDir ) @@ -390,6 +391,7 @@ export abstract class RouteModule< const { join } = require('node:path') as typeof import('node:path') const absoluteProjectDir = join( + /* turbopackIgnore: true */ process.cwd(), getRequestMeta(req, 'relativeProjectDir') || this.relativeProjectDir ) @@ -432,6 +434,7 @@ export abstract class RouteModule< } const { join } = require('node:path') as typeof import('node:path') const projectDir = join( + /* turbopackIgnore: true */ process.cwd(), getRequestMeta(req, 'relativeProjectDir') || this.relativeProjectDir ) @@ -539,6 +542,7 @@ export abstract class RouteModule< require('node:path') as typeof import('node:path') absoluteProjectDir = join( + /* turbopackIgnore: true */ process.cwd(), getRequestMeta(req, 'relativeProjectDir') || this.relativeProjectDir ) diff --git a/test/production/app-dir/build-output-tree-view/build-output-tree-view.test.ts b/test/production/app-dir/build-output-tree-view/build-output-tree-view.test.ts index 0e6bcc425fdc0..60a985c9b583c 100644 --- a/test/production/app-dir/build-output-tree-view/build-output-tree-view.test.ts +++ b/test/production/app-dir/build-output-tree-view/build-output-tree-view.test.ts @@ -74,15 +74,15 @@ describe('build-output-tree-view', () => { }) function getTreeView(cliOutput: string): string { - let foundBuildTracesLine = false + let foundStart = false const lines: string[] = [] for (const line of cliOutput.split('\n')) { - if (foundBuildTracesLine) { + foundStart ||= line.startsWith('Route ') + + if (foundStart) { lines.push(line) } - - foundBuildTracesLine ||= line.includes('Collecting build traces') } return lines.join('\n').trim() diff --git a/test/production/next-server-nft/app/layout.tsx b/test/production/next-server-nft/app/layout.tsx new file mode 100644 index 0000000000000..e7077399c03ce --- /dev/null +++ b/test/production/next-server-nft/app/layout.tsx @@ -0,0 +1,7 @@ +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} diff --git a/test/production/next-server-nft/app/page.tsx b/test/production/next-server-nft/app/page.tsx new file mode 100644 index 0000000000000..8afb7372a1d52 --- /dev/null +++ b/test/production/next-server-nft/app/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return 'Hello' +} diff --git a/test/production/next-server-nft/next-server-nft.test.ts b/test/production/next-server-nft/next-server-nft.test.ts new file mode 100644 index 0000000000000..08818c8782621 --- /dev/null +++ b/test/production/next-server-nft/next-server-nft.test.ts @@ -0,0 +1,353 @@ +import { nextTestSetup } from 'e2e-utils' +import path from 'path' +import fs from 'fs' + +// Only run this test for Turbopack as it is more conservative (i.e. aggressive) in including +// referenced files and might include too many. (The Webpack snapshots would different slightly from +// the Turbopack ones below.) +// +// This test is not meant for testing correctness (which is done by the behavioral tests), but as a +// regression test to ensure that some stray `path.join` doesn't cause all of the Next.js package to +// get included. +;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)( + 'next-server-nft', + () => { + const { next, skipped } = nextTestSetup({ + files: __dirname, + skipDeployment: true, + }) + + if (skipped) { + return + } + + async function readNormalizedNFT(name) { + let data = await next.readJSON(name) + let result = [ + ...new Set( + data.files + .filter((file: string) => { + // They are important, but they are never actually included by themselves but rather as + // part of some JS files in the same directory tree, which are higher-signal for the + // screenshot below. + if (file.endsWith('/package.json')) { + return false + } + + // Filter out the many symlinks that power node_modules + let fileAbsolute = path.join(next.testDir, name, '..', file) + if (fs.lstatSync(fileAbsolute).isSymbolicLink()) { + return false + } + return true + }) + .map((file: string) => { + // Normalize sharp, different architectures have different files + if (file.includes('/node_modules/@img/sharp-libvips-')) { + return '@img/sharp-libvips-*' + } + if ( + file.match( + /\/node_modules\/@img\/sharp-\w+-\w+\/lib\/sharp-\w+-\w+.node$/ + ) + ) { + return '@img/sharp-*/sharp-*.node' + } + + // Strip double node_modules to simplify output + let firstNodeModules = file.indexOf('/node_modules/') + let lastNodeModules = file.lastIndexOf('/node_modules/') + if (firstNodeModules !== lastNodeModules) { + return file.slice(lastNodeModules) + } + + return file + }) + ), + ] + result.sort() + return result + } + + it('should not trace too many files in next-server.js.nft.json', async () => { + let trace = await readNormalizedNFT('.next/next-server.js.nft.json') + + // Group the entries together so that the snapshot doesn't change too often. + // This trace contains quite a lot of files that aren't actually needed. But there isn't much + // that Turbopack itself can do about that. + + let traceGrouped = [ + ...new Set( + trace.map((file: string) => { + if (file.startsWith('/node_modules/next/dist/client/')) { + return '/node_modules/next/dist/client/*' + } + if (file.startsWith('/node_modules/next/dist/server/')) { + return '/node_modules/next/dist/server/*' + } + if (file.startsWith('/node_modules/next/dist/shared/')) { + return '/node_modules/next/dist/shared/*' + } + return file + }) + ), + ] + + expect(traceGrouped).toMatchInlineSnapshot(` + [ + "/node_modules/@next/env/dist/index.js", + "/node_modules/@swc/helpers/cjs/_class_private_field_loose_base.cjs", + "/node_modules/@swc/helpers/cjs/_class_private_field_loose_key.cjs", + "/node_modules/@swc/helpers/cjs/_interop_require_default.cjs", + "/node_modules/@swc/helpers/cjs/_interop_require_wildcard.cjs", + "/node_modules/client-only/index.js", + "/node_modules/color-convert/conversions.js", + "/node_modules/color-convert/index.js", + "/node_modules/color-convert/route.js", + "/node_modules/color-name/index.js", + "/node_modules/color-string/index.js", + "/node_modules/color/index.js", + "/node_modules/detect-libc/lib/detect-libc.js", + "/node_modules/detect-libc/lib/filesystem.js", + "/node_modules/detect-libc/lib/process.js", + "/node_modules/is-arrayish/index.js", + "/node_modules/next/dist/build/output/log.js", + "/node_modules/next/dist/build/segment-config/app/app-segment-config.js", + "/node_modules/next/dist/build/segment-config/app/app-segments.js", + "/node_modules/next/dist/build/static-paths/utils.js", + "/node_modules/next/dist/client/*", + "/node_modules/next/dist/compiled/@edge-runtime/cookies/index.js", + "/node_modules/next/dist/compiled/@hapi/accept/index.js", + "/node_modules/next/dist/compiled/@mswjs/interceptors/ClientRequest/index.js", + "/node_modules/next/dist/compiled/@opentelemetry/api/index.js", + "/node_modules/next/dist/compiled/babel-packages/packages-bundle.js", + "/node_modules/next/dist/compiled/babel/bundle.js", + "/node_modules/next/dist/compiled/babel/code-frame.js", + "/node_modules/next/dist/compiled/babel/core.js", + "/node_modules/next/dist/compiled/babel/parser.js", + "/node_modules/next/dist/compiled/babel/traverse.js", + "/node_modules/next/dist/compiled/babel/types.js", + "/node_modules/next/dist/compiled/busboy/index.js", + "/node_modules/next/dist/compiled/bytes/index.js", + "/node_modules/next/dist/compiled/content-disposition/index.js", + "/node_modules/next/dist/compiled/cookie/index.js", + "/node_modules/next/dist/compiled/debug/index.js", + "/node_modules/next/dist/compiled/edge-runtime/index.js", + "/node_modules/next/dist/compiled/fresh/index.js", + "/node_modules/next/dist/compiled/image-detector/detector.js", + "/node_modules/next/dist/compiled/image-size/index.js", + "/node_modules/next/dist/compiled/is-animated/index.js", + "/node_modules/next/dist/compiled/json5/index.js", + "/node_modules/next/dist/compiled/jsonwebtoken/index.js", + "/node_modules/next/dist/compiled/lru-cache/index.js", + "/node_modules/next/dist/compiled/nanoid/index.cjs", + "/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js", + "/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js", + "/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js", + "/node_modules/next/dist/compiled/p-queue/index.js", + "/node_modules/next/dist/compiled/path-browserify/index.js", + "/node_modules/next/dist/compiled/path-to-regexp/index.js", + "/node_modules/next/dist/compiled/picomatch/index.js", + "/node_modules/next/dist/compiled/react-is/cjs/react-is.development.js", + "/node_modules/next/dist/compiled/react-is/cjs/react-is.production.js", + "/node_modules/next/dist/compiled/react-is/index.js", + "/node_modules/next/dist/compiled/semver/index.js", + "/node_modules/next/dist/compiled/send/index.js", + "/node_modules/next/dist/compiled/source-map/source-map.js", + "/node_modules/next/dist/compiled/stacktrace-parser/stack-trace-parser.cjs.js", + "/node_modules/next/dist/compiled/string-hash/index.js", + "/node_modules/next/dist/compiled/strip-ansi/index.js", + "/node_modules/next/dist/compiled/superstruct/index.cjs", + "/node_modules/next/dist/compiled/ws/index.js", + "/node_modules/next/dist/compiled/zod-validation-error/index.js", + "/node_modules/next/dist/compiled/zod/index.cjs", + "/node_modules/next/dist/experimental/testmode/context.js", + "/node_modules/next/dist/experimental/testmode/fetch.js", + "/node_modules/next/dist/experimental/testmode/httpget.js", + "/node_modules/next/dist/experimental/testmode/server-edge.js", + "/node_modules/next/dist/experimental/testmode/server.js", + "/node_modules/next/dist/lib/batcher.js", + "/node_modules/next/dist/lib/client-and-server-references.js", + "/node_modules/next/dist/lib/constants.js", + "/node_modules/next/dist/lib/detached-promise.js", + "/node_modules/next/dist/lib/error-telemetry-utils.js", + "/node_modules/next/dist/lib/fallback.js", + "/node_modules/next/dist/lib/find-pages-dir.js", + "/node_modules/next/dist/lib/format-dynamic-import-path.js", + "/node_modules/next/dist/lib/format-server-error.js", + "/node_modules/next/dist/lib/framework/boundary-components.js", + "/node_modules/next/dist/lib/framework/boundary-constants.js", + "/node_modules/next/dist/lib/generate-interception-routes-rewrites.js", + "/node_modules/next/dist/lib/interop-default.js", + "/node_modules/next/dist/lib/is-api-route.js", + "/node_modules/next/dist/lib/is-app-page-route.js", + "/node_modules/next/dist/lib/is-app-route-route.js", + "/node_modules/next/dist/lib/is-error.js", + "/node_modules/next/dist/lib/is-serializable-props.js", + "/node_modules/next/dist/lib/metadata/get-metadata-route.js", + "/node_modules/next/dist/lib/metadata/is-metadata-route.js", + "/node_modules/next/dist/lib/metadata/metadata-context.js", + "/node_modules/next/dist/lib/multi-file-writer.js", + "/node_modules/next/dist/lib/non-nullable.js", + "/node_modules/next/dist/lib/page-types.js", + "/node_modules/next/dist/lib/pick.js", + "/node_modules/next/dist/lib/picocolors.js", + "/node_modules/next/dist/lib/redirect-status.js", + "/node_modules/next/dist/lib/route-pattern-normalizer.js", + "/node_modules/next/dist/lib/scheduler.js", + "/node_modules/next/dist/lib/semver-noop.js", + "/node_modules/next/dist/lib/static-env.js", + "/node_modules/next/dist/lib/url.js", + "/node_modules/next/dist/lib/wait.js", + "/node_modules/next/dist/next-devtools/server/shared.js", + "/node_modules/next/dist/server/*", + "/node_modules/next/dist/shared/*", + "/node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js", + "/node_modules/react-dom/cjs/react-dom-server-legacy.node.production.js", + "/node_modules/react-dom/cjs/react-dom-server.browser.production.js", + "/node_modules/react-dom/cjs/react-dom-server.edge.production.js", + "/node_modules/react-dom/cjs/react-dom-server.node.production.js", + "/node_modules/react-dom/cjs/react-dom.production.js", + "/node_modules/react-dom/index.js", + "/node_modules/react-dom/server.browser.js", + "/node_modules/react-dom/server.edge.js", + "/node_modules/react-dom/server.node.js", + "/node_modules/react-dom/static.node.js", + "/node_modules/react/cjs/react-compiler-runtime.production.js", + "/node_modules/react/cjs/react-jsx-dev-runtime.production.js", + "/node_modules/react/cjs/react-jsx-runtime.production.js", + "/node_modules/react/cjs/react.production.js", + "/node_modules/react/compiler-runtime.js", + "/node_modules/react/index.js", + "/node_modules/react/jsx-dev-runtime.js", + "/node_modules/react/jsx-runtime.js", + "/node_modules/semver/classes/comparator.js", + "/node_modules/semver/classes/range.js", + "/node_modules/semver/classes/semver.js", + "/node_modules/semver/functions/cmp.js", + "/node_modules/semver/functions/coerce.js", + "/node_modules/semver/functions/compare.js", + "/node_modules/semver/functions/eq.js", + "/node_modules/semver/functions/gt.js", + "/node_modules/semver/functions/gte.js", + "/node_modules/semver/functions/lt.js", + "/node_modules/semver/functions/lte.js", + "/node_modules/semver/functions/neq.js", + "/node_modules/semver/functions/parse.js", + "/node_modules/semver/functions/satisfies.js", + "/node_modules/semver/internal/constants.js", + "/node_modules/semver/internal/debug.js", + "/node_modules/semver/internal/identifiers.js", + "/node_modules/semver/internal/lrucache.js", + "/node_modules/semver/internal/parse-options.js", + "/node_modules/semver/internal/re.js", + "/node_modules/sharp/lib/channel.js", + "/node_modules/sharp/lib/colour.js", + "/node_modules/sharp/lib/composite.js", + "/node_modules/sharp/lib/constructor.js", + "/node_modules/sharp/lib/index.js", + "/node_modules/sharp/lib/input.js", + "/node_modules/sharp/lib/is.js", + "/node_modules/sharp/lib/libvips.js", + "/node_modules/sharp/lib/operation.js", + "/node_modules/sharp/lib/output.js", + "/node_modules/sharp/lib/resize.js", + "/node_modules/sharp/lib/sharp.js", + "/node_modules/sharp/lib/utility.js", + "/node_modules/simple-swizzle/index.js", + "/node_modules/styled-jsx/dist/index/index.js", + "/node_modules/styled-jsx/index.js", + "/node_modules/styled-jsx/style.js", + "@img/sharp-*/sharp-*.node", + "@img/sharp-libvips-*", + ] + `) + }) + + it('should not trace too many files in next-minimal-server.js.nft.json', async () => { + let trace = await readNormalizedNFT( + '.next/next-minimal-server.js.nft.json' + ) + expect(trace).toMatchInlineSnapshot(` + [ + "/node_modules/client-only/index.js", + "/node_modules/next/dist/client/components/app-router-headers.js", + "/node_modules/next/dist/compiled/@opentelemetry/api/index.js", + "/node_modules/next/dist/compiled/babel-packages/packages-bundle.js", + "/node_modules/next/dist/compiled/babel/bundle.js", + "/node_modules/next/dist/compiled/babel/code-frame.js", + "/node_modules/next/dist/compiled/babel/core.js", + "/node_modules/next/dist/compiled/babel/parser.js", + "/node_modules/next/dist/compiled/babel/traverse.js", + "/node_modules/next/dist/compiled/babel/types.js", + "/node_modules/next/dist/compiled/debug/index.js", + "/node_modules/next/dist/compiled/json5/index.js", + "/node_modules/next/dist/compiled/lru-cache/index.js", + "/node_modules/next/dist/compiled/next-server/server.runtime.prod.js", + "/node_modules/next/dist/compiled/semver/index.js", + "/node_modules/next/dist/compiled/source-map/source-map.js", + "/node_modules/next/dist/compiled/stacktrace-parser/stack-trace-parser.cjs.js", + "/node_modules/next/dist/compiled/ws/index.js", + "/node_modules/next/dist/experimental/testmode/context.js", + "/node_modules/next/dist/experimental/testmode/fetch.js", + "/node_modules/next/dist/experimental/testmode/server-edge.js", + "/node_modules/next/dist/lib/client-and-server-references.js", + "/node_modules/next/dist/lib/constants.js", + "/node_modules/next/dist/lib/interop-default.js", + "/node_modules/next/dist/lib/is-error.js", + "/node_modules/next/dist/server/app-render/after-task-async-storage-instance.js", + "/node_modules/next/dist/server/app-render/after-task-async-storage.external.js", + "/node_modules/next/dist/server/app-render/async-local-storage.js", + "/node_modules/next/dist/server/app-render/work-async-storage-instance.js", + "/node_modules/next/dist/server/app-render/work-async-storage.external.js", + "/node_modules/next/dist/server/app-render/work-unit-async-storage-instance.js", + "/node_modules/next/dist/server/app-render/work-unit-async-storage.external.js", + "/node_modules/next/dist/server/lib/cache-handlers/default.external.js", + "/node_modules/next/dist/server/lib/incremental-cache/memory-cache.external.js", + "/node_modules/next/dist/server/lib/incremental-cache/shared-cache-controls.external.js", + "/node_modules/next/dist/server/lib/incremental-cache/tags-manifest.external.js", + "/node_modules/next/dist/server/lib/lru-cache.js", + "/node_modules/next/dist/server/lib/router-utils/instrumentation-globals.external.js", + "/node_modules/next/dist/server/lib/router-utils/instrumentation-node-extensions.js", + "/node_modules/next/dist/server/lib/trace/constants.js", + "/node_modules/next/dist/server/lib/trace/tracer.js", + "/node_modules/next/dist/server/load-manifest.external.js", + "/node_modules/next/dist/server/response-cache/types.js", + "/node_modules/next/dist/server/route-modules/app-page/module.compiled.js", + "/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/amp-context.js", + "/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/app-router-context.js", + "/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.js", + "/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/head-manager-context.js", + "/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/hooks-client-context.js", + "/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/image-config-context.js", + "/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/router-context.js", + "/node_modules/next/dist/server/route-modules/app-page/vendored/contexts/server-inserted-html.js", + "/node_modules/next/dist/server/route-modules/pages/module.compiled.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/amp-context.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/app-router-context.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/head-manager-context.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/hooks-client-context.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/html-context.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/image-config-context.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/loadable-context.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/loadable.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/router-context.js", + "/node_modules/next/dist/server/route-modules/pages/vendored/contexts/server-inserted-html.js", + "/node_modules/next/dist/shared/lib/deep-freeze.js", + "/node_modules/next/dist/shared/lib/invariant-error.js", + "/node_modules/next/dist/shared/lib/is-plain-object.js", + "/node_modules/next/dist/shared/lib/is-thenable.js", + "/node_modules/next/dist/shared/lib/no-fallback-error.external.js", + "/node_modules/next/dist/shared/lib/runtime-config.external.js", + "/node_modules/next/dist/shared/lib/server-reference-info.js", + "/node_modules/react/cjs/react.production.js", + "/node_modules/react/index.js", + "/node_modules/styled-jsx/dist/index/index.js", + "/node_modules/styled-jsx/index.js", + "/node_modules/styled-jsx/style.js", + ] + `) + }) + } +) diff --git a/test/production/next-server-nft/next.config.js b/test/production/next-server-nft/next.config.js new file mode 100644 index 0000000000000..807126e4cf0bf --- /dev/null +++ b/test/production/next-server-nft/next.config.js @@ -0,0 +1,6 @@ +/** + * @type {import('next').NextConfig} + */ +const nextConfig = {} + +module.exports = nextConfig diff --git a/turbopack/crates/turbopack/src/lib.rs b/turbopack/crates/turbopack/src/lib.rs index 11dd2d331b38c..ab71efcb1474e 100644 --- a/turbopack/crates/turbopack/src/lib.rs +++ b/turbopack/crates/turbopack/src/lib.rs @@ -672,7 +672,7 @@ async fn process_default_internal( } #[turbo_tasks::function] -async fn externals_tracing_module_context( +pub async fn externals_tracing_module_context( ty: ExternalType, compile_time_info: Vc, ) -> Result> {