diff --git a/crates/next-core/src/next_client/transforms.rs b/crates/next-core/src/next_client/transforms.rs index 57a871b8a16e..657b1f2ac153 100644 --- a/crates/next-core/src/next_client/transforms.rs +++ b/crates/next-core/src/next_client/transforms.rs @@ -32,12 +32,6 @@ pub async fn get_next_client_transforms_rules( let modularize_imports_config = next_config.modularize_imports(); let enable_mdx_rs = next_config.mdx_rs().await?.is_some(); - let page_extensions: Vec = next_config - .page_extensions() - .await? - .iter() - .map(|s| s.to_string()) - .collect(); if !foreign_code { rules.push(get_next_lint_transform_rule(enable_mdx_rs).await?); @@ -83,7 +77,7 @@ pub async fn get_next_client_transforms_rules( ExportFilter::StripDataExports, enable_mdx_rs, vec![], - &page_extensions, + &next_config.page_extensions().await?, ) .await?, ); diff --git a/crates/next-core/src/next_server/transforms.rs b/crates/next-core/src/next_server/transforms.rs index 19ce3470a78c..215e8b9562c1 100644 --- a/crates/next-core/src/next_server/transforms.rs +++ b/crates/next-core/src/next_server/transforms.rs @@ -38,13 +38,7 @@ pub async fn get_next_server_transforms_rules( let mut rules = vec![]; let modularize_imports_config = next_config.modularize_imports(); - let mdx_rs = next_config.mdx_rs().await?.is_some(); - let page_extensions: Vec = next_config - .page_extensions() - .await? - .iter() - .map(|s| s.to_string()) - .collect(); + let mdx_rs: bool = next_config.mdx_rs().await?.is_some(); if !foreign_code { rules.push(get_next_lint_transform_rule(mdx_rs).await?); @@ -92,7 +86,7 @@ pub async fn get_next_server_transforms_rules( vec![RuleCondition::ReferenceType(ReferenceTypeCondition::Entry( Some(EntryReferenceSubType::PageData), ))], - &page_extensions, + &next_config.page_extensions().await?, ) .await?, ); @@ -157,7 +151,7 @@ pub async fn get_next_server_transforms_rules( }; if is_app_dir { - rules.push(get_next_debug_instant_stack_rule(mdx_rs, page_extensions.clone()).await?); + rules.push(get_next_debug_instant_stack_rule(mdx_rs, next_config.page_extensions()).await?); } if is_app_dir && diff --git a/crates/next-core/src/next_shared/transforms/next_debug_instant_stack.rs b/crates/next-core/src/next_shared/transforms/next_debug_instant_stack.rs index d58f5675290a..61b25d74ce88 100644 --- a/crates/next-core/src/next_shared/transforms/next_debug_instant_stack.rs +++ b/crates/next-core/src/next_shared/transforms/next_debug_instant_stack.rs @@ -1,7 +1,8 @@ use anyhow::Result; use async_trait::async_trait; -use next_custom_transforms::transforms::debug_instant_stack::debug_instant_stack; +use next_custom_transforms::transforms::debug_instant_stack::DebugInstantStack; use swc_core::ecma::ast::Program; +use turbo_rcstr::RcStr; use turbo_tasks::{ResolvedVc, Vc}; use turbopack::module_options::{ModuleRule, ModuleRuleEffect}; use turbopack_ecmascript::{ @@ -12,9 +13,9 @@ use super::module_rule_match_js_no_url; pub async fn get_next_debug_instant_stack_rule( enable_mdx_rs: bool, - page_extensions: Vec, + page_extensions: Vc>, ) -> Result { - let transform = EcmascriptInputTransform::Plugin( + let transform: EcmascriptInputTransform = EcmascriptInputTransform::Plugin( next_debug_instant_stack_transform_plugin(page_extensions) .to_resolved() .await?, @@ -32,24 +33,27 @@ pub async fn get_next_debug_instant_stack_rule( } #[turbo_tasks::function] -fn next_debug_instant_stack_transform_plugin(page_extensions: Vec) -> Vc { - Vc::cell(Box::new(NextDebugInstantStack { page_extensions }) - as Box) +async fn next_debug_instant_stack_transform_plugin( + page_extensions: ResolvedVc>, +) -> Result> { + Ok(Vc::cell(Box::new(NextDebugInstantStack { + debug_instant_stack: DebugInstantStack::new(&*page_extensions.await?), + }) as Box)) } #[derive(Debug)] struct NextDebugInstantStack { - page_extensions: Vec, + debug_instant_stack: DebugInstantStack, } #[async_trait] impl CustomTransformer for NextDebugInstantStack { #[tracing::instrument(level = tracing::Level::TRACE, name = "debug_instant_stack", skip_all)] async fn transform(&self, program: &mut Program, ctx: &TransformContext<'_>) -> Result<()> { - program.mutate(debug_instant_stack( - ctx.file_path_str.to_string(), - self.page_extensions.clone(), - )); + program.mutate( + self.debug_instant_stack + .get_pass(ctx.file_path_str.to_string()), + ); Ok(()) } } diff --git a/crates/next-core/src/next_shared/transforms/next_strip_page_exports.rs b/crates/next-core/src/next_shared/transforms/next_strip_page_exports.rs index b49b899defc2..2eb4a1a20e3d 100644 --- a/crates/next-core/src/next_shared/transforms/next_strip_page_exports.rs +++ b/crates/next-core/src/next_shared/transforms/next_strip_page_exports.rs @@ -5,6 +5,7 @@ use next_custom_transforms::transforms::strip_page_exports::{ ExportFilter, next_transform_strip_page_exports, }; use swc_core::ecma::ast::Program; +use turbo_rcstr::RcStr; use turbo_tasks::{ResolvedVc, TaskInput, Vc, trace::TraceRawVcs}; use turbo_tasks_fs::FileSystemPath; use turbopack::module_options::{ModuleRule, ModuleRuleEffect, RuleCondition}; @@ -45,7 +46,7 @@ pub async fn get_next_pages_transforms_rule( export_filter: ExportFilter, enable_mdx_rs: bool, extra_conditions: Vec, - page_extensions: &[String], + page_extensions: &[RcStr], ) -> Result { // Apply the Next SSG transform to all pages. let strip_transform = EcmascriptInputTransform::Plugin( diff --git a/crates/next-custom-transforms/src/chain_transforms.rs b/crates/next-custom-transforms/src/chain_transforms.rs index fe43275ebfc4..d14a4a29ebff 100644 --- a/crates/next-custom-transforms/src/chain_transforms.rs +++ b/crates/next-custom-transforms/src/chain_transforms.rs @@ -348,15 +348,15 @@ where crate::transforms::debug_fn_name::debug_fn_name(), opts.debug_function_name, ), - crate::transforms::debug_instant_stack::debug_instant_stack( - file_path_for_instant_stack, + crate::transforms::debug_instant_stack::DebugInstantStack::new( match &opts.server_components { Some(react_server_components::Config::WithOptions(options)) => { options.page_extensions.clone() } _ => vec![], }, - ), + ) + .get_pass(file_path_for_instant_stack), visit_mut_pass(crate::transforms::pure::pure_magic(comments.clone())), Optional::new( linter(lint_codemod_comments(comments)), diff --git a/crates/next-custom-transforms/src/transforms/debug_instant_stack.rs b/crates/next-custom-transforms/src/transforms/debug_instant_stack.rs index 091d5306c375..2dfe0122302c 100644 --- a/crates/next-custom-transforms/src/transforms/debug_instant_stack.rs +++ b/crates/next-custom-transforms/src/transforms/debug_instant_stack.rs @@ -8,30 +8,48 @@ use swc_core::{ quote, }; -fn build_page_extensions_regex(page_extensions: &[String]) -> String { - if page_extensions.is_empty() { - "(ts|js)x?".to_string() - } else { - let escaped: Vec = page_extensions - .iter() - .map(|ext| regex::escape(ext)) - .collect(); - format!("({})", escaped.join("|")) - } +#[derive(Debug)] +pub struct DebugInstantStack { + page_or_layout: Regex, } -pub fn debug_instant_stack(filepath: String, page_extensions: Vec) -> impl Pass { - visit_mut_pass(DebugInstantStack { - filepath, - instant_export_span: None, - page_extensions, - }) +impl DebugInstantStack { + pub fn new(page_extensions: I) -> Self + where + I: IntoIterator, + S: AsRef, + { + let mut result = String::from(r"[\\/](page|layout|default)\."); + let mut iter = page_extensions.into_iter(); + if let Some(first) = iter.next() { + result.push('('); + result.push_str(®ex::escape(first.as_ref())); + for ext in iter { + result.push('|'); + result.push_str(®ex::escape(ext.as_ref())); + } + result.push(')'); + } else { + result.push_str("(ts|js)x?"); + } + result.push('$'); + Self { + page_or_layout: Regex::new(&result).unwrap(), + } + } + pub fn get_pass(&self, filepath: String) -> impl Pass + use<> { + visit_mut_pass(DebugInstantStackPass { + filepath, + instant_export_span: None, + page_or_layout: self.page_or_layout.clone(), + }) + } } -struct DebugInstantStack { +struct DebugInstantStackPass { filepath: String, instant_export_span: Option, - page_extensions: Vec, + page_or_layout: Regex, } /// Given an export specifier, returns `Some((exported_name, local_name))` if @@ -80,12 +98,9 @@ fn find_var_init_span(items: &[ModuleItem], local_name: &str) -> Option { None } -impl VisitMut for DebugInstantStack { +impl VisitMut for DebugInstantStackPass { fn visit_mut_module_items(&mut self, items: &mut Vec) { - let ext_pattern = build_page_extensions_regex(&self.page_extensions); - let page_or_layout_re = - Regex::new(&format!(r"[\\/](page|layout|default)\.{ext_pattern}$")).unwrap(); - if !page_or_layout_re.is_match(&self.filepath) { + if !self.page_or_layout.is_match(&self.filepath) { return; } diff --git a/crates/next-custom-transforms/tests/fixture.rs b/crates/next-custom-transforms/tests/fixture.rs index fa31d2504786..8f11c270768a 100644 --- a/crates/next-custom-transforms/tests/fixture.rs +++ b/crates/next-custom-transforms/tests/fixture.rs @@ -8,7 +8,7 @@ use bytes_str::BytesStr; use next_custom_transforms::transforms::{ cjs_optimizer::cjs_optimizer, debug_fn_name::debug_fn_name, - debug_instant_stack::debug_instant_stack, + debug_instant_stack::DebugInstantStack, dynamic::{NextDynamicMode, next_dynamic}, fonts::{Config as FontLoaderConfig, next_font_loaders}, named_import_transform::named_import_transform, @@ -878,7 +878,7 @@ fn test_debug_instant_stack(input: PathBuf) { test_fixture( syntax(), - &|_| debug_instant_stack("app/page.js".to_string(), vec![]), + &|_| DebugInstantStack::new::, &str>(vec![]).get_pass("app/page.js".to_string()), &input, &output, FixtureTestConfig { diff --git a/lerna.json b/lerna.json index 8ab440cfd989..da599b557614 100644 --- a/lerna.json +++ b/lerna.json @@ -15,5 +15,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "16.3.0-canary.3" + "version": "16.3.0-canary.4" } \ No newline at end of file diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index bef1788ff9ee..dd4973048e9e 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 2956ca2c1383..21b8993cb1d1 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "description": "ESLint configuration used by Next.js.", "license": "MIT", "repository": { @@ -12,7 +12,7 @@ "dist" ], "dependencies": { - "@next/eslint-plugin-next": "16.3.0-canary.3", + "@next/eslint-plugin-next": "16.3.0-canary.4", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 37547abc8386..bd83cdf0c0e5 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,7 +1,7 @@ { "name": "@next/eslint-plugin-internal", "private": true, - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "description": "ESLint plugin for working on Next.js.", "exports": { ".": "./src/eslint-plugin-internal.js" diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 70d5617819e6..8cb7624f5e11 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/font/package.json b/packages/font/package.json index e4a884edff04..87b730f115e5 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,7 +1,7 @@ { "name": "@next/font", "private": true, - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index aadc2b2e6cc4..e8be6e98be98 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index b170eb2ed879..90e51376e5a3 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 708e92a25b35..9d8033cf179f 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 0668c45c2702..bf66b5d1e9ec 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-playwright/package.json b/packages/next-playwright/package.json index 4ab9d83a1fd6..aa81fc985dd6 100644 --- a/packages/next-playwright/package.json +++ b/packages/next-playwright/package.json @@ -1,6 +1,6 @@ { "name": "@next/playwright", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "repository": { "url": "vercel/next.js", "directory": "packages/next-playwright" diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 3069db48473c..fb382a6d393e 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index be99699a8883..306cc6115dce 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 2f2f6edd7867..83a423babf2a 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-routing/package.json b/packages/next-routing/package.json index f68679c29cd3..30a4c95dd1a6 100644 --- a/packages/next-routing/package.json +++ b/packages/next-routing/package.json @@ -1,6 +1,6 @@ { "name": "@next/routing", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "keywords": [ "react", "next", diff --git a/packages/next-rspack/package.json b/packages/next-rspack/package.json index 88fb79d6cc44..37552b4871b1 100644 --- a/packages/next-rspack/package.json +++ b/packages/next-rspack/package.json @@ -1,6 +1,6 @@ { "name": "next-rspack", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "repository": { "url": "vercel/next.js", "directory": "packages/next-rspack" diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 735580f99306..fb268bec4358 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "private": true, "files": [ "native/" diff --git a/packages/next/package.json b/packages/next/package.json index 60f3102409ad..23c93bf4f7a6 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -101,7 +101,7 @@ ] }, "dependencies": { - "@next/env": "16.3.0-canary.3", + "@next/env": "16.3.0-canary.4", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", @@ -165,11 +165,11 @@ "@modelcontextprotocol/sdk": "1.18.1", "@mswjs/interceptors": "0.23.0", "@napi-rs/triples": "1.2.0", - "@next/font": "16.3.0-canary.3", - "@next/polyfill-module": "16.3.0-canary.3", - "@next/polyfill-nomodule": "16.3.0-canary.3", - "@next/react-refresh-utils": "16.3.0-canary.3", - "@next/swc": "16.3.0-canary.3", + "@next/font": "16.3.0-canary.4", + "@next/polyfill-module": "16.3.0-canary.4", + "@next/polyfill-nomodule": "16.3.0-canary.4", + "@next/react-refresh-utils": "16.3.0-canary.4", + "@next/swc": "16.3.0-canary.4", "@opentelemetry/api": "1.6.0", "@playwright/test": "1.58.2", "@rspack/core": "1.6.7", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 7b928906b264..7ccdac890ebe 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/packages/third-parties/package.json b/packages/third-parties/package.json index b3a4c4e51664..bb85cede8a19 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "16.3.0-canary.3", + "version": "16.3.0-canary.4", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -27,7 +27,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "16.3.0-canary.3", + "next": "16.3.0-canary.4", "outdent": "0.8.0", "prettier": "2.5.1", "typescript": "6.0.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 655776c50e4f..eac89cdff1aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -983,7 +983,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 16.3.0-canary.3 + specifier: 16.3.0-canary.4 version: link:../eslint-plugin-next eslint: specifier: '>=9.0.0' @@ -1060,7 +1060,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 16.3.0-canary.3 + specifier: 16.3.0-canary.4 version: link:../next-env '@swc/helpers': specifier: 0.5.15 @@ -1181,19 +1181,19 @@ importers: specifier: 1.2.0 version: 1.2.0 '@next/font': - specifier: 16.3.0-canary.3 + specifier: 16.3.0-canary.4 version: link:../font '@next/polyfill-module': - specifier: 16.3.0-canary.3 + specifier: 16.3.0-canary.4 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 16.3.0-canary.3 + specifier: 16.3.0-canary.4 version: link:../next-polyfill-nomodule '@next/react-refresh-utils': - specifier: 16.3.0-canary.3 + specifier: 16.3.0-canary.4 version: link:../react-refresh-utils '@next/swc': - specifier: 16.3.0-canary.3 + specifier: 16.3.0-canary.4 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1927,7 +1927,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 16.3.0-canary.3 + specifier: 16.3.0-canary.4 version: link:../next outdent: specifier: 0.8.0