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