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