1use std::{collections::BTreeMap, sync::LazyLock};
2
3use anyhow::{Context, Result};
4use either::Either;
5use rustc_hash::FxHashMap;
6use turbo_rcstr::{RcStr, rcstr};
7use turbo_tasks::{FxIndexMap, ResolvedVc, Vc, fxindexmap};
8use turbo_tasks_fs::{FileSystem, FileSystemPath};
9use turbopack_core::{
10 reference_type::{CommonJsReferenceSubType, ReferenceType},
11 resolve::{
12 AliasPattern, ExternalTraced, ExternalType, ResolveAliasMap, SubpathValue,
13 node::node_cjs_resolve_options,
14 options::{ConditionValue, ImportMap, ImportMapping, ResolvedMap},
15 parse::Request,
16 pattern::Pattern,
17 resolve,
18 },
19 source::Source,
20};
21use turbopack_node::execution_context::ExecutionContext;
22
23use crate::{
24 app_structure::CollectedRootParams,
25 embed_js::{VIRTUAL_PACKAGE_NAME, next_js_fs},
26 mode::NextMode,
27 next_client::context::ClientContextType,
28 next_config::NextConfig,
29 next_edge::unsupported::NextEdgeUnsupportedModuleReplacer,
30 next_font::google::{
31 GOOGLE_FONTS_INTERNAL_PREFIX, NextFontGoogleCssModuleReplacer,
32 NextFontGoogleFontFileReplacer, NextFontGoogleReplacer,
33 },
34 next_root_params::insert_next_root_params_mapping,
35 next_server::context::ServerContextType,
36 util::NextRuntime,
37};
38
39static EDGE_UNSUPPORTED_NODE_INTERNALS: LazyLock<[RcStr; 44]> = LazyLock::new(|| {
46 [
47 rcstr!("child_process"),
48 rcstr!("cluster"),
49 rcstr!("console"),
50 rcstr!("constants"),
51 rcstr!("crypto"),
52 rcstr!("dgram"),
53 rcstr!("diagnostics_channel"),
54 rcstr!("dns"),
55 rcstr!("dns/promises"),
56 rcstr!("domain"),
57 rcstr!("fs"),
58 rcstr!("fs/promises"),
59 rcstr!("http"),
60 rcstr!("http2"),
61 rcstr!("https"),
62 rcstr!("inspector"),
63 rcstr!("module"),
64 rcstr!("net"),
65 rcstr!("os"),
66 rcstr!("path"),
67 rcstr!("path/posix"),
68 rcstr!("path/win32"),
69 rcstr!("perf_hooks"),
70 rcstr!("process"),
71 rcstr!("punycode"),
72 rcstr!("querystring"),
73 rcstr!("readline"),
74 rcstr!("repl"),
75 rcstr!("stream"),
76 rcstr!("stream/promises"),
77 rcstr!("stream/web"),
78 rcstr!("string_decoder"),
79 rcstr!("sys"),
80 rcstr!("timers"),
81 rcstr!("timers/promises"),
82 rcstr!("tls"),
83 rcstr!("trace_events"),
84 rcstr!("tty"),
85 rcstr!("v8"),
86 rcstr!("vm"),
87 rcstr!("wasi"),
88 rcstr!("worker_threads"),
89 rcstr!("zlib"),
90 rcstr!("pnpapi"),
91 ]
92});
93
94#[turbo_tasks::function]
97pub async fn get_next_client_import_map(
98 project_path: FileSystemPath,
99 ty: ClientContextType,
100 next_config: Vc<NextConfig>,
101 next_mode: Vc<NextMode>,
102 execution_context: Vc<ExecutionContext>,
103) -> Result<Vc<ImportMap>> {
104 let mut import_map = ImportMap::empty();
105
106 insert_next_shared_aliases(
107 &mut import_map,
108 project_path.clone(),
109 execution_context,
110 next_config,
111 next_mode,
112 false,
113 )
114 .await?;
115
116 insert_optimized_module_aliases(&mut import_map, project_path.clone()).await?;
117
118 insert_alias_option(
119 &mut import_map,
120 &project_path,
121 next_config.resolve_alias_options(),
122 ["browser"],
123 )
124 .await?;
125
126 match &ty {
127 ClientContextType::Pages { .. } => {}
128 ClientContextType::App { app_dir } => {
129 let react_flavor = if *next_config.enable_ppr().await?
130 || *next_config.enable_taint().await?
131 || *next_config.enable_view_transition().await?
132 || *next_config.enable_router_bfcache().await?
133 {
134 "-experimental"
135 } else {
136 ""
137 };
138
139 import_map.insert_exact_alias(
140 rcstr!("react"),
141 request_to_import_mapping(
142 app_dir.clone(),
143 format!("next/dist/compiled/react{react_flavor}").into(),
144 ),
145 );
146 import_map.insert_wildcard_alias(
147 rcstr!("react/"),
148 request_to_import_mapping(
149 app_dir.clone(),
150 format!("next/dist/compiled/react{react_flavor}/*").into(),
151 ),
152 );
153 import_map.insert_exact_alias(
154 rcstr!("react-dom"),
155 request_to_import_mapping(
156 app_dir.clone(),
157 format!("next/dist/compiled/react-dom{react_flavor}").into(),
158 ),
159 );
160 import_map.insert_exact_alias(
161 rcstr!("react-dom/static"),
162 request_to_import_mapping(
163 app_dir.clone(),
164 rcstr!("next/dist/compiled/react-dom-experimental/static"),
165 ),
166 );
167 import_map.insert_exact_alias(
168 rcstr!("react-dom/static.edge"),
169 request_to_import_mapping(
170 app_dir.clone(),
171 rcstr!("next/dist/compiled/react-dom-experimental/static.edge"),
172 ),
173 );
174 import_map.insert_exact_alias(
175 rcstr!("react-dom/static.browser"),
176 request_to_import_mapping(
177 app_dir.clone(),
178 rcstr!("next/dist/compiled/react-dom-experimental/static.browser"),
179 ),
180 );
181 let react_client_package = get_react_client_package(next_config).await?;
182 import_map.insert_exact_alias(
183 rcstr!("react-dom/client"),
184 request_to_import_mapping(
185 app_dir.clone(),
186 format!("next/dist/compiled/react-dom{react_flavor}/{react_client_package}")
187 .into(),
188 ),
189 );
190 import_map.insert_wildcard_alias(
191 rcstr!("react-dom/"),
192 request_to_import_mapping(
193 app_dir.clone(),
194 format!("next/dist/compiled/react-dom{react_flavor}/*").into(),
195 ),
196 );
197 import_map.insert_wildcard_alias(
198 rcstr!("react-server-dom-webpack/"),
199 request_to_import_mapping(app_dir.clone(), rcstr!("react-server-dom-turbopack/*")),
200 );
201 import_map.insert_wildcard_alias(
202 rcstr!("react-server-dom-turbopack/"),
203 request_to_import_mapping(
204 app_dir.clone(),
205 format!("next/dist/compiled/react-server-dom-turbopack{react_flavor}/*").into(),
206 ),
207 );
208 insert_exact_alias_or_js(
209 &mut import_map,
210 rcstr!("next/head"),
211 request_to_import_mapping(
212 project_path.clone(),
213 rcstr!("next/dist/client/components/noop-head"),
214 ),
215 );
216 insert_exact_alias_or_js(
217 &mut import_map,
218 rcstr!("next/dynamic"),
219 request_to_import_mapping(
220 project_path.clone(),
221 rcstr!("next/dist/shared/lib/app-dynamic"),
222 ),
223 );
224 insert_exact_alias_or_js(
225 &mut import_map,
226 rcstr!("next/link"),
227 request_to_import_mapping(
228 project_path.clone(),
229 rcstr!("next/dist/client/app-dir/link"),
230 ),
231 );
232 insert_exact_alias_or_js(
233 &mut import_map,
234 rcstr!("next/form"),
235 request_to_import_mapping(
236 project_path.clone(),
237 rcstr!("next/dist/client/app-dir/form"),
238 ),
239 );
240 }
241 ClientContextType::Fallback => {}
242 ClientContextType::Other => {}
243 }
244
245 insert_exact_alias_map(
247 &mut import_map,
248 project_path.clone(),
249 fxindexmap! {
250 rcstr!("server-only") => rcstr!("next/dist/compiled/server-only/index"),
251 rcstr!("client-only") => rcstr!("next/dist/compiled/client-only/index"),
252 rcstr!("next/dist/compiled/server-only") => rcstr!("next/dist/compiled/server-only/index"),
253 rcstr!("next/dist/compiled/client-only") => rcstr!("next/dist/compiled/client-only/index"),
254 },
255 );
256 insert_next_root_params_mapping(
257 &mut import_map,
258 next_config.enable_root_params(),
259 Either::Right(ty.clone()),
260 None,
261 )
262 .await?;
263
264 match ty {
265 ClientContextType::Pages { .. }
266 | ClientContextType::App { .. }
267 | ClientContextType::Fallback => {
268 for (original, alias) in NEXT_ALIASES.iter() {
269 import_map.insert_exact_alias(
270 format!("node:{original}"),
271 request_to_import_mapping(project_path.clone(), alias.clone()),
272 );
273 }
274 }
275 ClientContextType::Other => {}
276 }
277
278 insert_turbopack_dev_alias(&mut import_map).await?;
279 insert_instrumentation_client_alias(&mut import_map, project_path).await?;
280
281 Ok(import_map.cell())
282}
283
284#[turbo_tasks::function]
287pub async fn get_next_client_fallback_import_map(ty: ClientContextType) -> Result<Vc<ImportMap>> {
288 let mut import_map = ImportMap::empty();
289
290 match ty {
291 ClientContextType::Pages {
292 pages_dir: context_dir,
293 }
294 | ClientContextType::App {
295 app_dir: context_dir,
296 } => {
297 for (original, alias) in NEXT_ALIASES.iter() {
298 import_map.insert_exact_alias(
299 original.clone(),
300 request_to_import_mapping(context_dir.clone(), alias.clone()),
301 );
302 }
303 }
304 ClientContextType::Fallback => {}
305 ClientContextType::Other => {}
306 }
307
308 insert_turbopack_dev_alias(&mut import_map).await?;
309
310 Ok(import_map.cell())
311}
312
313#[turbo_tasks::function]
315pub async fn get_next_server_import_map(
316 project_path: FileSystemPath,
317 ty: ServerContextType,
318 next_config: Vc<NextConfig>,
319 next_mode: Vc<NextMode>,
320 execution_context: Vc<ExecutionContext>,
321 collected_root_params: Option<Vc<CollectedRootParams>>,
322) -> Result<Vc<ImportMap>> {
323 let mut import_map = ImportMap::empty();
324
325 insert_next_shared_aliases(
326 &mut import_map,
327 project_path.clone(),
328 execution_context,
329 next_config,
330 next_mode,
331 false,
332 )
333 .await?;
334
335 insert_alias_option(
336 &mut import_map,
337 &project_path,
338 next_config.resolve_alias_options(),
339 [],
340 )
341 .await?;
342
343 let external = ImportMapping::External(None, ExternalType::CommonJs, ExternalTraced::Traced)
344 .resolved_cell();
345
346 import_map.insert_exact_alias(rcstr!("next/dist/server/require-hook"), external);
347 match ty {
348 ServerContextType::Pages { .. }
349 | ServerContextType::PagesData { .. }
350 | ServerContextType::PagesApi { .. } => {
351 import_map.insert_exact_alias(rcstr!("react"), external);
352 import_map.insert_wildcard_alias(rcstr!("react/"), external);
353 import_map.insert_exact_alias(rcstr!("react-dom"), external);
354 import_map.insert_exact_alias(rcstr!("react-dom/client"), external);
355 import_map.insert_wildcard_alias(rcstr!("react-dom/"), external);
356 import_map.insert_exact_alias(rcstr!("styled-jsx"), external);
357 import_map.insert_exact_alias(
358 rcstr!("styled-jsx/style"),
359 ImportMapping::External(
360 Some(rcstr!("styled-jsx/style.js")),
361 ExternalType::CommonJs,
362 ExternalTraced::Traced,
363 )
364 .resolved_cell(),
365 );
366 import_map.insert_wildcard_alias(rcstr!("styled-jsx/"), external);
367 import_map.insert_wildcard_alias(rcstr!("next/dist/build/utils"), external);
369 }
370 ServerContextType::AppSSR { .. }
371 | ServerContextType::AppRSC { .. }
372 | ServerContextType::AppRoute { .. } => {
373 insert_exact_alias_or_js(
374 &mut import_map,
375 rcstr!("next/head"),
376 request_to_import_mapping(
377 project_path.clone(),
378 rcstr!("next/dist/client/components/noop-head"),
379 ),
380 );
381 insert_exact_alias_or_js(
382 &mut import_map,
383 rcstr!("next/dynamic"),
384 request_to_import_mapping(
385 project_path.clone(),
386 rcstr!("next/dist/shared/lib/app-dynamic"),
387 ),
388 );
389 insert_exact_alias_or_js(
390 &mut import_map,
391 rcstr!("next/link"),
392 request_to_import_mapping(
393 project_path.clone(),
394 rcstr!("next/dist/client/app-dir/link"),
395 ),
396 );
397 insert_exact_alias_or_js(
398 &mut import_map,
399 rcstr!("next/form"),
400 request_to_import_mapping(
401 project_path.clone(),
402 rcstr!("next/dist/client/app-dir/form"),
403 ),
404 );
405 }
406 ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => {}
407 }
408
409 insert_next_server_special_aliases(
410 &mut import_map,
411 project_path.clone(),
412 ty,
413 NextRuntime::NodeJs,
414 next_config,
415 collected_root_params,
416 )
417 .await?;
418
419 Ok(import_map.cell())
420}
421
422#[turbo_tasks::function]
424pub async fn get_next_edge_import_map(
425 project_path: FileSystemPath,
426 ty: ServerContextType,
427 next_config: Vc<NextConfig>,
428 next_mode: Vc<NextMode>,
429 execution_context: Vc<ExecutionContext>,
430 collected_root_params: Option<Vc<CollectedRootParams>>,
431) -> Result<Vc<ImportMap>> {
432 let mut import_map = ImportMap::empty();
433
434 insert_wildcard_alias_map(
438 &mut import_map,
439 project_path.clone(),
440 fxindexmap! {
441 rcstr!("next/dist/build/") => rcstr!("next/dist/esm/build/*"),
442 rcstr!("next/dist/client/") => rcstr!("next/dist/esm/client/*"),
443 rcstr!("next/dist/shared/") => rcstr!("next/dist/esm/shared/*"),
444 rcstr!("next/dist/pages/") => rcstr!("next/dist/esm/pages/*"),
445 rcstr!("next/dist/lib/") => rcstr!("next/dist/esm/lib/*"),
446 rcstr!("next/dist/server/") => rcstr!("next/dist/esm/server/*"),
447 rcstr!("next/dist/api/") => rcstr!("next/dist/esm/api/*"),
448 },
449 );
450
451 insert_exact_alias_map(
453 &mut import_map,
454 project_path.clone(),
455 fxindexmap! {
456 rcstr!("next/app") => rcstr!("next/dist/api/app"),
457 rcstr!("next/document") => rcstr!("next/dist/api/document"),
458 rcstr!("next/dynamic") => rcstr!("next/dist/api/dynamic"),
459 rcstr!("next/form") => rcstr!("next/dist/api/form"),
460 rcstr!("next/head") => rcstr!("next/dist/api/head"),
461 rcstr!("next/headers") => rcstr!("next/dist/api/headers"),
462 rcstr!("next/image") => rcstr!("next/dist/api/image"),
463 rcstr!("next/link") => rcstr!("next/dist/api/link"),
464 rcstr!("next/navigation") => rcstr!("next/dist/api/navigation"),
465 rcstr!("next/router") => rcstr!("next/dist/api/router"),
466 rcstr!("next/script") => rcstr!("next/dist/api/script"),
467 rcstr!("next/server") => rcstr!("next/dist/api/server"),
468 rcstr!("next/og") => rcstr!("next/dist/api/og"),
469
470 rcstr!("next/dist/compiled/@vercel/og/index.node.js") => rcstr!("next/dist/compiled/@vercel/og/index.edge.js"),
472 },
473 );
474
475 insert_next_shared_aliases(
476 &mut import_map,
477 project_path.clone(),
478 execution_context,
479 next_config,
480 next_mode,
481 true,
482 )
483 .await?;
484
485 insert_optimized_module_aliases(&mut import_map, project_path.clone()).await?;
486
487 insert_alias_option(
488 &mut import_map,
489 &project_path,
490 next_config.resolve_alias_options(),
491 [],
492 )
493 .await?;
494
495 match &ty {
496 ServerContextType::Pages { .. }
497 | ServerContextType::PagesData { .. }
498 | ServerContextType::PagesApi { .. }
499 | ServerContextType::Middleware { .. }
500 | ServerContextType::Instrumentation { .. } => {}
501 ServerContextType::AppSSR { .. }
502 | ServerContextType::AppRSC { .. }
503 | ServerContextType::AppRoute { .. } => {
504 insert_exact_alias_or_js(
505 &mut import_map,
506 rcstr!("next/head"),
507 request_to_import_mapping(
508 project_path.clone(),
509 rcstr!("next/dist/client/components/noop-head"),
510 ),
511 );
512 insert_exact_alias_or_js(
513 &mut import_map,
514 rcstr!("next/dynamic"),
515 request_to_import_mapping(
516 project_path.clone(),
517 rcstr!("next/dist/shared/lib/app-dynamic"),
518 ),
519 );
520 insert_exact_alias_or_js(
521 &mut import_map,
522 rcstr!("next/link"),
523 request_to_import_mapping(
524 project_path.clone(),
525 rcstr!("next/dist/client/app-dir/link"),
526 ),
527 );
528 }
529 }
530
531 insert_next_server_special_aliases(
532 &mut import_map,
533 project_path.clone(),
534 ty.clone(),
535 NextRuntime::Edge,
536 next_config,
537 collected_root_params,
538 )
539 .await?;
540
541 match ty {
544 ServerContextType::AppSSR { .. }
545 | ServerContextType::AppRSC { .. }
546 | ServerContextType::AppRoute { .. }
547 | ServerContextType::Middleware { .. }
548 | ServerContextType::Instrumentation { .. }
549 | ServerContextType::Pages { .. }
550 | ServerContextType::PagesData { .. }
551 | ServerContextType::PagesApi { .. } => {
552 insert_unsupported_node_internal_aliases(&mut import_map).await?;
553 }
554 }
555
556 Ok(import_map.cell())
557}
558
559#[turbo_tasks::function]
561pub async fn get_next_edge_and_server_fallback_import_map(
562 project_path: FileSystemPath,
563 runtime: NextRuntime,
564) -> Result<Vc<ImportMap>> {
565 let mut fallback_import_map = ImportMap::empty();
566
567 let external_cjs_if_node = move |context_dir: FileSystemPath, request: RcStr| match runtime {
568 NextRuntime::Edge => request_to_import_mapping(context_dir, request),
569 NextRuntime::NodeJs => external_request_to_cjs_import_mapping(context_dir, request),
570 };
571
572 fallback_import_map.insert_exact_alias(
573 rcstr!("@opentelemetry/api"),
574 ImportMapping::Alternatives(vec![external_cjs_if_node(
577 project_path,
578 rcstr!("next/dist/compiled/@opentelemetry/api"),
579 )])
580 .resolved_cell(),
581 );
582 Ok(fallback_import_map.cell())
583}
584
585async fn insert_unsupported_node_internal_aliases(import_map: &mut ImportMap) -> Result<()> {
589 let unsupported_replacer = ImportMapping::Dynamic(ResolvedVc::upcast(
590 NextEdgeUnsupportedModuleReplacer::new()
591 .to_resolved()
592 .await?,
593 ))
594 .resolved_cell();
595
596 EDGE_UNSUPPORTED_NODE_INTERNALS.iter().for_each(|module| {
597 import_map.insert_alias(AliasPattern::exact(module.clone()), unsupported_replacer);
598 });
599 Ok(())
600}
601
602pub fn get_next_client_resolved_map(
603 _context: FileSystemPath,
604 _root: FileSystemPath,
605 _mode: NextMode,
606) -> Vc<ResolvedMap> {
607 let glob_mappings = vec![];
608 ResolvedMap {
609 by_glob: glob_mappings,
610 }
611 .cell()
612}
613
614static NEXT_ALIASES: LazyLock<[(RcStr, RcStr); 23]> = LazyLock::new(|| {
615 [
616 (rcstr!("assert"), rcstr!("next/dist/compiled/assert")),
617 (rcstr!("buffer"), rcstr!("next/dist/compiled/buffer")),
618 (
619 rcstr!("constants"),
620 rcstr!("next/dist/compiled/constants-browserify"),
621 ),
622 (
623 rcstr!("crypto"),
624 rcstr!("next/dist/compiled/crypto-browserify"),
625 ),
626 (
627 rcstr!("domain"),
628 rcstr!("next/dist/compiled/domain-browser"),
629 ),
630 (rcstr!("http"), rcstr!("next/dist/compiled/stream-http")),
631 (
632 rcstr!("https"),
633 rcstr!("next/dist/compiled/https-browserify"),
634 ),
635 (rcstr!("os"), rcstr!("next/dist/compiled/os-browserify")),
636 (rcstr!("path"), rcstr!("next/dist/compiled/path-browserify")),
637 (rcstr!("punycode"), rcstr!("next/dist/compiled/punycode")),
638 (
639 rcstr!("process"),
640 rcstr!("next/dist/build/polyfills/process"),
641 ),
642 (
643 rcstr!("querystring"),
644 rcstr!("next/dist/compiled/querystring-es3"),
645 ),
646 (
647 rcstr!("stream"),
648 rcstr!("next/dist/compiled/stream-browserify"),
649 ),
650 (
651 rcstr!("string_decoder"),
652 rcstr!("next/dist/compiled/string_decoder"),
653 ),
654 (rcstr!("sys"), rcstr!("next/dist/compiled/util")),
655 (
656 rcstr!("timers"),
657 rcstr!("next/dist/compiled/timers-browserify"),
658 ),
659 (rcstr!("tty"), rcstr!("next/dist/compiled/tty-browserify")),
660 (rcstr!("url"), rcstr!("next/dist/compiled/native-url")),
661 (rcstr!("util"), rcstr!("next/dist/compiled/util")),
662 (rcstr!("vm"), rcstr!("next/dist/compiled/vm-browserify")),
663 (rcstr!("zlib"), rcstr!("next/dist/compiled/browserify-zlib")),
664 (rcstr!("events"), rcstr!("next/dist/compiled/events")),
665 (
666 rcstr!("setImmediate"),
667 rcstr!("next/dist/compiled/setimmediate"),
668 ),
669 ]
670});
671
672async fn insert_next_server_special_aliases(
673 import_map: &mut ImportMap,
674 project_path: FileSystemPath,
675 ty: ServerContextType,
676 runtime: NextRuntime,
677 next_config: Vc<NextConfig>,
678 collected_root_params: Option<Vc<CollectedRootParams>>,
679) -> Result<()> {
680 let external_cjs_if_node = move |context_dir: FileSystemPath, request: RcStr| match runtime {
681 NextRuntime::Edge => request_to_import_mapping(context_dir, request),
682 NextRuntime::NodeJs => external_request_to_cjs_import_mapping(context_dir, request),
683 };
684 let external_esm_if_node = move |context_dir: FileSystemPath, request: RcStr| match runtime {
685 NextRuntime::Edge => request_to_import_mapping(context_dir, request),
686 NextRuntime::NodeJs => external_request_to_esm_import_mapping(context_dir, request),
687 };
688
689 import_map.insert_exact_alias(
690 rcstr!("next/dist/compiled/@vercel/og/index.node.js"),
691 external_esm_if_node(
692 project_path.clone(),
693 rcstr!("next/dist/compiled/@vercel/og/index.node.js"),
694 ),
695 );
696
697 import_map.insert_exact_alias(
698 rcstr!("next/dist/server/ReactDOMServerPages"),
699 ImportMapping::Alternatives(vec![
700 request_to_import_mapping(project_path.clone(), rcstr!("react-dom/server.edge")),
701 request_to_import_mapping(project_path.clone(), rcstr!("react-dom/server.browser")),
702 ])
703 .resolved_cell(),
704 );
705
706 match &ty {
707 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {}
708 ServerContextType::PagesData { .. } => {}
709 ServerContextType::AppSSR { app_dir }
711 | ServerContextType::AppRSC { app_dir, .. }
712 | ServerContextType::AppRoute { app_dir, .. } => {
713 let next_package = get_next_package(app_dir.clone()).owned().await?;
714 import_map.insert_exact_alias(
715 rcstr!("styled-jsx"),
716 request_to_import_mapping(next_package.clone(), rcstr!("styled-jsx")),
717 );
718 import_map.insert_wildcard_alias(
719 rcstr!("styled-jsx/"),
720 request_to_import_mapping(next_package.clone(), rcstr!("styled-jsx/*")),
721 );
722
723 rsc_aliases(
724 import_map,
725 project_path.clone(),
726 ty.clone(),
727 runtime,
728 next_config,
729 )
730 .await?;
731 }
732 ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => {
733 rsc_aliases(
734 import_map,
735 project_path.clone(),
736 ty.clone(),
737 runtime,
738 next_config,
739 )
740 .await?;
741 }
742 }
743
744 match &ty {
750 ServerContextType::Pages { .. } => {
751 insert_exact_alias_map(
752 import_map,
753 project_path.clone(),
754 fxindexmap! {
755 rcstr!("server-only") => rcstr!("next/dist/compiled/server-only/empty"),
756 rcstr!("client-only") => rcstr!("next/dist/compiled/client-only/index"),
757 rcstr!("next/dist/compiled/server-only") => rcstr!("next/dist/compiled/server-only/empty"),
758 rcstr!("next/dist/compiled/client-only") => rcstr!("next/dist/compiled/client-only/index"),
759 },
760 );
761 }
762 ServerContextType::PagesData { .. }
763 | ServerContextType::PagesApi { .. }
764 | ServerContextType::AppRSC { .. }
765 | ServerContextType::AppRoute { .. }
766 | ServerContextType::Middleware { .. }
767 | ServerContextType::Instrumentation { .. } => {
768 insert_exact_alias_map(
769 import_map,
770 project_path.clone(),
771 fxindexmap! {
772 rcstr!("server-only") => rcstr!("next/dist/compiled/server-only/empty"),
773 rcstr!("client-only") => rcstr!("next/dist/compiled/client-only/error"),
774 rcstr!("next/dist/compiled/server-only") => rcstr!("next/dist/compiled/server-only/empty"),
775 rcstr!("next/dist/compiled/client-only") => rcstr!("next/dist/compiled/client-only/error"),
776 },
777 );
778 }
779 ServerContextType::AppSSR { .. } => {
780 insert_exact_alias_map(
781 import_map,
782 project_path.clone(),
783 fxindexmap! {
784 rcstr!("server-only") => rcstr!("next/dist/compiled/server-only/index"),
785 rcstr!("client-only") => rcstr!("next/dist/compiled/client-only/index"),
786 rcstr!("next/dist/compiled/server-only") => rcstr!("next/dist/compiled/server-only/index"),
787 rcstr!("next/dist/compiled/client-only") => rcstr!("next/dist/compiled/client-only/index"),
788 },
789 );
790 }
791 }
792
793 insert_next_root_params_mapping(
794 import_map,
795 next_config.enable_root_params(),
796 Either::Left(ty),
797 collected_root_params,
798 )
799 .await?;
800
801 import_map.insert_exact_alias(
802 rcstr!("@vercel/og"),
803 external_cjs_if_node(
804 project_path.clone(),
805 rcstr!("next/dist/server/og/image-response"),
806 ),
807 );
808
809 import_map.insert_exact_alias(
810 rcstr!("next/dist/compiled/next-devtools"),
811 request_to_import_mapping(
812 project_path.clone(),
813 rcstr!("next/dist/next-devtools/dev-overlay.shim.js"),
814 ),
815 );
816
817 Ok(())
818}
819
820async fn get_react_client_package(next_config: Vc<NextConfig>) -> Result<&'static str> {
821 let react_production_profiling = *next_config.enable_react_production_profiling().await?;
822 let react_client_package = if react_production_profiling {
823 "profiling"
824 } else {
825 "client"
826 };
827
828 Ok(react_client_package)
829}
830
831async fn apply_vendored_react_aliases_server(
834 import_map: &mut ImportMap,
835 project_path: FileSystemPath,
836 ty: ServerContextType,
837 runtime: NextRuntime,
838 next_config: Vc<NextConfig>,
839) -> Result<()> {
840 let ppr = *next_config.enable_ppr().await?;
841 let taint = *next_config.enable_taint().await?;
842 let router_bfcache = *next_config.enable_router_bfcache().await?;
843 let view_transition = *next_config.enable_view_transition().await?;
844 let react_channel = if ppr || taint || view_transition || router_bfcache {
845 "-experimental"
846 } else {
847 ""
848 };
849 let react_condition = if ty.should_use_react_server_condition() {
850 "server"
851 } else {
852 "client"
853 };
854
855 let mut react_alias = FxIndexMap::default();
861 if runtime == NextRuntime::NodeJs && react_condition == "client" {
862 react_alias.extend(fxindexmap! {
863 rcstr!("react") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react"),
865 rcstr!("react/compiler-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-compiler-runtime"),
866 rcstr!("react/jsx-dev-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-dev-runtime"),
867 rcstr!("react/jsx-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime"),
868 rcstr!("react-dom") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-dom"),
870 rcstr!("react-dom/client") => format!("next/dist/compiled/react-dom{react_channel}/client").into(),
871 rcstr!("react-dom/server") => format!("next/dist/compiled/react-dom{react_channel}/server.node").into(),
872 rcstr!("react-dom/server.browser") => format!("next/dist/compiled/react-dom{react_channel}/server.browser").into(),
873 rcstr!("react-dom/server.edge") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
875 rcstr!("react-dom/static") => format!("next/dist/compiled/react-dom{react_channel}/static.node").into(),
876 rcstr!("react-dom/static.browser") => format!("next/dist/compiled/react-dom{react_channel}/static.browser").into(),
877 rcstr!("react-dom/static.edge") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
878 rcstr!("react-server-dom-webpack/client") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client"),
880 rcstr!("react-server-dom-webpack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
881 rcstr!("react-server-dom-webpack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
882 rcstr!("react-server-dom-webpack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.node").into(),
883 rcstr!("react-server-dom-turbopack/client") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client"),
884 rcstr!("react-server-dom-turbopack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
885 rcstr!("react-server-dom-turbopack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
886 rcstr!("react-server-dom-turbopack/static.edge") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),
887 })
888 } else if runtime == NextRuntime::NodeJs && react_condition == "server" {
889 react_alias.extend(fxindexmap! {
890 rcstr!("react") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react"),
892 rcstr!("react/compiler-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-compiler-runtime"),
893 rcstr!("react/jsx-dev-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-jsx-dev-runtime"),
894 rcstr!("react/jsx-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-jsx-runtime"),
895 rcstr!("react-dom") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-dom"),
897 rcstr!("react-dom/client") => format!("next/dist/compiled/react-dom{react_channel}/client").into(),
898 rcstr!("react-dom/server") => format!("next/dist/compiled/react-dom{react_channel}/server.node").into(),
899 rcstr!("react-dom/server.browser") => format!("next/dist/compiled/react-dom{react_channel}/server.browser").into(),
900 rcstr!("react-dom/server.edge") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
902 rcstr!("react-dom/static") => format!("next/dist/compiled/react-dom{react_channel}/static.node").into(),
903 rcstr!("react-dom/static.browser") => format!("next/dist/compiled/react-dom{react_channel}/static.browser").into(),
904 rcstr!("react-dom/static.edge") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
905 rcstr!("react-server-dom-webpack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.node").into(),
907 rcstr!("react-server-dom-webpack/server") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server"),
908 rcstr!("react-server-dom-webpack/server.node") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server"),
909 rcstr!("react-server-dom-webpack/static") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-static"),
910 rcstr!("react-server-dom-turbopack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.node").into(),
911 rcstr!("react-server-dom-turbopack/server") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server"),
912 rcstr!("react-server-dom-turbopack/server.node") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server"),
913 rcstr!("react-server-dom-turbopack/static") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-static"),
914
915 rcstr!("next/dist/compiled/react") => rcstr!("next/dist/compiled/react/index.js"),
918 })
919 } else if runtime == NextRuntime::Edge && react_condition == "client" {
920 react_alias.extend(fxindexmap! {
921 rcstr!("react") => format!("next/dist/compiled/react{react_channel}").into(),
923 rcstr!("react/compiler-runtime") => format!("next/dist/compiled/react{react_channel}/compiler-runtime").into(),
924 rcstr!("react/jsx-dev-runtime") => format!("next/dist/compiled/react{react_channel}/jsx-dev-runtime").into(),
925 rcstr!("react/jsx-runtime") => format!("next/dist/compiled/react{react_channel}/jsx-runtime").into(),
926 rcstr!("react-dom") => format!("next/dist/compiled/react-dom{react_channel}").into(),
928 rcstr!("react-dom/client") => format!("next/dist/compiled/react-dom{react_channel}/client").into(),
929 rcstr!("react-dom/server") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
930 rcstr!("react-dom/server.browser") => format!("next/dist/compiled/react-dom{react_channel}/server.browser").into(),
931 rcstr!("react-dom/server.edge") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
933 rcstr!("react-dom/static") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
934 rcstr!("react-dom/static.browser") => format!("next/dist/compiled/react-dom{react_channel}/static.browser").into(),
935 rcstr!("react-dom/static.edge") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
936 rcstr!("react-server-dom-webpack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge").into(),
938 rcstr!("react-server-dom-webpack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge").into(),
939 rcstr!("react-server-dom-webpack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
940 rcstr!("react-server-dom-webpack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),
941 rcstr!("react-server-dom-turbopack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge").into(),
942 rcstr!("react-server-dom-turbopack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge").into(),
943 rcstr!("react-server-dom-turbopack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
944 rcstr!("react-server-dom-turbopack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),
945 })
946 } else if runtime == NextRuntime::Edge && react_condition == "server" {
947 react_alias.extend(fxindexmap! {
948 rcstr!("react") => format!("next/dist/compiled/react{react_channel}/react.react-server").into(),
950 rcstr!("react/compiler-runtime") => format!("next/dist/compiled/react{react_channel}/compiler-runtime").into(),
951 rcstr!("react/jsx-dev-runtime") => format!("next/dist/compiled/react{react_channel}/jsx-dev-runtime.react-server").into(),
952 rcstr!("react/jsx-runtime") => format!("next/dist/compiled/react{react_channel}/jsx-runtime.react-server").into(),
953 rcstr!("react-dom") => format!("next/dist/compiled/react-dom{react_channel}/react-dom.react-server").into(),
955 rcstr!("react-dom/client") => format!("next/dist/compiled/react-dom{react_channel}/client").into(),
956 rcstr!("react-dom/server") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
957 rcstr!("react-dom/server.browser") => format!("next/dist/compiled/react-dom{react_channel}/server.browser").into(),
958 rcstr!("react-dom/server.edge") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
960 rcstr!("react-dom/static") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
961 rcstr!("react-dom/static.browser") => format!("next/dist/compiled/react-dom{react_channel}/static.browser").into(),
962 rcstr!("react-dom/static.edge") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
963 rcstr!("react-server-dom-webpack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge").into(),
965 rcstr!("react-server-dom-webpack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge").into(),
966 rcstr!("react-server-dom-webpack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
967 rcstr!("react-server-dom-webpack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),
968 rcstr!("react-server-dom-turbopack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge").into(),
969 rcstr!("react-server-dom-turbopack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge").into(),
970 rcstr!("react-server-dom-turbopack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
971 rcstr!("react-server-dom-turbopack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),
972 });
973
974 react_alias.extend(fxindexmap! {
975 rcstr!("next/dist/compiled/react") => react_alias["react"].clone(),
977 rcstr!("next/dist/compiled/react-experimental") => react_alias["react"].clone(),
978 rcstr!("next/dist/compiled/react/compiler-runtime") => react_alias["react/compiler-runtime"].clone(),
979 rcstr!("next/dist/compiled/react-experimental/compiler-runtime") => react_alias["react/compiler-runtime"].clone(),
980 rcstr!("next/dist/compiled/react/jsx-dev-runtime") => react_alias["react/jsx-dev-runtime"].clone(),
981 rcstr!("next/dist/compiled/react-experimental/jsx-dev-runtime") => react_alias["react/jsx-dev-runtime"].clone(),
982 rcstr!("next/dist/compiled/react/jsx-runtime") => react_alias["react/jsx-runtime"].clone(),
983 rcstr!("next/dist/compiled/react-experimental/jsx-runtime") => react_alias["react/jsx-runtime"].clone(),
984 rcstr!("next/dist/compiled/react-dom") => react_alias["react-dom"].clone(),
985 rcstr!("next/dist/compiled/react-dom-experimental") => react_alias["react-dom"].clone(),
986 });
987 }
988
989 let react_client_package = get_react_client_package(next_config).await?;
990 react_alias.extend(fxindexmap! {
991 rcstr!("react-dom/client") => RcStr::from(format!("next/dist/compiled/react-dom{react_channel}/{react_client_package}")),
992 });
993
994 let mut alias = react_alias;
995 if react_condition == "server" {
996 alias.extend(fxindexmap! {
998 rcstr!("next/navigation") => rcstr!("next/dist/api/navigation.react-server"),
999 });
1000 }
1001
1002 insert_exact_alias_map(import_map, project_path, alias);
1003
1004 Ok(())
1005}
1006
1007async fn rsc_aliases(
1008 import_map: &mut ImportMap,
1009 project_path: FileSystemPath,
1010 ty: ServerContextType,
1011 runtime: NextRuntime,
1012 next_config: Vc<NextConfig>,
1013) -> Result<()> {
1014 apply_vendored_react_aliases_server(
1015 import_map,
1016 project_path.clone(),
1017 ty.clone(),
1018 runtime,
1019 next_config,
1020 )
1021 .await?;
1022
1023 let mut alias = FxIndexMap::default();
1024 if ty.should_use_react_server_condition() {
1025 alias.extend(fxindexmap! {
1027 rcstr!("next/navigation") => rcstr!("next/dist/api/navigation.react-server"),
1028 });
1029 }
1030
1031 insert_exact_alias_map(import_map, project_path.clone(), alias);
1032
1033 Ok(())
1034}
1035
1036pub fn mdx_import_source_file() -> RcStr {
1037 format!("{VIRTUAL_PACKAGE_NAME}/mdx-import-source").into()
1038}
1039
1040async fn insert_optimized_module_aliases(
1043 import_map: &mut ImportMap,
1044 project_path: FileSystemPath,
1045) -> Result<()> {
1046 insert_exact_alias_map(
1047 import_map,
1048 project_path,
1049 fxindexmap! {
1050 rcstr!("unfetch") => rcstr!("next/dist/build/polyfills/fetch/index.js"),
1051 rcstr!("isomorphic-unfetch") => rcstr!("next/dist/build/polyfills/fetch/index.js"),
1052 rcstr!("whatwg-fetch") => rcstr!("next/dist/build/polyfills/fetch/whatwg-fetch.js"),
1053 rcstr!("object-assign") => rcstr!("next/dist/build/polyfills/object-assign.js"),
1054 rcstr!("object.assign/auto") => rcstr!("next/dist/build/polyfills/object.assign/auto.js"),
1055 rcstr!("object.assign/implementation") => rcstr!("next/dist/build/polyfills/object.assign/implementation.js"),
1056 rcstr!("object.assign/polyfill") => rcstr!("next/dist/build/polyfills/object.assign/polyfill.js"),
1057 rcstr!("object.assign/shim") => rcstr!("next/dist/build/polyfills/object.assign/shim.js"),
1058 rcstr!("url") => rcstr!("next/dist/compiled/native-url"),
1059 rcstr!("node:url") => rcstr!("next/dist/compiled/native-url"),
1060 },
1061 );
1062 Ok(())
1063}
1064
1065async fn insert_next_shared_aliases(
1067 import_map: &mut ImportMap,
1068 project_path: FileSystemPath,
1069 execution_context: Vc<ExecutionContext>,
1070 next_config: Vc<NextConfig>,
1071 next_mode: Vc<NextMode>,
1072 is_runtime_edge: bool,
1073) -> Result<()> {
1074 let package_root = next_js_fs().root().owned().await?;
1075
1076 insert_alias_to_alternatives(
1077 import_map,
1078 mdx_import_source_file(),
1079 vec![
1080 request_to_import_mapping(project_path.clone(), rcstr!("./mdx-components")),
1081 request_to_import_mapping(project_path.clone(), rcstr!("./src/mdx-components")),
1082 request_to_import_mapping(project_path.clone(), rcstr!("@mdx-js/react")),
1083 request_to_import_mapping(project_path.clone(), rcstr!("@next/mdx/mdx-components.js")),
1084 ],
1085 );
1086
1087 insert_package_alias(
1088 import_map,
1089 &format!("{VIRTUAL_PACKAGE_NAME}/"),
1090 package_root,
1091 );
1092
1093 let next_font_google_replacer_mapping = ImportMapping::Dynamic(ResolvedVc::upcast(
1099 NextFontGoogleReplacer::new(project_path.clone())
1100 .to_resolved()
1101 .await?,
1102 ))
1103 .resolved_cell();
1104
1105 import_map.insert_alias(
1106 AliasPattern::exact(rcstr!("next/font/google/target.css")),
1108 next_font_google_replacer_mapping,
1109 );
1110
1111 import_map.insert_alias(
1112 AliasPattern::exact(rcstr!("@next/font/google/target.css")),
1114 next_font_google_replacer_mapping,
1115 );
1116
1117 let fetch_client = next_config.fetch_client(execution_context.env());
1118 import_map.insert_alias(
1119 AliasPattern::exact(rcstr!(
1120 "@vercel/turbopack-next/internal/font/google/cssmodule.module.css"
1121 )),
1122 ImportMapping::Dynamic(ResolvedVc::upcast(
1123 NextFontGoogleCssModuleReplacer::new(
1124 project_path.clone(),
1125 execution_context,
1126 next_mode,
1127 fetch_client,
1128 )
1129 .to_resolved()
1130 .await?,
1131 ))
1132 .resolved_cell(),
1133 );
1134
1135 import_map.insert_alias(
1136 AliasPattern::exact(rcstr!(GOOGLE_FONTS_INTERNAL_PREFIX)),
1137 ImportMapping::Dynamic(ResolvedVc::upcast(
1138 NextFontGoogleFontFileReplacer::new(project_path.clone(), fetch_client)
1139 .to_resolved()
1140 .await?,
1141 ))
1142 .resolved_cell(),
1143 );
1144
1145 let next_package = get_next_package(project_path.clone()).owned().await?;
1146 import_map.insert_singleton_alias(rcstr!("@swc/helpers"), next_package.clone());
1147 import_map.insert_singleton_alias(rcstr!("styled-jsx"), next_package.clone());
1148 import_map.insert_singleton_alias(rcstr!("next"), project_path.clone());
1149 import_map.insert_singleton_alias(rcstr!("react"), project_path.clone());
1150 import_map.insert_singleton_alias(rcstr!("react-dom"), project_path.clone());
1151 let react_client_package = get_react_client_package(next_config).await?;
1152 import_map.insert_exact_alias(
1153 rcstr!("react-dom/client"),
1154 request_to_import_mapping(
1155 project_path.clone(),
1156 format!("react-dom/{react_client_package}").into(),
1157 ),
1158 );
1159
1160 import_map.insert_alias(
1161 AliasPattern::exact(rcstr!("next")),
1164 ImportMapping::Empty.resolved_cell(),
1165 );
1166
1167 import_map.insert_exact_alias(
1169 rcstr!("setimmediate"),
1170 request_to_import_mapping(
1171 project_path.clone(),
1172 rcstr!("next/dist/compiled/setimmediate"),
1173 ),
1174 );
1175
1176 import_map.insert_exact_alias(
1177 rcstr!("private-next-rsc-server-reference"),
1178 request_to_import_mapping(
1179 project_path.clone(),
1180 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/server-reference"),
1181 ),
1182 );
1183 import_map.insert_exact_alias(
1184 rcstr!("private-next-rsc-action-client-wrapper"),
1185 request_to_import_mapping(
1186 project_path.clone(),
1187 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/action-client-wrapper"),
1188 ),
1189 );
1190 import_map.insert_exact_alias(
1191 rcstr!("private-next-rsc-action-validate"),
1192 request_to_import_mapping(
1193 project_path.clone(),
1194 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/action-validate"),
1195 ),
1196 );
1197 import_map.insert_exact_alias(
1198 rcstr!("private-next-rsc-action-encryption"),
1199 request_to_import_mapping(
1200 project_path.clone(),
1201 rcstr!("next/dist/server/app-render/encryption"),
1202 ),
1203 );
1204 import_map.insert_exact_alias(
1205 rcstr!("private-next-rsc-cache-wrapper"),
1206 request_to_import_mapping(
1207 project_path.clone(),
1208 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/cache-wrapper"),
1209 ),
1210 );
1211 import_map.insert_exact_alias(
1212 rcstr!("private-next-rsc-track-dynamic-import"),
1213 request_to_import_mapping(
1214 project_path.clone(),
1215 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/track-dynamic-import"),
1216 ),
1217 );
1218
1219 insert_turbopack_dev_alias(import_map).await?;
1220 insert_package_alias(
1221 import_map,
1222 "@vercel/turbopack-node/",
1223 turbopack_node::embed_js::embed_fs().root().owned().await?,
1224 );
1225
1226 let image_config = next_config.image_config().await?;
1227 if let Some(loader_file) = image_config.loader_file.as_deref().map(RcStr::from) {
1228 import_map.insert_exact_alias(
1229 rcstr!("next/dist/shared/lib/image-loader"),
1230 request_to_import_mapping(project_path.clone(), loader_file.clone()),
1231 );
1232
1233 if is_runtime_edge {
1234 import_map.insert_exact_alias(
1235 rcstr!("next/dist/esm/shared/lib/image-loader"),
1236 request_to_import_mapping(project_path.clone(), loader_file),
1237 );
1238 }
1239 }
1240
1241 Ok(())
1242}
1243
1244#[turbo_tasks::function]
1245pub async fn get_next_package(context_directory: FileSystemPath) -> Result<Vc<FileSystemPath>> {
1246 let result = resolve(
1247 context_directory.clone(),
1248 ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined),
1249 Request::parse(Pattern::Constant(rcstr!("next/package.json"))),
1250 node_cjs_resolve_options(context_directory.root().owned().await?),
1251 );
1252 let source = result
1253 .first_source()
1254 .await?
1255 .context("Next.js package not found")?;
1256 Ok(source.ident().path().await?.parent().cell())
1257}
1258
1259pub async fn insert_alias_option<const N: usize>(
1260 import_map: &mut ImportMap,
1261 project_path: &FileSystemPath,
1262 alias_options: Vc<ResolveAliasMap>,
1263 conditions: [&'static str; N],
1264) -> Result<()> {
1265 let conditions = BTreeMap::from(conditions.map(|c| (c.into(), ConditionValue::Set)));
1266 for (alias, value) in &alias_options.await? {
1267 if let Some(mapping) = export_value_to_import_mapping(value, &conditions, project_path) {
1268 import_map.insert_alias(alias, mapping);
1269 }
1270 }
1271 Ok(())
1272}
1273
1274fn export_value_to_import_mapping(
1275 value: &SubpathValue,
1276 conditions: &BTreeMap<RcStr, ConditionValue>,
1277 project_path: &FileSystemPath,
1278) -> Option<ResolvedVc<ImportMapping>> {
1279 let mut result = Vec::new();
1280 value.add_results(
1281 conditions,
1282 &ConditionValue::Unset,
1283 &mut FxHashMap::default(),
1284 &mut result,
1285 );
1286 if result.is_empty() {
1287 None
1288 } else {
1289 Some(if result.len() == 1 {
1290 ImportMapping::PrimaryAlternative(result[0].0.into(), Some(project_path.clone()))
1291 .resolved_cell()
1292 } else {
1293 ImportMapping::Alternatives(
1294 result
1295 .iter()
1296 .map(|(m, _)| {
1297 ImportMapping::PrimaryAlternative((*m).into(), Some(project_path.clone()))
1298 .resolved_cell()
1299 })
1300 .collect(),
1301 )
1302 .resolved_cell()
1303 })
1304 }
1305}
1306
1307fn insert_exact_alias_map(
1308 import_map: &mut ImportMap,
1309 project_path: FileSystemPath,
1310 map: FxIndexMap<RcStr, RcStr>,
1311) {
1312 for (pattern, request) in map {
1313 import_map.insert_exact_alias(
1314 pattern,
1315 request_to_import_mapping(project_path.clone(), request),
1316 );
1317 }
1318}
1319
1320fn insert_wildcard_alias_map(
1321 import_map: &mut ImportMap,
1322 project_path: FileSystemPath,
1323 map: FxIndexMap<RcStr, RcStr>,
1324) {
1325 for (pattern, request) in map {
1326 import_map.insert_wildcard_alias(
1327 pattern,
1328 request_to_import_mapping(project_path.clone(), request),
1329 );
1330 }
1331}
1332
1333fn insert_alias_to_alternatives<'a>(
1335 import_map: &mut ImportMap,
1336 alias: impl Into<RcStr> + 'a,
1337 alternatives: Vec<ResolvedVc<ImportMapping>>,
1338) {
1339 import_map.insert_exact_alias(
1340 alias.into(),
1341 ImportMapping::Alternatives(alternatives).resolved_cell(),
1342 );
1343}
1344
1345fn insert_package_alias(import_map: &mut ImportMap, prefix: &str, package_root: FileSystemPath) {
1347 import_map.insert_wildcard_alias(
1348 prefix,
1349 ImportMapping::PrimaryAlternative(rcstr!("./*"), Some(package_root)).resolved_cell(),
1350 );
1351}
1352
1353async fn insert_turbopack_dev_alias(import_map: &mut ImportMap) -> Result<()> {
1355 insert_package_alias(
1356 import_map,
1357 "@vercel/turbopack-ecmascript-runtime/",
1358 turbopack_ecmascript_runtime::embed_fs()
1359 .root()
1360 .owned()
1361 .await?,
1362 );
1363 Ok(())
1364}
1365
1366async fn insert_instrumentation_client_alias(
1368 import_map: &mut ImportMap,
1369 project_path: FileSystemPath,
1370) -> Result<()> {
1371 insert_alias_to_alternatives(
1372 import_map,
1373 rcstr!("private-next-instrumentation-client"),
1374 vec![
1375 request_to_import_mapping(project_path.clone(), rcstr!("./src/instrumentation-client")),
1376 request_to_import_mapping(
1377 project_path.clone(),
1378 rcstr!("./src/instrumentation-client.ts"),
1379 ),
1380 request_to_import_mapping(project_path.clone(), rcstr!("./instrumentation-client")),
1381 request_to_import_mapping(project_path.clone(), rcstr!("./instrumentation-client.ts")),
1382 ImportMapping::Ignore.resolved_cell(),
1383 ],
1384 );
1385
1386 Ok(())
1387}
1388
1389fn insert_exact_alias_or_js(
1391 import_map: &mut ImportMap,
1392 pattern: RcStr,
1393 mapping: ResolvedVc<ImportMapping>,
1394) {
1395 import_map.insert_exact_alias(format!("{pattern}.js"), mapping);
1396 import_map.insert_exact_alias(pattern, mapping);
1397}
1398
1399fn request_to_import_mapping(
1402 context_path: FileSystemPath,
1403 request: RcStr,
1404) -> ResolvedVc<ImportMapping> {
1405 ImportMapping::PrimaryAlternative(request, Some(context_path)).resolved_cell()
1406}
1407
1408fn external_request_to_cjs_import_mapping(
1411 context_dir: FileSystemPath,
1412 request: RcStr,
1413) -> ResolvedVc<ImportMapping> {
1414 ImportMapping::PrimaryAlternativeExternal {
1415 name: Some(request),
1416 ty: ExternalType::CommonJs,
1417 traced: ExternalTraced::Traced,
1418 lookup_dir: context_dir,
1419 }
1420 .resolved_cell()
1421}
1422
1423fn external_request_to_esm_import_mapping(
1426 context_dir: FileSystemPath,
1427 request: RcStr,
1428) -> ResolvedVc<ImportMapping> {
1429 ImportMapping::PrimaryAlternativeExternal {
1430 name: Some(request),
1431 ty: ExternalType::EcmaScriptModule,
1432 traced: ExternalTraced::Traced,
1433 lookup_dir: context_dir,
1434 }
1435 .resolved_cell()
1436}