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