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