1use std::collections::BTreeMap;
2
3use anyhow::{Context, Result};
4use rustc_hash::FxHashMap;
5use turbo_rcstr::RcStr;
6use turbo_tasks::{FxIndexMap, ResolvedVc, Value, Vc, fxindexmap};
7use turbo_tasks_fs::{FileSystem, FileSystemPath};
8use turbopack_core::{
9 reference_type::{CommonJsReferenceSubType, ReferenceType},
10 resolve::{
11 AliasPattern, ExternalTraced, ExternalType, ResolveAliasMap, SubpathValue,
12 node::node_cjs_resolve_options,
13 options::{ConditionValue, ImportMap, ImportMapping, ResolvedMap},
14 parse::Request,
15 pattern::Pattern,
16 resolve,
17 },
18 source::Source,
19};
20use turbopack_node::execution_context::ExecutionContext;
21
22use crate::{
23 embed_js::{VIRTUAL_PACKAGE_NAME, next_js_fs},
24 mode::NextMode,
25 next_client::context::ClientContextType,
26 next_config::NextConfig,
27 next_edge::unsupported::NextEdgeUnsupportedModuleReplacer,
28 next_font::google::{
29 GOOGLE_FONTS_INTERNAL_PREFIX, NextFontGoogleCssModuleReplacer,
30 NextFontGoogleFontFileReplacer, NextFontGoogleReplacer,
31 },
32 next_server::context::ServerContextType,
33 util::NextRuntime,
34};
35
36const EDGE_UNSUPPORTED_NODE_INTERNALS: [&str; 44] = [
43 "child_process",
44 "cluster",
45 "console",
46 "constants",
47 "crypto",
48 "dgram",
49 "diagnostics_channel",
50 "dns",
51 "dns/promises",
52 "domain",
53 "fs",
54 "fs/promises",
55 "http",
56 "http2",
57 "https",
58 "inspector",
59 "module",
60 "net",
61 "os",
62 "path",
63 "path/posix",
64 "path/win32",
65 "perf_hooks",
66 "process",
67 "punycode",
68 "querystring",
69 "readline",
70 "repl",
71 "stream",
72 "stream/promises",
73 "stream/web",
74 "string_decoder",
75 "sys",
76 "timers",
77 "timers/promises",
78 "tls",
79 "trace_events",
80 "tty",
81 "v8",
82 "vm",
83 "wasi",
84 "worker_threads",
85 "zlib",
86 "pnpapi",
87];
88
89#[turbo_tasks::function]
92pub async fn get_next_client_import_map(
93 project_path: ResolvedVc<FileSystemPath>,
94 ty: Value<ClientContextType>,
95 next_config: Vc<NextConfig>,
96 execution_context: Vc<ExecutionContext>,
97) -> Result<Vc<ImportMap>> {
98 let mut import_map = ImportMap::empty();
99
100 insert_next_shared_aliases(
101 &mut import_map,
102 project_path,
103 execution_context,
104 next_config,
105 false,
106 )
107 .await?;
108
109 insert_optimized_module_aliases(&mut import_map, project_path).await?;
110
111 insert_alias_option(
112 &mut import_map,
113 project_path,
114 next_config.resolve_alias_options(),
115 ["browser"],
116 )
117 .await?;
118
119 match ty.into_value() {
120 ClientContextType::Pages { .. } => {}
121 ClientContextType::App { app_dir } => {
122 let react_flavor = if *next_config.enable_ppr().await?
123 || *next_config.enable_taint().await?
124 || *next_config.enable_view_transition().await?
125 || *next_config.enable_router_bfcache().await?
126 {
127 "-experimental"
128 } else {
129 ""
130 };
131
132 import_map.insert_exact_alias(
133 "react",
134 request_to_import_mapping(
135 app_dir,
136 &format!("next/dist/compiled/react{react_flavor}"),
137 ),
138 );
139 import_map.insert_wildcard_alias(
140 "react/",
141 request_to_import_mapping(
142 app_dir,
143 &format!("next/dist/compiled/react{react_flavor}/*"),
144 ),
145 );
146 import_map.insert_exact_alias(
147 "react-dom",
148 request_to_import_mapping(
149 app_dir,
150 &format!("next/dist/compiled/react-dom{react_flavor}"),
151 ),
152 );
153 import_map.insert_exact_alias(
154 "react-dom/static",
155 request_to_import_mapping(
156 app_dir,
157 "next/dist/compiled/react-dom-experimental/static",
158 ),
159 );
160 import_map.insert_exact_alias(
161 "react-dom/static.edge",
162 request_to_import_mapping(
163 app_dir,
164 "next/dist/compiled/react-dom-experimental/static.edge",
165 ),
166 );
167 import_map.insert_exact_alias(
168 "react-dom/static.browser",
169 request_to_import_mapping(
170 app_dir,
171 "next/dist/compiled/react-dom-experimental/static.browser",
172 ),
173 );
174 let react_client_package = get_react_client_package(next_config).await?;
175 import_map.insert_exact_alias(
176 "react-dom/client",
177 request_to_import_mapping(
178 app_dir,
179 &format!("next/dist/compiled/react-dom{react_flavor}/{react_client_package}"),
180 ),
181 );
182 import_map.insert_wildcard_alias(
183 "react-dom/",
184 request_to_import_mapping(
185 app_dir,
186 &format!("next/dist/compiled/react-dom{react_flavor}/*"),
187 ),
188 );
189 import_map.insert_wildcard_alias(
190 "react-server-dom-webpack/",
191 request_to_import_mapping(app_dir, "react-server-dom-turbopack/*"),
192 );
193 import_map.insert_wildcard_alias(
194 "react-server-dom-turbopack/",
195 request_to_import_mapping(
196 app_dir,
197 &format!("next/dist/compiled/react-server-dom-turbopack{react_flavor}/*"),
198 ),
199 );
200 insert_exact_alias_or_js(
201 &mut import_map,
202 "next/head",
203 request_to_import_mapping(project_path, "next/dist/client/components/noop-head"),
204 );
205 insert_exact_alias_or_js(
206 &mut import_map,
207 "next/dynamic",
208 request_to_import_mapping(project_path, "next/dist/shared/lib/app-dynamic"),
209 );
210 insert_exact_alias_or_js(
211 &mut import_map,
212 "next/link",
213 request_to_import_mapping(project_path, "next/dist/client/app-dir/link"),
214 );
215 insert_exact_alias_or_js(
216 &mut import_map,
217 "next/form",
218 request_to_import_mapping(project_path, "next/dist/client/app-dir/form"),
219 );
220 }
221 ClientContextType::Fallback => {}
222 ClientContextType::Other => {}
223 }
224
225 insert_exact_alias_map(
227 &mut import_map,
228 project_path,
229 fxindexmap! {
230 "server-only" => "next/dist/compiled/server-only/index".to_string(),
231 "client-only" => "next/dist/compiled/client-only/index".to_string(),
232 "next/dist/compiled/server-only" => "next/dist/compiled/server-only/index".to_string(),
233 "next/dist/compiled/client-only" => "next/dist/compiled/client-only/index".to_string(),
234 },
235 );
236
237 match ty.into_value() {
238 ClientContextType::Pages { .. }
239 | ClientContextType::App { .. }
240 | ClientContextType::Fallback => {
241 for (original, alias) in NEXT_ALIASES {
242 import_map.insert_exact_alias(
243 format!("node:{original}"),
244 request_to_import_mapping(project_path, alias),
245 );
246 }
247 }
248 ClientContextType::Other => {}
249 }
250
251 insert_turbopack_dev_alias(&mut import_map).await?;
252 insert_instrumentation_client_alias(&mut import_map, project_path).await?;
253
254 Ok(import_map.cell())
255}
256
257#[turbo_tasks::function]
260pub async fn get_next_client_fallback_import_map(
261 ty: Value<ClientContextType>,
262) -> Result<Vc<ImportMap>> {
263 let mut import_map = ImportMap::empty();
264
265 match ty.into_value() {
266 ClientContextType::Pages {
267 pages_dir: context_dir,
268 }
269 | ClientContextType::App {
270 app_dir: context_dir,
271 } => {
272 for (original, alias) in NEXT_ALIASES {
273 import_map
274 .insert_exact_alias(original, request_to_import_mapping(context_dir, alias));
275 }
276 }
277 ClientContextType::Fallback => {}
278 ClientContextType::Other => {}
279 }
280
281 insert_turbopack_dev_alias(&mut import_map).await?;
282
283 Ok(import_map.cell())
284}
285
286#[turbo_tasks::function]
288pub async fn get_next_server_import_map(
289 project_path: ResolvedVc<FileSystemPath>,
290 ty: Value<ServerContextType>,
291 next_config: Vc<NextConfig>,
292 execution_context: Vc<ExecutionContext>,
293) -> Result<Vc<ImportMap>> {
294 let mut import_map = ImportMap::empty();
295
296 insert_next_shared_aliases(
297 &mut import_map,
298 project_path,
299 execution_context,
300 next_config,
301 false,
302 )
303 .await?;
304
305 insert_alias_option(
306 &mut import_map,
307 project_path,
308 next_config.resolve_alias_options(),
309 [],
310 )
311 .await?;
312
313 let ty = ty.into_value();
314
315 let external = ImportMapping::External(None, ExternalType::CommonJs, ExternalTraced::Traced)
316 .resolved_cell();
317
318 import_map.insert_exact_alias("next/dist/server/require-hook", external);
319 match ty {
320 ServerContextType::Pages { .. }
321 | ServerContextType::PagesData { .. }
322 | ServerContextType::PagesApi { .. } => {
323 import_map.insert_exact_alias("react", external);
324 import_map.insert_wildcard_alias("react/", external);
325 import_map.insert_exact_alias("react-dom", external);
326 import_map.insert_exact_alias("react-dom/client", external);
327 import_map.insert_wildcard_alias("react-dom/", external);
328 import_map.insert_exact_alias("styled-jsx", external);
329 import_map.insert_exact_alias(
330 "styled-jsx/style",
331 ImportMapping::External(
332 Some("styled-jsx/style.js".into()),
333 ExternalType::CommonJs,
334 ExternalTraced::Traced,
335 )
336 .resolved_cell(),
337 );
338 import_map.insert_wildcard_alias("styled-jsx/", external);
339 import_map.insert_wildcard_alias("next/dist/build/utils", external);
341 }
342 ServerContextType::AppSSR { .. }
343 | ServerContextType::AppRSC { .. }
344 | ServerContextType::AppRoute { .. } => {
345 insert_exact_alias_or_js(
346 &mut import_map,
347 "next/head",
348 request_to_import_mapping(project_path, "next/dist/client/components/noop-head"),
349 );
350 insert_exact_alias_or_js(
351 &mut import_map,
352 "next/dynamic",
353 request_to_import_mapping(project_path, "next/dist/shared/lib/app-dynamic"),
354 );
355 insert_exact_alias_or_js(
356 &mut import_map,
357 "next/link",
358 request_to_import_mapping(project_path, "next/dist/client/app-dir/link"),
359 );
360 insert_exact_alias_or_js(
361 &mut import_map,
362 "next/form",
363 request_to_import_mapping(project_path, "next/dist/client/app-dir/form"),
364 );
365 }
366 ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => {}
367 }
368
369 insert_next_server_special_aliases(
370 &mut import_map,
371 project_path,
372 ty,
373 NextRuntime::NodeJs,
374 next_config,
375 )
376 .await?;
377
378 Ok(import_map.cell())
379}
380
381#[turbo_tasks::function]
383pub async fn get_next_edge_import_map(
384 project_path: ResolvedVc<FileSystemPath>,
385 ty: Value<ServerContextType>,
386 next_config: Vc<NextConfig>,
387 execution_context: Vc<ExecutionContext>,
388) -> Result<Vc<ImportMap>> {
389 let mut import_map = ImportMap::empty();
390
391 insert_wildcard_alias_map(
395 &mut import_map,
396 project_path,
397 fxindexmap! {
398 "next/dist/build/" => "next/dist/esm/build/*".to_string(),
399 "next/dist/client/" => "next/dist/esm/client/*".to_string(),
400 "next/dist/shared/" => "next/dist/esm/shared/*".to_string(),
401 "next/dist/pages/" => "next/dist/esm/pages/*".to_string(),
402 "next/dist/lib/" => "next/dist/esm/lib/*".to_string(),
403 "next/dist/server/" => "next/dist/esm/server/*".to_string(),
404 "next/dist/api/" => "next/dist/esm/api/*".to_string(),
405 },
406 );
407
408 insert_exact_alias_map(
410 &mut import_map,
411 project_path,
412 fxindexmap! {
413 "next/app" => "next/dist/api/app".to_string(),
414 "next/document" => "next/dist/api/document".to_string(),
415 "next/dynamic" => "next/dist/api/dynamic".to_string(),
416 "next/form" => "next/dist/api/form".to_string(),
417 "next/head" => "next/dist/api/head".to_string(),
418 "next/headers" => "next/dist/api/headers".to_string(),
419 "next/image" => "next/dist/api/image".to_string(),
420 "next/link" => "next/dist/api/link".to_string(),
421 "next/form" => "next/dist/api/form".to_string(),
422 "next/navigation" => "next/dist/api/navigation".to_string(),
423 "next/router" => "next/dist/api/router".to_string(),
424 "next/script" => "next/dist/api/script".to_string(),
425 "next/server" => "next/dist/api/server".to_string(),
426 "next/og" => "next/dist/api/og".to_string(),
427
428 "next/dist/compiled/@vercel/og/index.node.js" => "next/dist/compiled/@vercel/og/index.edge.js".to_string(),
430 },
431 );
432
433 insert_next_shared_aliases(
434 &mut import_map,
435 project_path,
436 execution_context,
437 next_config,
438 true,
439 )
440 .await?;
441
442 insert_optimized_module_aliases(&mut import_map, project_path).await?;
443
444 insert_alias_option(
445 &mut import_map,
446 project_path,
447 next_config.resolve_alias_options(),
448 [],
449 )
450 .await?;
451
452 let ty = ty.into_value();
453 match ty {
454 ServerContextType::Pages { .. }
455 | ServerContextType::PagesData { .. }
456 | ServerContextType::PagesApi { .. }
457 | ServerContextType::Middleware { .. }
458 | ServerContextType::Instrumentation { .. } => {}
459 ServerContextType::AppSSR { .. }
460 | ServerContextType::AppRSC { .. }
461 | ServerContextType::AppRoute { .. } => {
462 insert_exact_alias_or_js(
463 &mut import_map,
464 "next/head",
465 request_to_import_mapping(project_path, "next/dist/client/components/noop-head"),
466 );
467 insert_exact_alias_or_js(
468 &mut import_map,
469 "next/dynamic",
470 request_to_import_mapping(project_path, "next/dist/shared/lib/app-dynamic"),
471 );
472 insert_exact_alias_or_js(
473 &mut import_map,
474 "next/link",
475 request_to_import_mapping(project_path, "next/dist/client/app-dir/link"),
476 );
477 }
478 }
479
480 insert_next_server_special_aliases(
481 &mut import_map,
482 project_path,
483 ty,
484 NextRuntime::Edge,
485 next_config,
486 )
487 .await?;
488
489 match ty {
492 ServerContextType::AppSSR { .. }
493 | ServerContextType::AppRSC { .. }
494 | ServerContextType::AppRoute { .. }
495 | ServerContextType::Middleware { .. }
496 | ServerContextType::Instrumentation { .. }
497 | ServerContextType::Pages { .. }
498 | ServerContextType::PagesData { .. }
499 | ServerContextType::PagesApi { .. } => {
500 insert_unsupported_node_internal_aliases(&mut import_map).await?;
501 }
502 }
503
504 Ok(import_map.cell())
505}
506
507async fn insert_unsupported_node_internal_aliases(import_map: &mut ImportMap) -> Result<()> {
511 let unsupported_replacer = ImportMapping::Dynamic(ResolvedVc::upcast(
512 NextEdgeUnsupportedModuleReplacer::new()
513 .to_resolved()
514 .await?,
515 ))
516 .resolved_cell();
517
518 EDGE_UNSUPPORTED_NODE_INTERNALS.iter().for_each(|module| {
519 import_map.insert_alias(AliasPattern::exact(*module), unsupported_replacer);
520 });
521 Ok(())
522}
523
524pub fn get_next_client_resolved_map(
525 _context: Vc<FileSystemPath>,
526 _root: ResolvedVc<FileSystemPath>,
527 _mode: NextMode,
528) -> Vc<ResolvedMap> {
529 let glob_mappings = vec![];
530 ResolvedMap {
531 by_glob: glob_mappings,
532 }
533 .cell()
534}
535
536static NEXT_ALIASES: [(&str, &str); 23] = [
537 ("assert", "next/dist/compiled/assert"),
538 ("buffer", "next/dist/compiled/buffer"),
539 ("constants", "next/dist/compiled/constants-browserify"),
540 ("crypto", "next/dist/compiled/crypto-browserify"),
541 ("domain", "next/dist/compiled/domain-browser"),
542 ("http", "next/dist/compiled/stream-http"),
543 ("https", "next/dist/compiled/https-browserify"),
544 ("os", "next/dist/compiled/os-browserify"),
545 ("path", "next/dist/compiled/path-browserify"),
546 ("punycode", "next/dist/compiled/punycode"),
547 ("process", "next/dist/build/polyfills/process"),
548 ("querystring", "next/dist/compiled/querystring-es3"),
549 ("stream", "next/dist/compiled/stream-browserify"),
550 ("string_decoder", "next/dist/compiled/string_decoder"),
551 ("sys", "next/dist/compiled/util"),
552 ("timers", "next/dist/compiled/timers-browserify"),
553 ("tty", "next/dist/compiled/tty-browserify"),
554 ("url", "next/dist/compiled/native-url"),
555 ("util", "next/dist/compiled/util"),
556 ("vm", "next/dist/compiled/vm-browserify"),
557 ("zlib", "next/dist/compiled/browserify-zlib"),
558 ("events", "next/dist/compiled/events"),
559 ("setImmediate", "next/dist/compiled/setimmediate"),
560];
561
562async fn insert_next_server_special_aliases(
563 import_map: &mut ImportMap,
564 project_path: ResolvedVc<FileSystemPath>,
565 ty: ServerContextType,
566 runtime: NextRuntime,
567 next_config: Vc<NextConfig>,
568) -> Result<()> {
569 let external_cjs_if_node =
570 move |context_dir: ResolvedVc<FileSystemPath>, request: &str| match runtime {
571 NextRuntime::Edge => request_to_import_mapping(context_dir, request),
572 NextRuntime::NodeJs => external_request_to_cjs_import_mapping(context_dir, request),
573 };
574 let external_esm_if_node =
575 move |context_dir: ResolvedVc<FileSystemPath>, request: &str| match runtime {
576 NextRuntime::Edge => request_to_import_mapping(context_dir, request),
577 NextRuntime::NodeJs => external_request_to_esm_import_mapping(context_dir, request),
578 };
579
580 import_map.insert_exact_alias(
581 "next/dist/compiled/@vercel/og/index.node.js",
582 external_esm_if_node(project_path, "next/dist/compiled/@vercel/og/index.node.js"),
583 );
584
585 import_map.insert_exact_alias(
586 "next/dist/server/ReactDOMServerPages",
587 ImportMapping::Alternatives(vec![
588 request_to_import_mapping(project_path, "react-dom/server.edge"),
589 request_to_import_mapping(project_path, "react-dom/server.browser"),
590 ])
591 .resolved_cell(),
592 );
593
594 import_map.insert_exact_alias(
595 "@opentelemetry/api",
596 ImportMapping::Alternatives(vec![
598 external_cjs_if_node(project_path, "@opentelemetry/api"),
599 external_cjs_if_node(project_path, "next/dist/compiled/@opentelemetry/api"),
600 ])
601 .resolved_cell(),
602 );
603
604 match ty {
605 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {}
606 ServerContextType::PagesData { .. } => {}
607 ServerContextType::AppSSR { app_dir }
609 | ServerContextType::AppRSC { app_dir, .. }
610 | ServerContextType::AppRoute { app_dir, .. } => {
611 let next_package = get_next_package(*app_dir).to_resolved().await?;
612 import_map.insert_exact_alias(
613 "styled-jsx",
614 request_to_import_mapping(next_package, "styled-jsx"),
615 );
616 import_map.insert_wildcard_alias(
617 "styled-jsx/",
618 request_to_import_mapping(next_package, "styled-jsx/*"),
619 );
620
621 rsc_aliases(import_map, project_path, ty, runtime, next_config).await?;
622 }
623 ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => {
624 rsc_aliases(import_map, project_path, ty, runtime, next_config).await?;
625 }
626 }
627
628 match ty {
634 ServerContextType::Pages { .. } => {
635 insert_exact_alias_map(
636 import_map,
637 project_path,
638 fxindexmap! {
639 "server-only" => "next/dist/compiled/server-only/empty".to_string(),
640 "client-only" => "next/dist/compiled/client-only/index".to_string(),
641 "next/dist/compiled/server-only" => "next/dist/compiled/server-only/empty".to_string(),
642 "next/dist/compiled/client-only" => "next/dist/compiled/client-only/index".to_string(),
643 },
644 );
645 }
646 ServerContextType::PagesData { .. }
647 | ServerContextType::PagesApi { .. }
648 | ServerContextType::AppRSC { .. }
649 | ServerContextType::AppRoute { .. }
650 | ServerContextType::Middleware { .. }
651 | ServerContextType::Instrumentation { .. } => {
652 insert_exact_alias_map(
653 import_map,
654 project_path,
655 fxindexmap! {
656 "server-only" => "next/dist/compiled/server-only/empty".to_string(),
657 "client-only" => "next/dist/compiled/client-only/error".to_string(),
658 "next/dist/compiled/server-only" => "next/dist/compiled/server-only/empty".to_string(),
659 "next/dist/compiled/client-only" => "next/dist/compiled/client-only/error".to_string(),
660 },
661 );
662 }
663 ServerContextType::AppSSR { .. } => {
664 insert_exact_alias_map(
665 import_map,
666 project_path,
667 fxindexmap! {
668 "server-only" => "next/dist/compiled/server-only/index".to_string(),
669 "client-only" => "next/dist/compiled/client-only/index".to_string(),
670 "next/dist/compiled/server-only" => "next/dist/compiled/server-only/index".to_string(),
671 "next/dist/compiled/client-only" => "next/dist/compiled/client-only/index".to_string(),
672 },
673 );
674 }
675 }
676
677 import_map.insert_exact_alias(
678 "@vercel/og",
679 external_cjs_if_node(project_path, "next/dist/server/og/image-response"),
680 );
681
682 Ok(())
683}
684
685async fn get_react_client_package(next_config: Vc<NextConfig>) -> Result<&'static str> {
686 let react_production_profiling = *next_config.enable_react_production_profiling().await?;
687 let react_client_package = if react_production_profiling {
688 "profiling"
689 } else {
690 "client"
691 };
692
693 Ok(react_client_package)
694}
695
696async fn rsc_aliases(
697 import_map: &mut ImportMap,
698 project_path: ResolvedVc<FileSystemPath>,
699 ty: ServerContextType,
700 runtime: NextRuntime,
701 next_config: Vc<NextConfig>,
702) -> Result<()> {
703 let ppr = *next_config.enable_ppr().await?;
704 let taint = *next_config.enable_taint().await?;
705 let router_bfcache = *next_config.enable_router_bfcache().await?;
706 let view_transition = *next_config.enable_view_transition().await?;
707 let react_channel = if ppr || taint || view_transition || router_bfcache {
708 "-experimental"
709 } else {
710 ""
711 };
712 let react_client_package = get_react_client_package(next_config).await?;
713
714 let mut alias = FxIndexMap::default();
715 if matches!(
716 ty,
717 ServerContextType::AppSSR { .. }
718 | ServerContextType::AppRSC { .. }
719 | ServerContextType::AppRoute { .. }
720 ) {
721 alias.extend(fxindexmap! {
722 "react" => format!("next/dist/compiled/react{react_channel}"),
723 "react-dom" => format!("next/dist/compiled/react-dom{react_channel}"),
724 "react/jsx-runtime" => format!("next/dist/compiled/react{react_channel}/jsx-runtime"),
725 "react/jsx-dev-runtime" => format!("next/dist/compiled/react{react_channel}/jsx-dev-runtime"),
726 "react/compiler-runtime" => format!("next/dist/compiled/react{react_channel}/compiler-runtime"),
727 "react-dom/client" => format!("next/dist/compiled/react-dom{react_channel}/{react_client_package}"),
728 "react-dom/static" => format!("next/dist/compiled/react-dom{react_channel}/static"),
729 "react-dom/static.edge" => format!("next/dist/compiled/react-dom{react_channel}/static.edge"),
730 "react-dom/static.browser" => format!("next/dist/compiled/react-dom{react_channel}/static.browser"),
731 "react-dom/server" => format!("next/dist/compiled/react-dom{react_channel}/server"),
732 "react-dom/server.edge" => format!("next/dist/compiled/react-dom{react_channel}/server.edge"),
733 "react-dom/server.browser" => format!("next/dist/compiled/react-dom{react_channel}/server.browser"),
734 });
735 }
736 alias.extend(fxindexmap! {
737 "react-server-dom-webpack/client" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client"),
738 "react-server-dom-webpack/client.edge" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge"),
739 "react-server-dom-webpack/server.edge" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge"),
740 "react-server-dom-webpack/server.node" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node"),
741 "react-server-dom-webpack/static.edge" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge"),
742 "react-server-dom-turbopack/client" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client"),
743 "react-server-dom-turbopack/client.edge" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge"),
744 "react-server-dom-turbopack/server.edge" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge"),
745 "react-server-dom-turbopack/server.node" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node"),
746 "react-server-dom-turbopack/static.edge" => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge"),
747 });
748
749 if runtime == NextRuntime::NodeJs {
750 match ty {
751 ServerContextType::AppSSR { .. } => {
752 alias.extend(fxindexmap! {
753 "react/jsx-runtime" => format!("next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime"),
754 "react/jsx-dev-runtime" => format!("next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-dev-runtime"),
755 "react/compiler-runtime" => format!("next/dist/server/route-modules/app-page/vendored/ssr/react-compiler-runtime"),
756 "react" => format!("next/dist/server/route-modules/app-page/vendored/ssr/react"),
757 "react-dom" => format!("next/dist/server/route-modules/app-page/vendored/ssr/react-dom"),
758 "react-server-dom-webpack/client.edge" => format!("next/dist/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client-edge"),
759 "react-server-dom-turbopack/client.edge" => format!("next/dist/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client-edge"),
760 });
761 }
762 ServerContextType::AppRSC { .. }
763 | ServerContextType::AppRoute { .. }
764 | ServerContextType::Middleware { .. }
765 | ServerContextType::Instrumentation { .. } => {
766 alias.extend(fxindexmap! {
767 "react/jsx-runtime" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-jsx-runtime"),
768 "react/jsx-dev-runtime" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-jsx-dev-runtime"),
769 "react/compiler-runtime" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-compiler-runtime"),
770 "react" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react"),
771 "react-dom" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-dom"),
772 "react-server-dom-webpack/server.edge" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server-edge"),
773 "react-server-dom-webpack/server.node" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server-node"),
774 "react-server-dom-webpack/static.edge" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-static-edge"),
775 "react-server-dom-turbopack/server.edge" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server-edge"),
776 "react-server-dom-turbopack/server.node" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server-node"),
777 "react-server-dom-turbopack/static.edge" => format!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-static-edge"),
778 "next/navigation" => format!("next/dist/api/navigation.react-server"),
779
780 "next/dist/compiled/react" => format!("next/dist/compiled/react/index.js"),
782 });
783 }
784 _ => {}
785 }
786 }
787
788 if runtime == NextRuntime::Edge && ty.supports_react_server() {
789 alias.extend(fxindexmap! {
790 "react" => format!("next/dist/compiled/react{react_channel}/react.react-server"),
791 "next/dist/compiled/react" => format!("next/dist/compiled/react{react_channel}/react.react-server"),
792 "next/dist/compiled/react-experimental" => format!("next/dist/compiled/react-experimental/react.react-server"),
793 "react/jsx-runtime" => format!("next/dist/compiled/react{react_channel}/jsx-runtime.react-server"),
794 "react/compiler-runtime" => format!("next/dist/compiled/react{react_channel}/compiler-runtime"),
795 "next/dist/compiled/react/jsx-runtime" => format!("next/dist/compiled/react{react_channel}/jsx-runtime.react-server"),
796 "next/dist/compiled/react-experimental/jsx-runtime" => format!("next/dist/compiled/react-experimental/jsx-runtime.react-server"),
797 "next/dist/compiled/react/compiler-runtime" => format!("next/dist/compiled/react{react_channel}/compiler-runtime"),
798 "react/jsx-dev-runtime" => format!("next/dist/compiled/react{react_channel}/jsx-dev-runtime.react-server"),
799 "next/dist/compiled/react/jsx-dev-runtime" => format!("next/dist/compiled/react{react_channel}/jsx-dev-runtime.react-server"),
800 "next/dist/compiled/react-experimental/jsx-dev-runtime" => format!("next/dist/compiled/react-experimental/jsx-dev-runtime.react-server"),
801 "react-dom" => format!("next/dist/compiled/react-dom{react_channel}/react-dom.react-server"),
802 "next/dist/compiled/react-dom" => format!("next/dist/compiled/react-dom{react_channel}/react-dom.react-server"),
803 "next/dist/compiled/react-dom-experimental" => format!("next/dist/compiled/react-dom-experimental/react-dom.react-server"),
804 "next/navigation" => format!("next/dist/api/navigation.react-server"),
805 })
806 }
807
808 insert_exact_alias_map(import_map, project_path, alias);
809
810 Ok(())
811}
812
813pub fn mdx_import_source_file() -> RcStr {
814 format!("{VIRTUAL_PACKAGE_NAME}/mdx-import-source").into()
815}
816
817async fn insert_optimized_module_aliases(
820 import_map: &mut ImportMap,
821 project_path: ResolvedVc<FileSystemPath>,
822) -> Result<()> {
823 insert_exact_alias_map(
824 import_map,
825 project_path,
826 fxindexmap! {
827 "unfetch" => "next/dist/build/polyfills/fetch/index.js".to_string(),
828 "isomorphic-unfetch" => "next/dist/build/polyfills/fetch/index.js".to_string(),
829 "whatwg-fetch" => "next/dist/build/polyfills/fetch/whatwg-fetch.js".to_string(),
830 "object-assign" => "next/dist/build/polyfills/object-assign.js".to_string(),
831 "object.assign/auto" => "next/dist/build/polyfills/object.assign/auto.js".to_string(),
832 "object.assign/implementation" => "next/dist/build/polyfills/object.assign/implementation.js".to_string(),
833 "object.assign/polyfill" => "next/dist/build/polyfills/object.assign/polyfill.js".to_string(),
834 "object.assign/shim" => "next/dist/build/polyfills/object.assign/shim.js".to_string(),
835 "url" => "next/dist/compiled/native-url".to_string(),
836 "node:url" => "next/dist/compiled/native-url".to_string(),
837 },
838 );
839 Ok(())
840}
841
842async fn insert_next_shared_aliases(
844 import_map: &mut ImportMap,
845 project_path: ResolvedVc<FileSystemPath>,
846 execution_context: Vc<ExecutionContext>,
847 next_config: Vc<NextConfig>,
848 is_runtime_edge: bool,
849) -> Result<()> {
850 let package_root = next_js_fs().root().to_resolved().await?;
851
852 insert_alias_to_alternatives(
853 import_map,
854 mdx_import_source_file(),
855 vec![
856 request_to_import_mapping(project_path, "./mdx-components"),
857 request_to_import_mapping(project_path, "./src/mdx-components"),
858 request_to_import_mapping(project_path, "@mdx-js/react"),
859 ],
860 );
861
862 insert_package_alias(
863 import_map,
864 &format!("{VIRTUAL_PACKAGE_NAME}/"),
865 package_root,
866 );
867
868 let next_font_google_replacer_mapping = ImportMapping::Dynamic(ResolvedVc::upcast(
874 NextFontGoogleReplacer::new(*project_path)
875 .to_resolved()
876 .await?,
877 ))
878 .resolved_cell();
879
880 import_map.insert_alias(
881 AliasPattern::exact("next/font/google/target.css"),
883 next_font_google_replacer_mapping,
884 );
885
886 import_map.insert_alias(
887 AliasPattern::exact("@next/font/google/target.css"),
889 next_font_google_replacer_mapping,
890 );
891
892 import_map.insert_alias(
893 AliasPattern::exact("@vercel/turbopack-next/internal/font/google/cssmodule.module.css"),
894 ImportMapping::Dynamic(ResolvedVc::upcast(
895 NextFontGoogleCssModuleReplacer::new(*project_path, execution_context)
896 .to_resolved()
897 .await?,
898 ))
899 .resolved_cell(),
900 );
901
902 import_map.insert_alias(
903 AliasPattern::exact(GOOGLE_FONTS_INTERNAL_PREFIX),
904 ImportMapping::Dynamic(ResolvedVc::upcast(
905 NextFontGoogleFontFileReplacer::new(*project_path)
906 .to_resolved()
907 .await?,
908 ))
909 .resolved_cell(),
910 );
911
912 let next_package = get_next_package(*project_path).to_resolved().await?;
913 import_map.insert_singleton_alias("@swc/helpers", next_package);
914 import_map.insert_singleton_alias("styled-jsx", next_package);
915 import_map.insert_singleton_alias("next", project_path);
916 import_map.insert_singleton_alias("react", project_path);
917 import_map.insert_singleton_alias("react-dom", project_path);
918 let react_client_package = get_react_client_package(next_config).await?;
919 import_map.insert_exact_alias(
920 "react-dom/client",
921 request_to_import_mapping(project_path, &format!("react-dom/{react_client_package}")),
922 );
923
924 import_map.insert_alias(
925 AliasPattern::exact("next"),
928 ImportMapping::Empty.resolved_cell(),
929 );
930
931 import_map.insert_exact_alias(
933 "setimmediate",
934 request_to_import_mapping(project_path, "next/dist/compiled/setimmediate"),
935 );
936
937 import_map.insert_exact_alias(
938 "private-next-rsc-server-reference",
939 request_to_import_mapping(
940 project_path,
941 "next/dist/build/webpack/loaders/next-flight-loader/server-reference",
942 ),
943 );
944 import_map.insert_exact_alias(
945 "private-next-rsc-action-client-wrapper",
946 request_to_import_mapping(
947 project_path,
948 "next/dist/build/webpack/loaders/next-flight-loader/action-client-wrapper",
949 ),
950 );
951 import_map.insert_exact_alias(
952 "private-next-rsc-action-validate",
953 request_to_import_mapping(
954 project_path,
955 "next/dist/build/webpack/loaders/next-flight-loader/action-validate",
956 ),
957 );
958 import_map.insert_exact_alias(
959 "private-next-rsc-action-encryption",
960 request_to_import_mapping(project_path, "next/dist/server/app-render/encryption"),
961 );
962 import_map.insert_exact_alias(
963 "private-next-rsc-cache-wrapper",
964 request_to_import_mapping(
965 project_path,
966 "next/dist/build/webpack/loaders/next-flight-loader/cache-wrapper",
967 ),
968 );
969 import_map.insert_exact_alias(
970 "private-next-rsc-track-dynamic-import",
971 request_to_import_mapping(
972 project_path,
973 "next/dist/build/webpack/loaders/next-flight-loader/track-dynamic-import",
974 ),
975 );
976
977 insert_turbopack_dev_alias(import_map).await?;
978 insert_package_alias(
979 import_map,
980 "@vercel/turbopack-node/",
981 turbopack_node::embed_js::embed_fs()
982 .root()
983 .to_resolved()
984 .await?,
985 );
986
987 let image_config = next_config.image_config().await?;
988 if let Some(loader_file) = image_config.loader_file.as_deref() {
989 import_map.insert_exact_alias(
990 "next/dist/shared/lib/image-loader",
991 request_to_import_mapping(project_path, loader_file),
992 );
993
994 if is_runtime_edge {
995 import_map.insert_exact_alias(
996 "next/dist/esm/shared/lib/image-loader",
997 request_to_import_mapping(project_path, loader_file),
998 );
999 }
1000 }
1001
1002 Ok(())
1003}
1004
1005#[turbo_tasks::function]
1006pub async fn get_next_package(context_directory: Vc<FileSystemPath>) -> Result<Vc<FileSystemPath>> {
1007 let result = resolve(
1008 context_directory,
1009 Value::new(ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined)),
1010 Request::parse(Value::new(Pattern::Constant("next/package.json".into()))),
1011 node_cjs_resolve_options(context_directory.root()),
1012 );
1013 let source = result
1014 .first_source()
1015 .await?
1016 .context("Next.js package not found")?;
1017 Ok(source.ident().path().parent())
1018}
1019
1020pub async fn insert_alias_option<const N: usize>(
1021 import_map: &mut ImportMap,
1022 project_path: ResolvedVc<FileSystemPath>,
1023 alias_options: Vc<ResolveAliasMap>,
1024 conditions: [&'static str; N],
1025) -> Result<()> {
1026 let conditions = BTreeMap::from(conditions.map(|c| (c.into(), ConditionValue::Set)));
1027 for (alias, value) in &alias_options.await? {
1028 if let Some(mapping) = export_value_to_import_mapping(value, &conditions, project_path) {
1029 import_map.insert_alias(alias, mapping);
1030 }
1031 }
1032 Ok(())
1033}
1034
1035fn export_value_to_import_mapping(
1036 value: &SubpathValue,
1037 conditions: &BTreeMap<RcStr, ConditionValue>,
1038 project_path: ResolvedVc<FileSystemPath>,
1039) -> Option<ResolvedVc<ImportMapping>> {
1040 let mut result = Vec::new();
1041 value.add_results(
1042 conditions,
1043 &ConditionValue::Unset,
1044 &mut FxHashMap::default(),
1045 &mut result,
1046 );
1047 if result.is_empty() {
1048 None
1049 } else {
1050 Some(if result.len() == 1 {
1051 ImportMapping::PrimaryAlternative(result[0].0.into(), Some(project_path))
1052 .resolved_cell()
1053 } else {
1054 ImportMapping::Alternatives(
1055 result
1056 .iter()
1057 .map(|(m, _)| {
1058 ImportMapping::PrimaryAlternative((*m).into(), Some(project_path))
1059 .resolved_cell()
1060 })
1061 .collect(),
1062 )
1063 .resolved_cell()
1064 })
1065 }
1066}
1067
1068fn insert_exact_alias_map(
1069 import_map: &mut ImportMap,
1070 project_path: ResolvedVc<FileSystemPath>,
1071 map: FxIndexMap<&'static str, String>,
1072) {
1073 for (pattern, request) in map {
1074 import_map.insert_exact_alias(pattern, request_to_import_mapping(project_path, &request));
1075 }
1076}
1077
1078fn insert_wildcard_alias_map(
1079 import_map: &mut ImportMap,
1080 project_path: ResolvedVc<FileSystemPath>,
1081 map: FxIndexMap<&'static str, String>,
1082) {
1083 for (pattern, request) in map {
1084 import_map
1085 .insert_wildcard_alias(pattern, request_to_import_mapping(project_path, &request));
1086 }
1087}
1088
1089fn insert_alias_to_alternatives<'a>(
1091 import_map: &mut ImportMap,
1092 alias: impl Into<String> + 'a,
1093 alternatives: Vec<ResolvedVc<ImportMapping>>,
1094) {
1095 import_map.insert_exact_alias(
1096 alias.into(),
1097 ImportMapping::Alternatives(alternatives).resolved_cell(),
1098 );
1099}
1100
1101fn insert_package_alias(
1103 import_map: &mut ImportMap,
1104 prefix: &str,
1105 package_root: ResolvedVc<FileSystemPath>,
1106) {
1107 import_map.insert_wildcard_alias(
1108 prefix,
1109 ImportMapping::PrimaryAlternative("./*".into(), Some(package_root)).resolved_cell(),
1110 );
1111}
1112
1113async fn insert_turbopack_dev_alias(import_map: &mut ImportMap) -> Result<()> {
1115 insert_package_alias(
1116 import_map,
1117 "@vercel/turbopack-ecmascript-runtime/",
1118 turbopack_ecmascript_runtime::embed_fs()
1119 .root()
1120 .to_resolved()
1121 .await?,
1122 );
1123 Ok(())
1124}
1125
1126async fn insert_instrumentation_client_alias(
1128 import_map: &mut ImportMap,
1129 project_path: ResolvedVc<FileSystemPath>,
1130) -> Result<()> {
1131 insert_alias_to_alternatives(
1132 import_map,
1133 "private-next-instrumentation-client",
1134 vec![
1135 request_to_import_mapping(project_path, "./src/instrumentation-client"),
1136 request_to_import_mapping(project_path, "./src/instrumentation-client.ts"),
1137 request_to_import_mapping(project_path, "./instrumentation-client"),
1138 request_to_import_mapping(project_path, "./instrumentation-client.ts"),
1139 ImportMapping::Ignore.resolved_cell(),
1140 ],
1141 );
1142
1143 Ok(())
1144}
1145
1146fn insert_exact_alias_or_js(
1148 import_map: &mut ImportMap,
1149 pattern: &str,
1150 mapping: ResolvedVc<ImportMapping>,
1151) {
1152 import_map.insert_exact_alias(pattern, mapping);
1153 import_map.insert_exact_alias(format!("{pattern}.js"), mapping);
1154}
1155
1156fn request_to_import_mapping(
1159 context_path: ResolvedVc<FileSystemPath>,
1160 request: &str,
1161) -> ResolvedVc<ImportMapping> {
1162 ImportMapping::PrimaryAlternative(request.into(), Some(context_path)).resolved_cell()
1163}
1164
1165fn external_request_to_cjs_import_mapping(
1168 context_dir: ResolvedVc<FileSystemPath>,
1169 request: &str,
1170) -> ResolvedVc<ImportMapping> {
1171 ImportMapping::PrimaryAlternativeExternal {
1172 name: Some(request.into()),
1173 ty: ExternalType::CommonJs,
1174 traced: ExternalTraced::Traced,
1175 lookup_dir: context_dir,
1176 }
1177 .resolved_cell()
1178}
1179
1180fn external_request_to_esm_import_mapping(
1183 context_dir: ResolvedVc<FileSystemPath>,
1184 request: &str,
1185) -> ResolvedVc<ImportMapping> {
1186 ImportMapping::PrimaryAlternativeExternal {
1187 name: Some(request.into()),
1188 ty: ExternalType::EcmaScriptModule,
1189 traced: ExternalTraced::Traced,
1190 lookup_dir: context_dir,
1191 }
1192 .resolved_cell()
1193}