1use std::{borrow::Cow, collections::BTreeMap, sync::LazyLock};
2
3use anyhow::{Context, Result};
4use async_trait::async_trait;
5use either::Either;
6use next_taskless::{EDGE_NODE_EXTERNALS, NODE_EXTERNALS};
7use rustc_hash::FxHashMap;
8use turbo_rcstr::{RcStr, rcstr};
9use turbo_tasks::{FxIndexMap, ResolvedVc, Vc, fxindexmap};
10use turbo_tasks_fs::{
11 FileContent, FileSystem, FileSystemPath,
12 glob::{Glob, GlobOptions},
13 to_sys_path,
14};
15use turbopack_core::{
16 asset::AssetContent,
17 issue::{Issue, IssueExt, IssueSeverity, IssueStage, StyledString},
18 reference_type::{CommonJsReferenceSubType, ReferenceType},
19 resolve::{
20 AliasKey, AliasPattern, AliasTemplate, ExternalTraced, ExternalType,
21 ReplacedSubpathValueResultType, ResolveAliasMap, ResolveResult, SubpathValue,
22 node::node_cjs_resolve_options,
23 options::{ConditionValue, ImportMap, ImportMapping, ResolvedMap},
24 parse::Request,
25 pattern::Pattern,
26 resolve,
27 },
28 source::Source,
29 virtual_source::VirtualSource,
30};
31use turbopack_node::execution_context::ExecutionContext;
32
33use crate::{
34 app_structure::CollectedRootParams,
35 browser_variant_modules::BROWSER_VARIANT_MODULES,
36 embed_js::{VIRTUAL_PACKAGE_NAME, next_js_fs},
37 mode::NextMode,
38 next_client::context::ClientContextType,
39 next_config::{NextConfig, OptionFileSystemPath},
40 next_edge::unsupported::NextEdgeUnsupportedModuleReplacer,
41 next_font::{
42 google::{
43 GOOGLE_FONTS_INTERNAL_PREFIX, NextFontGoogleCssModuleReplacer,
44 NextFontGoogleFontFileReplacer, NextFontGoogleReplacer,
45 },
46 local::{
47 NextFontLocalCssModuleReplacer, NextFontLocalFontFileReplacer, NextFontLocalReplacer,
48 },
49 },
50 next_root_params::insert_next_root_params_mapping,
51 next_server::context::ServerContextType,
52 next_shared::ContextType,
53 util::NextRuntime,
54};
55
56#[turbo_tasks::function]
59pub async fn get_next_client_import_map(
60 project_path: FileSystemPath,
61 ty: ClientContextType,
62 next_config: Vc<NextConfig>,
63 next_mode: Vc<NextMode>,
64 execution_context: Vc<ExecutionContext>,
65) -> Result<Vc<ImportMap>> {
66 let mut import_map = ImportMap::empty();
67
68 import_map.insert_exact_alias(
69 rcstr!("next/image"),
70 request_to_import_mapping(project_path.clone(), rcstr!("next/dist/api/image")),
71 );
72
73 insert_next_shared_aliases(
74 &mut import_map,
75 project_path.clone(),
76 execution_context,
77 next_config,
78 next_mode,
79 ContextType::Client(ty.clone()),
80 false,
81 )
82 .await?;
83
84 insert_optimized_module_aliases(&mut import_map, project_path.clone()).await?;
85
86 insert_alias_option(
87 &mut import_map,
88 &project_path,
89 next_config.resolve_alias_options(),
90 ["browser"],
91 )
92 .await?;
93
94 match &ty {
95 ClientContextType::Pages { .. } => {
96 insert_exact_alias_or_js(
100 &mut import_map,
101 rcstr!("next/error"),
102 request_to_import_mapping(project_path.clone(), rcstr!("next/dist/api/error")),
103 );
104 }
105 ClientContextType::App { app_dir } => {
106 let react_channel = if *next_config.use_react_experimental().await? {
107 "-experimental"
108 } else {
109 ""
110 };
111
112 import_map.insert_exact_alias(
113 rcstr!("react"),
114 request_to_import_mapping(
115 app_dir.clone(),
116 format!("next/dist/compiled/react{react_channel}").into(),
117 ),
118 );
119 import_map.insert_wildcard_alias(
120 rcstr!("react/"),
121 request_to_import_mapping(
122 app_dir.clone(),
123 format!("next/dist/compiled/react{react_channel}/*").into(),
124 ),
125 );
126 import_map.insert_exact_alias(
127 rcstr!("react-dom"),
128 request_to_import_mapping(
129 app_dir.clone(),
130 format!("next/dist/compiled/react-dom{react_channel}").into(),
131 ),
132 );
133 import_map.insert_exact_alias(
134 rcstr!("react-dom/static"),
135 request_to_import_mapping(
136 app_dir.clone(),
137 rcstr!("next/dist/compiled/react-dom-experimental/static"),
138 ),
139 );
140 import_map.insert_exact_alias(
141 rcstr!("react-dom/static.edge"),
142 request_to_import_mapping(
143 app_dir.clone(),
144 rcstr!("next/dist/compiled/react-dom-experimental/static.edge"),
145 ),
146 );
147 import_map.insert_exact_alias(
148 rcstr!("react-dom/static.browser"),
149 request_to_import_mapping(
150 app_dir.clone(),
151 rcstr!("next/dist/compiled/react-dom-experimental/static.browser"),
152 ),
153 );
154 let react_client_package = get_react_client_package(next_config).await?;
155 import_map.insert_exact_alias(
156 rcstr!("react-dom/client"),
157 request_to_import_mapping(
158 app_dir.clone(),
159 format!("next/dist/compiled/react-dom{react_channel}/{react_client_package}")
160 .into(),
161 ),
162 );
163 import_map.insert_wildcard_alias(
164 rcstr!("react-dom/"),
165 request_to_import_mapping(
166 app_dir.clone(),
167 format!("next/dist/compiled/react-dom{react_channel}/*").into(),
168 ),
169 );
170 import_map.insert_wildcard_alias(
171 rcstr!("react-server-dom-webpack/"),
172 request_to_import_mapping(app_dir.clone(), rcstr!("react-server-dom-turbopack/*")),
173 );
174 import_map.insert_wildcard_alias(
175 rcstr!("react-server-dom-turbopack/"),
176 request_to_import_mapping(
177 app_dir.clone(),
178 format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/*")
179 .into(),
180 ),
181 );
182 insert_exact_alias_or_js(
183 &mut import_map,
184 rcstr!("next/head"),
185 request_to_import_mapping(
186 project_path.clone(),
187 rcstr!("next/dist/client/components/noop-head"),
188 ),
189 );
190 insert_exact_alias_or_js(
191 &mut import_map,
192 rcstr!("next/dynamic"),
193 request_to_import_mapping(
194 project_path.clone(),
195 rcstr!("next/dist/shared/lib/app-dynamic"),
196 ),
197 );
198 insert_exact_alias_or_js(
199 &mut import_map,
200 rcstr!("next/link"),
201 request_to_import_mapping(
202 project_path.clone(),
203 rcstr!("next/dist/client/app-dir/link"),
204 ),
205 );
206 insert_exact_alias_or_js(
207 &mut import_map,
208 rcstr!("next/form"),
209 request_to_import_mapping(
210 project_path.clone(),
211 rcstr!("next/dist/client/app-dir/form"),
212 ),
213 );
214 }
215 ClientContextType::Fallback => {}
216 ClientContextType::Other => {}
217 }
218
219 insert_exact_alias_map(
221 &mut import_map,
222 project_path.clone(),
223 fxindexmap! {rcstr!("server-only") => rcstr!("next/dist/compiled/server-only/index"),
224 rcstr!("client-only") => rcstr!("next/dist/compiled/client-only/index"),
225 rcstr!("next/dist/compiled/server-only") => rcstr!("next/dist/compiled/server-only/index"),
226 rcstr!("next/dist/compiled/client-only") => rcstr!("next/dist/compiled/client-only/index"),},
227 );
228 insert_next_root_params_mapping(&mut import_map, Either::Right(ty.clone()), None).await?;
229
230 match ty {
231 ClientContextType::Pages { .. }
232 | ClientContextType::App { .. }
233 | ClientContextType::Fallback => {
234 for (original, alias) in NEXT_ALIASES.iter() {
235 import_map.insert_exact_alias(
236 format!("node:{original}"),
237 request_to_import_mapping(project_path.clone(), alias.clone()),
238 );
239 }
240 }
241 ClientContextType::Other => {}
242 }
243
244 insert_instrumentation_client_alias(&mut import_map, project_path, next_config).await?;
245
246 insert_server_only_error_alias(&mut import_map);
247
248 Ok(import_map.cell())
249}
250
251#[turbo_tasks::function]
254pub async fn get_next_client_fallback_import_map(ty: ClientContextType) -> Result<Vc<ImportMap>> {
255 let mut import_map = ImportMap::empty();
256
257 match ty {
258 ClientContextType::Pages {
259 pages_dir: context_dir,
260 }
261 | ClientContextType::App {
262 app_dir: context_dir,
263 } => {
264 for (original, alias) in NEXT_ALIASES.iter() {
265 import_map.insert_exact_alias(
266 original.clone(),
267 request_to_import_mapping(context_dir.clone(), alias.clone()),
268 );
269 }
270 }
271 ClientContextType::Fallback => {}
272 ClientContextType::Other => {}
273 }
274
275 Ok(import_map.cell())
276}
277
278#[turbo_tasks::function]
280pub async fn get_next_server_import_map(
281 project_path: FileSystemPath,
282 ty: ServerContextType,
283 next_config: Vc<NextConfig>,
284 next_mode: Vc<NextMode>,
285 execution_context: Vc<ExecutionContext>,
286 collected_root_params: Option<Vc<CollectedRootParams>>,
287) -> Result<Vc<ImportMap>> {
288 let mut import_map = ImportMap::empty();
289
290 import_map.insert_exact_alias(
291 rcstr!("next/image"),
292 request_to_import_mapping(project_path.clone(), rcstr!("next/dist/api/image")),
293 );
294
295 insert_next_shared_aliases(
296 &mut import_map,
297 project_path.clone(),
298 execution_context,
299 next_config,
300 next_mode,
301 ContextType::Server(ty.clone()),
302 false,
303 )
304 .await?;
305
306 insert_alias_option(
307 &mut import_map,
308 &project_path,
309 next_config.resolve_alias_options(),
310 [],
311 )
312 .await?;
313
314 let external = ImportMapping::External(None, ExternalType::CommonJs, ExternalTraced::Traced)
315 .resolved_cell();
316
317 import_map.insert_exact_alias(rcstr!("next/dist/server/require-hook"), external);
318 match ty {
319 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {
320 import_map.insert_exact_alias(rcstr!("react"), external);
321 import_map.insert_wildcard_alias(rcstr!("react/"), external);
322 import_map.insert_exact_alias(rcstr!("react-dom"), external);
323 import_map.insert_exact_alias(rcstr!("react-dom/client"), external);
324 import_map.insert_wildcard_alias(rcstr!("react-dom/"), external);
325 import_map.insert_exact_alias(rcstr!("styled-jsx"), external);
326 import_map.insert_exact_alias(
327 rcstr!("styled-jsx/style"),
328 ImportMapping::External(
329 Some(rcstr!("styled-jsx/style.js")),
330 ExternalType::CommonJs,
331 ExternalTraced::Traced,
332 )
333 .resolved_cell(),
334 );
335 import_map.insert_wildcard_alias(rcstr!("styled-jsx/"), external);
336 import_map.insert_wildcard_alias(rcstr!("next/dist/build/utils"), external);
338 }
339 ServerContextType::AppSSR { .. }
340 | ServerContextType::AppRSC { .. }
341 | ServerContextType::AppRoute { .. } => {
342 insert_exact_alias_or_js(
343 &mut import_map,
344 rcstr!("next/head"),
345 request_to_import_mapping(
346 project_path.clone(),
347 rcstr!("next/dist/client/components/noop-head"),
348 ),
349 );
350 insert_exact_alias_or_js(
351 &mut import_map,
352 rcstr!("next/dynamic"),
353 request_to_import_mapping(
354 project_path.clone(),
355 rcstr!("next/dist/shared/lib/app-dynamic"),
356 ),
357 );
358 insert_exact_alias_or_js(
359 &mut import_map,
360 rcstr!("next/link"),
361 request_to_import_mapping(
362 project_path.clone(),
363 rcstr!("next/dist/client/app-dir/link"),
364 ),
365 );
366 insert_exact_alias_or_js(
367 &mut import_map,
368 rcstr!("next/form"),
369 request_to_import_mapping(
370 project_path.clone(),
371 rcstr!("next/dist/client/app-dir/form"),
372 ),
373 );
374 }
375 ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => {}
376 }
377
378 insert_next_server_special_aliases(
379 &mut import_map,
380 project_path.clone(),
381 ty,
382 NextRuntime::NodeJs,
383 next_config,
384 collected_root_params,
385 )
386 .await?;
387
388 Ok(import_map.cell())
389}
390
391#[turbo_tasks::function]
393pub async fn get_next_edge_import_map(
394 project_path: FileSystemPath,
395 ty: ServerContextType,
396 next_config: Vc<NextConfig>,
397 next_mode: Vc<NextMode>,
398 execution_context: Vc<ExecutionContext>,
399 collected_root_params: Option<Vc<CollectedRootParams>>,
400) -> Result<Vc<ImportMap>> {
401 let mut import_map = ImportMap::empty();
402
403 insert_wildcard_alias_map(
407 &mut import_map,
408 project_path.clone(),
409 fxindexmap! {rcstr!("next/dist/build/") => rcstr!("next/dist/esm/build/*"),
410 rcstr!("next/dist/client/") => rcstr!("next/dist/esm/client/*"),
411 rcstr!("next/dist/shared/") => rcstr!("next/dist/esm/shared/*"),
412 rcstr!("next/dist/pages/") => rcstr!("next/dist/esm/pages/*"),
413 rcstr!("next/dist/lib/") => rcstr!("next/dist/esm/lib/*"),
414 rcstr!("next/dist/server/") => rcstr!("next/dist/esm/server/*"),
415 rcstr!("next/dist/api/") => rcstr!("next/dist/esm/api/*"),},
416 );
417
418 insert_exact_alias_map(
420 &mut import_map,
421 project_path.clone(),
422 fxindexmap! {rcstr!("next/app") => rcstr!("next/dist/api/app"),
423 rcstr!("next/document") => rcstr!("next/dist/api/document"),
424 rcstr!("next/dynamic") => rcstr!("next/dist/api/dynamic"),
425 rcstr!("next/error") => rcstr!("next/dist/api/error"),
426 rcstr!("next/form") => rcstr!("next/dist/api/form"),
427 rcstr!("next/head") => rcstr!("next/dist/api/head"),
428 rcstr!("next/headers") => rcstr!("next/dist/api/headers"),
429 rcstr!("next/image") => rcstr!("next/dist/api/image"),
430 rcstr!("next/link") => rcstr!("next/dist/api/link"),
431 rcstr!("next/navigation") => rcstr!("next/dist/api/navigation"),
432 rcstr!("next/router") => rcstr!("next/dist/api/router"),
433 rcstr!("next/script") => rcstr!("next/dist/api/script"),
434 rcstr!("next/server") => rcstr!("next/dist/api/server"),
435 rcstr!("next/og") => rcstr!("next/dist/api/og"),
436
437 rcstr!("next/dist/compiled/@vercel/og/index.node.js") => rcstr!("next/dist/compiled/@vercel/og/index.edge.js"),},
439 );
440
441 insert_next_shared_aliases(
442 &mut import_map,
443 project_path.clone(),
444 execution_context,
445 next_config,
446 next_mode,
447 ContextType::Server(ty.clone()),
448 true,
449 )
450 .await?;
451
452 insert_optimized_module_aliases(&mut import_map, project_path.clone()).await?;
453
454 insert_alias_option(
455 &mut import_map,
456 &project_path,
457 next_config.resolve_alias_options(),
458 [],
459 )
460 .await?;
461
462 match &ty {
463 ServerContextType::Pages { .. }
464 | ServerContextType::PagesApi { .. }
465 | ServerContextType::Middleware { .. }
466 | ServerContextType::Instrumentation { .. } => {}
467 ServerContextType::AppSSR { .. }
468 | ServerContextType::AppRSC { .. }
469 | ServerContextType::AppRoute { .. } => {
470 insert_exact_alias_or_js(
471 &mut import_map,
472 rcstr!("next/head"),
473 request_to_import_mapping(
474 project_path.clone(),
475 rcstr!("next/dist/client/components/noop-head"),
476 ),
477 );
478 insert_exact_alias_or_js(
479 &mut import_map,
480 rcstr!("next/dynamic"),
481 request_to_import_mapping(
482 project_path.clone(),
483 rcstr!("next/dist/shared/lib/app-dynamic"),
484 ),
485 );
486 insert_exact_alias_or_js(
487 &mut import_map,
488 rcstr!("next/link"),
489 request_to_import_mapping(
490 project_path.clone(),
491 rcstr!("next/dist/client/app-dir/link"),
492 ),
493 );
494 }
495 }
496
497 insert_next_server_special_aliases(
498 &mut import_map,
499 project_path.clone(),
500 ty.clone(),
501 NextRuntime::Edge,
502 next_config,
503 collected_root_params,
504 )
505 .await?;
506
507 match ty {
510 ServerContextType::AppSSR { .. }
511 | ServerContextType::AppRSC { .. }
512 | ServerContextType::AppRoute { .. }
513 | ServerContextType::Middleware { .. }
514 | ServerContextType::Instrumentation { .. }
515 | ServerContextType::Pages { .. }
516 | ServerContextType::PagesApi { .. } => {
517 insert_unsupported_node_internal_aliases(&mut import_map).await?;
518 }
519 }
520
521 if matches!(
522 ty,
523 ServerContextType::AppRSC { .. }
524 | ServerContextType::AppRoute { .. }
525 | ServerContextType::Middleware { .. }
526 | ServerContextType::Instrumentation { .. }
527 ) {
528 insert_client_only_error_alias(&mut import_map);
529 }
530
531 Ok(import_map.cell())
532}
533
534#[turbo_tasks::function]
536pub async fn get_next_edge_and_server_fallback_import_map(
537 project_path: FileSystemPath,
538 runtime: NextRuntime,
539) -> Result<Vc<ImportMap>> {
540 let mut fallback_import_map = ImportMap::empty();
541
542 let external_cjs_if_node = move |context_dir: FileSystemPath, request: RcStr| match runtime {
543 NextRuntime::Edge => request_to_import_mapping(context_dir, request),
544 NextRuntime::NodeJs => external_request_to_cjs_import_mapping(context_dir, request),
545 };
546
547 fallback_import_map.insert_exact_alias(
548 rcstr!("@opentelemetry/api"),
549 ImportMapping::Alternatives(vec![external_cjs_if_node(
552 project_path,
553 rcstr!("next/dist/compiled/@opentelemetry/api"),
554 )])
555 .resolved_cell(),
556 );
557 Ok(fallback_import_map.cell())
558}
559
560async fn insert_unsupported_node_internal_aliases(import_map: &mut ImportMap) -> Result<()> {
564 let unsupported_replacer = ImportMapping::Dynamic(ResolvedVc::upcast(
565 NextEdgeUnsupportedModuleReplacer::new()
566 .to_resolved()
567 .await?,
568 ))
569 .resolved_cell();
570
571 for module in NODE_EXTERNALS {
572 if EDGE_NODE_EXTERNALS.binary_search(&module).is_ok() {
573 continue;
574 }
575 import_map.insert_alias(AliasPattern::exact(module), unsupported_replacer);
576 }
577
578 Ok(())
579}
580
581pub async fn get_next_client_resolved_map(
582 context_path: FileSystemPath,
583 _mode: NextMode,
584 expose_testing_api: bool,
585 concurrent_router_queue: bool,
586) -> Result<Vc<ResolvedMap>> {
587 let mut glob_mappings = Vec::with_capacity(BROWSER_VARIANT_MODULES.len() + 1);
597 for module in BROWSER_VARIANT_MODULES {
598 glob_mappings.push((
599 None,
600 Glob::new(
601 format!("**/next/dist/{module}.js").into(),
602 GlobOptions::default(),
603 )
604 .to_resolved()
605 .await?,
606 request_to_import_mapping(
607 context_path.clone(),
608 format!("next/dist/{module}.browser").into(),
609 ),
610 ));
611 }
612
613 if !expose_testing_api {
619 glob_mappings.push((
620 None,
621 Glob::new(
622 rcstr!("**/next/dist/client/components/segment-cache/navigation-testing-lock.js"),
623 GlobOptions::default(),
624 )
625 .to_resolved()
626 .await?,
627 request_to_import_mapping(
628 context_path.clone(),
629 rcstr!(
630 "next/dist/client/components/segment-cache/navigation-testing-lock.disabled"
631 ),
632 ),
633 ));
634 }
635
636 if concurrent_router_queue {
642 glob_mappings.push((
643 None,
644 Glob::new(
645 rcstr!("**/next/dist/client/components/navigator.js"),
646 GlobOptions::default(),
647 )
648 .to_resolved()
649 .await?,
650 request_to_import_mapping(
651 context_path.clone(),
652 rcstr!("next/dist/client/components/concurrent-router-queue"),
653 ),
654 ));
655 glob_mappings.push((
656 None,
657 Glob::new(
658 rcstr!("**/next/dist/client/app-call-server.js"),
659 GlobOptions::default(),
660 )
661 .to_resolved()
662 .await?,
663 request_to_import_mapping(
664 context_path.clone(),
665 rcstr!("next/dist/client/concurrent-call-server"),
666 ),
667 ));
668 }
669
670 Ok(ResolvedMap {
671 by_glob: glob_mappings,
672 }
673 .cell())
674}
675
676static NEXT_ALIASES: LazyLock<[(RcStr, RcStr); 23]> = LazyLock::new(|| {
677 [
678 (rcstr!("assert"), rcstr!("next/dist/compiled/assert")),
679 (rcstr!("buffer"), rcstr!("next/dist/compiled/buffer")),
680 (
681 rcstr!("constants"),
682 rcstr!("next/dist/compiled/constants-browserify"),
683 ),
684 (
685 rcstr!("crypto"),
686 rcstr!("next/dist/compiled/crypto-browserify"),
687 ),
688 (
689 rcstr!("domain"),
690 rcstr!("next/dist/compiled/domain-browser"),
691 ),
692 (rcstr!("http"), rcstr!("next/dist/compiled/stream-http")),
693 (
694 rcstr!("https"),
695 rcstr!("next/dist/compiled/https-browserify"),
696 ),
697 (rcstr!("os"), rcstr!("next/dist/compiled/os-browserify")),
698 (rcstr!("path"), rcstr!("next/dist/compiled/path-browserify")),
699 (rcstr!("punycode"), rcstr!("next/dist/compiled/punycode")),
700 (
701 rcstr!("process"),
702 rcstr!("next/dist/build/polyfills/process"),
703 ),
704 (
705 rcstr!("querystring"),
706 rcstr!("next/dist/compiled/querystring-es3"),
707 ),
708 (
709 rcstr!("stream"),
710 rcstr!("next/dist/compiled/stream-browserify"),
711 ),
712 (
713 rcstr!("string_decoder"),
714 rcstr!("next/dist/compiled/string_decoder"),
715 ),
716 (rcstr!("sys"), rcstr!("next/dist/compiled/util")),
717 (
718 rcstr!("timers"),
719 rcstr!("next/dist/compiled/timers-browserify"),
720 ),
721 (rcstr!("tty"), rcstr!("next/dist/compiled/tty-browserify")),
722 (rcstr!("url"), rcstr!("next/dist/compiled/native-url")),
723 (rcstr!("util"), rcstr!("next/dist/compiled/util")),
724 (rcstr!("vm"), rcstr!("next/dist/compiled/vm-browserify")),
725 (rcstr!("zlib"), rcstr!("next/dist/compiled/browserify-zlib")),
726 (rcstr!("events"), rcstr!("next/dist/compiled/events")),
727 (
728 rcstr!("setImmediate"),
729 rcstr!("next/dist/compiled/setimmediate"),
730 ),
731 ]
732});
733
734async fn insert_next_server_special_aliases(
735 import_map: &mut ImportMap,
736 project_path: FileSystemPath,
737 ty: ServerContextType,
738 runtime: NextRuntime,
739 next_config: Vc<NextConfig>,
740 collected_root_params: Option<Vc<CollectedRootParams>>,
741) -> Result<()> {
742 let external_cjs_if_node = move |context_dir: FileSystemPath, request: RcStr| match runtime {
743 NextRuntime::Edge => request_to_import_mapping(context_dir, request),
744 NextRuntime::NodeJs => external_request_to_cjs_import_mapping(context_dir, request),
745 };
746 let external_esm_if_node = move |context_dir: FileSystemPath, request: RcStr| match runtime {
747 NextRuntime::Edge => request_to_import_mapping(context_dir, request),
748 NextRuntime::NodeJs => external_request_to_esm_import_mapping(context_dir, request),
749 };
750
751 import_map.insert_exact_alias(
752 rcstr!("next/dist/compiled/@vercel/og/index.node.js"),
753 external_esm_if_node(
754 project_path.clone(),
755 rcstr!("next/dist/compiled/@vercel/og/index.node.js"),
756 ),
757 );
758
759 import_map.insert_exact_alias(
760 rcstr!("next/dist/server/ReactDOMServerPages"),
761 ImportMapping::Alternatives(vec![
762 request_to_import_mapping(project_path.clone(), rcstr!("react-dom/server.edge")),
763 request_to_import_mapping(project_path.clone(), rcstr!("react-dom/server.browser")),
764 ])
765 .resolved_cell(),
766 );
767
768 match &ty {
769 ServerContextType::Pages { .. } | ServerContextType::PagesApi { .. } => {}
770 ServerContextType::AppSSR { app_dir } => {
772 let next_package = get_next_package(app_dir.clone()).await?;
773 import_map.insert_exact_alias(
774 rcstr!("styled-jsx"),
775 request_to_import_mapping(next_package.clone(), rcstr!("styled-jsx")),
776 );
777 import_map.insert_wildcard_alias(
778 rcstr!("styled-jsx/"),
779 request_to_import_mapping(next_package.clone(), rcstr!("styled-jsx/*")),
780 );
781
782 rsc_aliases(
783 import_map,
784 project_path.clone(),
785 ty.clone(),
786 runtime,
787 next_config,
788 )
789 .await?;
790 }
791 ServerContextType::AppRSC { .. }
792 | ServerContextType::AppRoute { .. }
793 | ServerContextType::Middleware { .. }
794 | ServerContextType::Instrumentation { .. } => {
795 rsc_aliases(
796 import_map,
797 project_path.clone(),
798 ty.clone(),
799 runtime,
800 next_config,
801 )
802 .await?;
803 }
804 }
805
806 match &ty {
812 ServerContextType::Pages { .. } => {
813 insert_exact_alias_map(
814 import_map,
815 project_path.clone(),
816 fxindexmap! {rcstr!("server-only") => rcstr!("next/dist/compiled/server-only/empty"),
817 rcstr!("client-only") => rcstr!("next/dist/compiled/client-only/index"),
818 rcstr!("next/dist/compiled/server-only") => rcstr!("next/dist/compiled/server-only/empty"),
819 rcstr!("next/dist/compiled/client-only") => rcstr!("next/dist/compiled/client-only/index"),},
820 );
821 }
822 ServerContextType::PagesApi { .. }
823 | ServerContextType::AppRSC { .. }
824 | ServerContextType::AppRoute { .. }
825 | ServerContextType::Middleware { .. }
826 | ServerContextType::Instrumentation { .. } => {
827 insert_exact_alias_map(
828 import_map,
829 project_path.clone(),
830 fxindexmap! {rcstr!("server-only") => rcstr!("next/dist/compiled/server-only/empty"),
831 rcstr!("next/dist/compiled/server-only") => rcstr!("next/dist/compiled/server-only/empty"),
832 rcstr!("next/dist/compiled/client-only") => rcstr!("next/dist/compiled/client-only/error"),},
833 );
834 insert_client_only_error_alias(import_map);
835 }
836 ServerContextType::AppSSR { .. } => {
837 insert_exact_alias_map(
838 import_map,
839 project_path.clone(),
840 fxindexmap! {rcstr!("server-only") => rcstr!("next/dist/compiled/server-only/index"),
841 rcstr!("client-only") => rcstr!("next/dist/compiled/client-only/index"),
842 rcstr!("next/dist/compiled/server-only") => rcstr!("next/dist/compiled/server-only/index"),
843 rcstr!("next/dist/compiled/client-only") => rcstr!("next/dist/compiled/client-only/index"),},
844 );
845 }
846 }
847
848 insert_next_root_params_mapping(import_map, Either::Left(ty), collected_root_params).await?;
849
850 import_map.insert_exact_alias(
851 rcstr!("@vercel/og"),
852 external_cjs_if_node(
853 project_path.clone(),
854 rcstr!("next/dist/server/og/image-response"),
855 ),
856 );
857
858 import_map.insert_exact_alias(
859 rcstr!("next/dist/compiled/next-devtools"),
860 request_to_import_mapping(
861 project_path.clone(),
862 rcstr!("next/dist/next-devtools/dev-overlay.shim.js"),
863 ),
864 );
865
866 Ok(())
867}
868
869async fn get_react_client_package(next_config: Vc<NextConfig>) -> Result<&'static str> {
870 let react_production_profiling = *next_config.enable_react_production_profiling().await?;
871 let react_client_package = if react_production_profiling {
872 "profiling"
873 } else {
874 "client"
875 };
876
877 Ok(react_client_package)
878}
879
880async fn apply_vendored_react_aliases_server(
883 import_map: &mut ImportMap,
884 project_path: FileSystemPath,
885 ty: ServerContextType,
886 runtime: NextRuntime,
887 next_config: Vc<NextConfig>,
888) -> Result<()> {
889 let react_channel = if *next_config.use_react_experimental().await? {
890 "-experimental"
891 } else {
892 ""
893 };
894 let react_condition = if ty.should_use_react_server_condition() {
895 "server"
896 } else {
897 "client"
898 };
899
900 let mut react_alias = FxIndexMap::default();
906 if runtime == NextRuntime::NodeJs && react_condition == "client" {
907 react_alias.extend(fxindexmap! {rcstr!("react") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react"),
909 rcstr!("react/compiler-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-compiler-runtime"),
910 rcstr!("react/jsx-dev-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-dev-runtime"),
911 rcstr!("react/jsx-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtime"),
912 rcstr!("react-dom") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-dom"),
914 rcstr!("react-dom/client") => format!("next/dist/compiled/react-dom{react_channel}/client").into(),
915 rcstr!("react-dom/server") => format!("next/dist/compiled/react-dom{react_channel}/server.node").into(),
916 rcstr!("react-dom/server.browser") => format!("next/dist/compiled/react-dom{react_channel}/server.browser").into(),
917 rcstr!("react-dom/server.edge") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
919 rcstr!("react-dom/static") => format!("next/dist/compiled/react-dom{react_channel}/static.node").into(),
920 rcstr!("react-dom/static.browser") => format!("next/dist/compiled/react-dom{react_channel}/static.browser").into(),
921 rcstr!("react-dom/static.edge") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
922 rcstr!("react-server-dom-webpack/client") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client"),
924 rcstr!("react-server-dom-webpack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
925 rcstr!("react-server-dom-webpack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
926 rcstr!("react-server-dom-webpack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.node").into(),
927 rcstr!("react-server-dom-turbopack/client") => rcstr!("next/dist/server/route-modules/app-page/vendored/ssr/react-server-dom-turbopack-client"),
928 rcstr!("react-server-dom-turbopack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
929 rcstr!("react-server-dom-turbopack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
930 rcstr!("react-server-dom-turbopack/static.edge") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),})
931 } else if runtime == NextRuntime::NodeJs && react_condition == "server" {
932 react_alias.extend(fxindexmap! {rcstr!("react") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react"),
934 rcstr!("react/compiler-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-compiler-runtime"),
935 rcstr!("react/jsx-dev-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-jsx-dev-runtime"),
936 rcstr!("react/jsx-runtime") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-jsx-runtime"),
937 rcstr!("react-dom") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-dom"),
939 rcstr!("react-dom/client") => format!("next/dist/compiled/react-dom{react_channel}/client").into(),
940 rcstr!("react-dom/server") => format!("next/dist/compiled/react-dom{react_channel}/server.node").into(),
941 rcstr!("react-dom/server.browser") => format!("next/dist/compiled/react-dom{react_channel}/server.browser").into(),
942 rcstr!("react-dom/server.edge") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
944 rcstr!("react-dom/static") => format!("next/dist/compiled/react-dom{react_channel}/static.node").into(),
945 rcstr!("react-dom/static.browser") => format!("next/dist/compiled/react-dom{react_channel}/static.browser").into(),
946 rcstr!("react-dom/static.edge") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
947 rcstr!("react-server-dom-webpack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.node").into(),
949 rcstr!("react-server-dom-webpack/server") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server"),
950 rcstr!("react-server-dom-webpack/server.node") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server"),
951 rcstr!("react-server-dom-webpack/static") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-static"),
952 rcstr!("react-server-dom-turbopack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.node").into(),
953 rcstr!("react-server-dom-turbopack/server") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server"),
954 rcstr!("react-server-dom-turbopack/server.node") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-server"),
955 rcstr!("react-server-dom-turbopack/static") => rcstr!("next/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-turbopack-static"),
956
957 rcstr!("next/dist/compiled/react") => rcstr!("next/dist/compiled/react/index.js"),})
960 } else if runtime == NextRuntime::Edge && react_condition == "client" {
961 react_alias.extend(fxindexmap! {rcstr!("react") => format!("next/dist/compiled/react{react_channel}").into(),
963 rcstr!("react/compiler-runtime") => format!("next/dist/compiled/react{react_channel}/compiler-runtime").into(),
964 rcstr!("react/jsx-dev-runtime") => format!("next/dist/compiled/react{react_channel}/jsx-dev-runtime").into(),
965 rcstr!("react/jsx-runtime") => format!("next/dist/compiled/react{react_channel}/jsx-runtime").into(),
966 rcstr!("react-dom") => format!("next/dist/compiled/react-dom{react_channel}").into(),
968 rcstr!("react-dom/client") => format!("next/dist/compiled/react-dom{react_channel}/client").into(),
969 rcstr!("react-dom/server") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
970 rcstr!("react-dom/server.browser") => format!("next/dist/compiled/react-dom{react_channel}/server.browser").into(),
971 rcstr!("react-dom/server.edge") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
973 rcstr!("react-dom/static") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
974 rcstr!("react-dom/static.browser") => format!("next/dist/compiled/react-dom{react_channel}/static.browser").into(),
975 rcstr!("react-dom/static.edge") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
976 rcstr!("react-server-dom-webpack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge").into(),
978 rcstr!("react-server-dom-webpack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge").into(),
979 rcstr!("react-server-dom-webpack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
980 rcstr!("react-server-dom-webpack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),
981 rcstr!("react-server-dom-turbopack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge").into(),
982 rcstr!("react-server-dom-turbopack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge").into(),
983 rcstr!("react-server-dom-turbopack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
984 rcstr!("react-server-dom-turbopack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),})
985 } else if runtime == NextRuntime::Edge && react_condition == "server" {
986 react_alias.extend(fxindexmap! {rcstr!("react") => format!("next/dist/compiled/react{react_channel}/react.react-server").into(),
988 rcstr!("react/compiler-runtime") => format!("next/dist/compiled/react{react_channel}/compiler-runtime").into(),
989 rcstr!("react/jsx-dev-runtime") => format!("next/dist/compiled/react{react_channel}/jsx-dev-runtime.react-server").into(),
990 rcstr!("react/jsx-runtime") => format!("next/dist/compiled/react{react_channel}/jsx-runtime.react-server").into(),
991 rcstr!("react-dom") => format!("next/dist/compiled/react-dom{react_channel}/react-dom.react-server").into(),
993 rcstr!("react-dom/client") => format!("next/dist/compiled/react-dom{react_channel}/client").into(),
994 rcstr!("react-dom/server") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
995 rcstr!("react-dom/server.browser") => format!("next/dist/compiled/react-dom{react_channel}/server.browser").into(),
996 rcstr!("react-dom/server.edge") => format!("next/dist/compiled/react-dom{react_channel}/server.edge").into(),
998 rcstr!("react-dom/static") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
999 rcstr!("react-dom/static.browser") => format!("next/dist/compiled/react-dom{react_channel}/static.browser").into(),
1000 rcstr!("react-dom/static.edge") => format!("next/dist/compiled/react-dom{react_channel}/static.edge").into(),
1001 rcstr!("react-server-dom-webpack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge").into(),
1003 rcstr!("react-server-dom-webpack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge").into(),
1004 rcstr!("react-server-dom-webpack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
1005 rcstr!("react-server-dom-webpack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),
1006 rcstr!("react-server-dom-turbopack/client") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/client.edge").into(),
1007 rcstr!("react-server-dom-turbopack/server") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.edge").into(),
1008 rcstr!("react-server-dom-turbopack/server.node") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/server.node").into(),
1009 rcstr!("react-server-dom-turbopack/static") => format!("next/dist/compiled/react-server-dom-turbopack{react_channel}/static.edge").into(),});
1010
1011 react_alias.extend(fxindexmap! {rcstr!("next/dist/compiled/react") => react_alias["react"].clone(),
1013 rcstr!("next/dist/compiled/react-experimental") => react_alias["react"].clone(),
1014 rcstr!("next/dist/compiled/react/compiler-runtime") => react_alias["react/compiler-runtime"].clone(),
1015 rcstr!("next/dist/compiled/react-experimental/compiler-runtime") => react_alias["react/compiler-runtime"].clone(),
1016 rcstr!("next/dist/compiled/react/jsx-dev-runtime") => react_alias["react/jsx-dev-runtime"].clone(),
1017 rcstr!("next/dist/compiled/react-experimental/jsx-dev-runtime") => react_alias["react/jsx-dev-runtime"].clone(),
1018 rcstr!("next/dist/compiled/react/jsx-runtime") => react_alias["react/jsx-runtime"].clone(),
1019 rcstr!("next/dist/compiled/react-experimental/jsx-runtime") => react_alias["react/jsx-runtime"].clone(),
1020 rcstr!("next/dist/compiled/react-dom") => react_alias["react-dom"].clone(),
1021 rcstr!("next/dist/compiled/react-dom-experimental") => react_alias["react-dom"].clone(),});
1022 }
1023
1024 let react_client_package = get_react_client_package(next_config).await?;
1025 react_alias.extend(fxindexmap! {rcstr!("react-dom/client") => RcStr::from(format!("next/dist/compiled/react-dom{react_channel}/{react_client_package}")),});
1026
1027 let mut alias = react_alias;
1028 if react_condition == "server" {
1029 alias.extend(
1031 fxindexmap! {rcstr!("next/error") => rcstr!("next/dist/api/error.react-server"),
1032 rcstr!("next/navigation") => rcstr!("next/dist/api/navigation.react-server"),
1033 rcstr!("next/link") => rcstr!("next/dist/client/app-dir/link.react-server"),},
1034 );
1035 }
1036
1037 insert_exact_alias_map(import_map, project_path, alias);
1038
1039 Ok(())
1040}
1041
1042async fn rsc_aliases(
1043 import_map: &mut ImportMap,
1044 project_path: FileSystemPath,
1045 ty: ServerContextType,
1046 runtime: NextRuntime,
1047 next_config: Vc<NextConfig>,
1048) -> Result<()> {
1049 apply_vendored_react_aliases_server(
1050 import_map,
1051 project_path.clone(),
1052 ty.clone(),
1053 runtime,
1054 next_config,
1055 )
1056 .await?;
1057
1058 let mut alias = FxIndexMap::default();
1059 if ty.should_use_react_server_condition() {
1060 alias.extend(
1062 fxindexmap! {rcstr!("next/error") => rcstr!("next/dist/api/error.react-server"),
1063 rcstr!("next/navigation") => rcstr!("next/dist/api/navigation.react-server"),
1064 rcstr!("next/link") => rcstr!("next/dist/client/app-dir/link.react-server"),},
1065 );
1066 }
1067
1068 insert_exact_alias_map(import_map, project_path.clone(), alias);
1069
1070 Ok(())
1071}
1072
1073pub fn mdx_import_source_file() -> RcStr {
1074 format!("{VIRTUAL_PACKAGE_NAME}/mdx-import-source").into()
1075}
1076
1077async fn insert_optimized_module_aliases(
1080 import_map: &mut ImportMap,
1081 project_path: FileSystemPath,
1082) -> Result<()> {
1083 insert_exact_alias_map(
1084 import_map,
1085 project_path,
1086 fxindexmap! {rcstr!("unfetch") => rcstr!("next/dist/build/polyfills/fetch/index.js"),
1087 rcstr!("isomorphic-unfetch") => rcstr!("next/dist/build/polyfills/fetch/index.js"),
1088 rcstr!("whatwg-fetch") => rcstr!("next/dist/build/polyfills/fetch/whatwg-fetch.js"),
1089 rcstr!("object-assign") => rcstr!("next/dist/build/polyfills/object-assign.js"),
1090 rcstr!("object.assign/auto") => rcstr!("next/dist/build/polyfills/object.assign/auto.js"),
1091 rcstr!("object.assign/implementation") => rcstr!("next/dist/build/polyfills/object.assign/implementation.js"),
1092 rcstr!("object.assign/polyfill") => rcstr!("next/dist/build/polyfills/object.assign/polyfill.js"),
1093 rcstr!("object.assign/shim") => rcstr!("next/dist/build/polyfills/object.assign/shim.js"),
1094 rcstr!("url") => rcstr!("next/dist/compiled/native-url"),
1095 rcstr!("node:url") => rcstr!("next/dist/compiled/native-url"),},
1096 );
1097 Ok(())
1098}
1099
1100async fn insert_next_shared_aliases(
1102 import_map: &mut ImportMap,
1103 project_path: FileSystemPath,
1104 execution_context: Vc<ExecutionContext>,
1105 next_config: Vc<NextConfig>,
1106 next_mode: Vc<NextMode>,
1107 ty: ContextType,
1108 is_runtime_edge: bool,
1109) -> Result<()> {
1110 let package_root = next_js_fs().root().owned().await?;
1111
1112 insert_alias_to_alternatives(
1113 import_map,
1114 mdx_import_source_file(),
1115 vec![
1116 request_to_import_mapping(project_path.clone(), rcstr!("./mdx-components")),
1117 request_to_import_mapping(project_path.clone(), rcstr!("./src/mdx-components")),
1118 request_to_import_mapping(project_path.clone(), rcstr!("@mdx-js/react")),
1119 request_to_import_mapping(project_path.clone(), rcstr!("@next/mdx/mdx-components.js")),
1120 ],
1121 );
1122
1123 insert_package_alias(
1124 import_map,
1125 &format!("{VIRTUAL_PACKAGE_NAME}/"),
1126 package_root,
1127 );
1128
1129 match ty {
1130 ContextType::Client(_)
1131 | ContextType::Server(
1132 ServerContextType::Pages { .. }
1133 | ServerContextType::AppSSR { .. }
1134 | ServerContextType::AppRSC { .. },
1135 ) => {
1136 import_map.insert_alias(
1137 AliasPattern::exact(rcstr!("next/font/local/target.css")),
1138 ImportMapping::Dynamic(ResolvedVc::upcast(
1139 NextFontLocalReplacer::new(project_path.clone())
1140 .to_resolved()
1141 .await?,
1142 ))
1143 .resolved_cell(),
1144 );
1145
1146 import_map.insert_alias(
1147 AliasPattern::exact(rcstr!(
1148 "@vercel/turbopack-next/internal/font/local/cssmodule.module.css"
1149 )),
1150 ImportMapping::Dynamic(ResolvedVc::upcast(
1151 NextFontLocalCssModuleReplacer::new().to_resolved().await?,
1152 ))
1153 .resolved_cell(),
1154 );
1155
1156 import_map.insert_alias(
1157 AliasPattern::exact(rcstr!("@vercel/turbopack-next/internal/font/local/font")),
1158 ImportMapping::Dynamic(ResolvedVc::upcast(
1159 NextFontLocalFontFileReplacer::new().to_resolved().await?,
1160 ))
1161 .resolved_cell(),
1162 );
1163 }
1164 _ => {}
1165 }
1166
1167 let next_font_google_replacer_mapping = ImportMapping::Dynamic(ResolvedVc::upcast(
1168 NextFontGoogleReplacer::new(project_path.clone())
1169 .to_resolved()
1170 .await?,
1171 ))
1172 .resolved_cell();
1173
1174 import_map.insert_alias(
1175 AliasPattern::exact(rcstr!("next/font/google/target.css")),
1177 next_font_google_replacer_mapping,
1178 );
1179
1180 import_map.insert_alias(
1181 AliasPattern::exact(rcstr!("@next/font/google/target.css")),
1183 next_font_google_replacer_mapping,
1184 );
1185
1186 let fetch_client = next_config.fetch_client(next_mode);
1187 import_map.insert_alias(
1188 AliasPattern::exact(rcstr!(
1189 "@vercel/turbopack-next/internal/font/google/cssmodule.module.css"
1190 )),
1191 ImportMapping::Dynamic(ResolvedVc::upcast(
1192 NextFontGoogleCssModuleReplacer::new(
1193 project_path.clone(),
1194 execution_context,
1195 next_mode,
1196 fetch_client,
1197 )
1198 .to_resolved()
1199 .await?,
1200 ))
1201 .resolved_cell(),
1202 );
1203
1204 import_map.insert_alias(
1205 AliasPattern::exact(GOOGLE_FONTS_INTERNAL_PREFIX),
1206 ImportMapping::Dynamic(ResolvedVc::upcast(
1207 NextFontGoogleFontFileReplacer::new(project_path.clone(), next_mode, fetch_client)
1208 .to_resolved()
1209 .await?,
1210 ))
1211 .resolved_cell(),
1212 );
1213
1214 let next_package = get_next_package(project_path.clone()).await?;
1215 import_map.insert_singleton_alias(rcstr!("@swc/helpers"), next_package.clone());
1216 import_map.insert_singleton_alias(rcstr!("styled-jsx"), next_package.clone());
1217 import_map.insert_singleton_alias(rcstr!("next"), project_path.clone());
1218 import_map.insert_singleton_alias(rcstr!("react"), project_path.clone());
1219 import_map.insert_singleton_alias(rcstr!("react-dom"), project_path.clone());
1220 let react_client_package = get_react_client_package(next_config).await?;
1221 import_map.insert_exact_alias(
1222 rcstr!("react-dom/client"),
1223 request_to_import_mapping(
1224 project_path.clone(),
1225 format!("react-dom/{react_client_package}").into(),
1226 ),
1227 );
1228
1229 import_map.insert_alias(
1230 AliasPattern::exact(rcstr!("next")),
1233 ImportMapping::Empty.resolved_cell(),
1234 );
1235
1236 import_map.insert_exact_alias(
1238 rcstr!("setimmediate"),
1239 request_to_import_mapping(
1240 project_path.clone(),
1241 rcstr!("next/dist/compiled/setimmediate"),
1242 ),
1243 );
1244
1245 import_map.insert_exact_alias(
1246 rcstr!("private-next-rsc-server-reference"),
1247 request_to_import_mapping(
1248 project_path.clone(),
1249 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/server-reference"),
1250 ),
1251 );
1252 import_map.insert_exact_alias(
1253 rcstr!("private-next-rsc-action-client-wrapper"),
1254 request_to_import_mapping(
1255 project_path.clone(),
1256 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/action-client-wrapper"),
1257 ),
1258 );
1259 import_map.insert_exact_alias(
1260 rcstr!("private-next-rsc-action-validate"),
1261 request_to_import_mapping(
1262 project_path.clone(),
1263 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/action-validate"),
1264 ),
1265 );
1266 import_map.insert_exact_alias(
1267 rcstr!("private-next-rsc-action-encryption"),
1268 request_to_import_mapping(
1269 project_path.clone(),
1270 rcstr!("next/dist/server/app-render/encryption"),
1271 ),
1272 );
1273 import_map.insert_exact_alias(
1274 rcstr!("private-next-rsc-cache-wrapper"),
1275 request_to_import_mapping(
1276 project_path.clone(),
1277 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/cache-wrapper"),
1278 ),
1279 );
1280 import_map.insert_exact_alias(
1281 rcstr!("private-next-rsc-track-dynamic-import"),
1282 request_to_import_mapping(
1283 project_path.clone(),
1284 rcstr!("next/dist/build/webpack/loaders/next-flight-loader/track-dynamic-import"),
1285 ),
1286 );
1287
1288 insert_package_alias(
1289 import_map,
1290 "@vercel/turbopack-node/",
1291 turbopack_node::embed_js::embed_fs().root().owned().await?,
1292 );
1293
1294 let image_config = next_config.image_config().await?;
1295 if let Some(loader_file) = image_config.loader_file.as_deref().map(RcStr::from) {
1296 import_map.insert_exact_alias(
1297 rcstr!("next/dist/shared/lib/image-loader"),
1298 request_to_import_mapping(project_path.clone(), loader_file.clone()),
1299 );
1300
1301 if is_runtime_edge {
1302 import_map.insert_exact_alias(
1303 rcstr!("next/dist/esm/shared/lib/image-loader"),
1304 request_to_import_mapping(project_path.clone(), loader_file),
1305 );
1306 }
1307 }
1308
1309 Ok(())
1310}
1311
1312pub async fn get_next_package(context_directory: FileSystemPath) -> Result<FileSystemPath> {
1313 try_get_next_package(context_directory)
1314 .owned()
1315 .await?
1316 .context("Next.js package not found")
1317}
1318
1319#[turbo_tasks::value(shared)]
1320struct MissingNextFolderIssue {
1321 path: FileSystemPath,
1322 root: FileSystemPath,
1323}
1324
1325#[async_trait]
1326#[turbo_tasks::value_impl]
1327impl Issue for MissingNextFolderIssue {
1328 async fn file_path(&self) -> Result<FileSystemPath> {
1329 Ok(self.path.clone())
1330 }
1331
1332 fn severity(&self) -> IssueSeverity {
1333 IssueSeverity::Error
1337 }
1338
1339 fn stage(&self) -> IssueStage {
1340 IssueStage::Resolve
1341 }
1342
1343 async fn title(&self) -> Result<StyledString> {
1344 Ok(StyledString::Text(rcstr!(
1345 "Could not find the Next.js package (next/package.json)"
1346 )))
1347 }
1348
1349 async fn description(&self) -> Result<Option<StyledString>> {
1350 let context_path: RcStr = match to_sys_path(self.path.clone()).await? {
1351 Some(path) => path.to_str().unwrap_or("{unknown}").into(),
1352 _ => rcstr!("{unknown}"),
1353 };
1354 let root_path: RcStr = match to_sys_path(self.root.clone()).await? {
1355 Some(path) => path.to_str().unwrap_or("{unknown}").into(),
1356 _ => rcstr!("{unknown}"),
1357 };
1358
1359 Ok(Some(StyledString::Stack(vec![
1360 StyledString::Line(vec![
1361 StyledString::Text(rcstr!("Resolved from: ")),
1362 StyledString::Strong(context_path),
1363 ]),
1364 StyledString::Line(vec![
1365 StyledString::Text(rcstr!("Filesystem root used for resolution: ")),
1366 StyledString::Strong(root_path),
1367 ]),
1368 StyledString::Line(vec![StyledString::Text(rcstr!(""))]),
1369 StyledString::Line(vec![StyledString::Text(rcstr!("Possible causes:"))]),
1370 StyledString::Line(vec![StyledString::Text(rcstr!(
1371 " - node_modules is being reorganized by a concurrent install (e.g. pnpm adding \
1372 a package with a `next` peer dependency). This is transient and should clear \
1373 once the install completes."
1374 ))]),
1375 StyledString::Line(vec![StyledString::Text(rcstr!(
1376 " - node_modules/next was removed, renamed, or has a broken symlink."
1377 ))]),
1378 StyledString::Line(vec![
1379 StyledString::Text(rcstr!(" - The workspace root is incorrect — see ")),
1380 StyledString::Code(rcstr!("turbopack.root")),
1381 StyledString::Text(rcstr!(
1382 " in the Next.js config docs for how to configure it."
1383 )),
1384 ]),
1385 StyledString::Line(vec![StyledString::Text(rcstr!(
1386 " - In a monorepo, the Next.js package may only exist in a directory above the \
1387 closest directory containing a package manager lockfile. The workspace root is \
1388 detected by locating the nearest package manager lockfile."
1389 ))]),
1390 StyledString::Line(vec![StyledString::Text(rcstr!(
1391 " - Next.js is installed globally rather than as a project dependency. This is \
1392 not supported; install it locally."
1393 ))]),
1394 StyledString::Line(vec![StyledString::Text(rcstr!(""))]),
1395 StyledString::Line(vec![StyledString::Text(rcstr!(
1396 "Note: To ensure a hermetic build and a portable cache, files outside of the \
1397 workspace root are not compiled."
1398 ))]),
1399 ])))
1400 }
1401
1402 fn documentation_link(&self) -> RcStr {
1403 rcstr!(
1404 "https://nextjs.org/docs/app/api-reference/config/next-config-js/turbopack#root-directory"
1405 )
1406 }
1407}
1408
1409#[turbo_tasks::function]
1410pub async fn try_get_next_package(
1411 context_directory: FileSystemPath,
1412) -> Result<Vc<OptionFileSystemPath>> {
1413 let root = context_directory.root().owned().await?;
1414 let result = resolve(
1415 context_directory.clone(),
1416 ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined),
1417 Request::parse(Pattern::Constant(rcstr!("next/package.json"))),
1418 node_cjs_resolve_options(),
1419 );
1420 if let Some(source) = result.await?.first_source() {
1421 Ok(Vc::cell(Some(source.ident().await?.path.parent())))
1422 } else {
1423 MissingNextFolderIssue {
1424 path: context_directory,
1425 root,
1426 }
1427 .resolved_cell()
1428 .emit();
1429 Ok(Vc::cell(None))
1430 }
1431}
1432
1433pub async fn insert_alias_option<const N: usize>(
1434 import_map: &mut ImportMap,
1435 project_path: &FileSystemPath,
1436 alias_options: Vc<ResolveAliasMap>,
1437 conditions: [&'static str; N],
1438) -> Result<()> {
1439 let conditions = BTreeMap::from(conditions.map(|c| (c.into(), ConditionValue::Set)));
1440 for (alias, value) in &alias_options.await? {
1441 if let Some(mapping) = export_value_to_import_mapping(value, &conditions, project_path) {
1442 import_map.insert_alias(alias, mapping);
1443 }
1444 }
1445 Ok(())
1446}
1447
1448fn export_value_to_import_mapping(
1449 value: &SubpathValue,
1450 conditions: &BTreeMap<RcStr, ConditionValue>,
1451 project_path: &FileSystemPath,
1452) -> Option<ResolvedVc<ImportMapping>> {
1453 let alias_key = AliasKey::Exact;
1454 let mut results = Vec::new();
1455 value.convert().add_results(
1456 Cow::Borrowed(""),
1457 &alias_key,
1458 conditions,
1459 &ConditionValue::Unset,
1460 &mut FxHashMap::default(),
1461 &mut results,
1462 );
1463
1464 let mappings: Vec<_> = results
1465 .iter()
1466 .filter_map(|r| match &r.ty {
1467 ReplacedSubpathValueResultType::Path(path) => {
1468 let m = path.as_constant_string()?;
1469 Some(
1470 ImportMapping::PrimaryAlternative(m.clone(), Some(project_path.clone()))
1471 .resolved_cell(),
1472 )
1473 }
1474 ReplacedSubpathValueResultType::Empty => Some(ImportMapping::Empty.resolved_cell()),
1475 })
1476 .collect();
1477
1478 match mappings.len() {
1479 0 => None,
1480 1 => mappings.into_iter().next(),
1481 _ => Some(ImportMapping::Alternatives(mappings).resolved_cell()),
1482 }
1483}
1484
1485fn insert_exact_alias_map(
1486 import_map: &mut ImportMap,
1487 project_path: FileSystemPath,
1488 map: FxIndexMap<RcStr, RcStr>,
1489) {
1490 for (pattern, request) in map {
1491 import_map.insert_exact_alias(
1492 pattern,
1493 request_to_import_mapping(project_path.clone(), request),
1494 );
1495 }
1496}
1497
1498fn insert_wildcard_alias_map(
1499 import_map: &mut ImportMap,
1500 project_path: FileSystemPath,
1501 map: FxIndexMap<RcStr, RcStr>,
1502) {
1503 for (pattern, request) in map {
1504 import_map.insert_wildcard_alias(
1505 pattern,
1506 request_to_import_mapping(project_path.clone(), request),
1507 );
1508 }
1509}
1510
1511fn insert_alias_to_alternatives<'a>(
1513 import_map: &mut ImportMap,
1514 alias: impl Into<RcStr> + 'a,
1515 alternatives: Vec<ResolvedVc<ImportMapping>>,
1516) {
1517 import_map.insert_exact_alias(
1518 alias.into(),
1519 ImportMapping::Alternatives(alternatives).resolved_cell(),
1520 );
1521}
1522
1523fn insert_package_alias(import_map: &mut ImportMap, prefix: &str, package_root: FileSystemPath) {
1525 import_map.insert_wildcard_alias(
1526 prefix,
1527 ImportMapping::PrimaryAlternative(rcstr!("./*"), Some(package_root)).resolved_cell(),
1528 );
1529}
1530
1531async fn insert_instrumentation_client_alias(
1538 import_map: &mut ImportMap,
1539 project_path: FileSystemPath,
1540 next_config: Vc<NextConfig>,
1541) -> Result<()> {
1542 let user_file_alternatives = vec![
1543 request_to_import_mapping(project_path.clone(), rcstr!("./src/instrumentation-client")),
1544 request_to_import_mapping(
1545 project_path.clone(),
1546 rcstr!("./src/instrumentation-client.ts"),
1547 ),
1548 request_to_import_mapping(project_path.clone(), rcstr!("./instrumentation-client")),
1549 request_to_import_mapping(project_path.clone(), rcstr!("./instrumentation-client.ts")),
1550 ImportMapping::Ignore.resolved_cell(),
1551 ];
1552
1553 let modules = next_config.instrumentation_client_inject().await?;
1554
1555 if modules.is_empty() {
1556 insert_alias_to_alternatives(
1557 import_map,
1558 rcstr!("private-next-instrumentation-client"),
1559 user_file_alternatives,
1560 );
1561 return Ok(());
1562 }
1563
1564 insert_alias_to_alternatives(
1567 import_map,
1568 rcstr!("private-next-instrumentation-client-user"),
1569 user_file_alternatives,
1570 );
1571
1572 let modules = modules
1573 .iter()
1574 .map(|s| s.as_str())
1575 .chain(std::iter::once("private-next-instrumentation-client-user"));
1576 let mut body = String::from("module.exports = [");
1577 for (i, spec) in modules.enumerate() {
1578 if i > 0 {
1579 body.push(',');
1580 }
1581 body.push_str(&format!("require({})", serde_json::to_string(spec)?));
1582 }
1583 body.push_str("];\n");
1584
1585 let virtual_source = VirtualSource::new(
1586 project_path.join("__next_instrumentation_client.cjs")?,
1590 AssetContent::file(FileContent::Content(body.into()).cell()),
1591 )
1592 .to_resolved()
1593 .await?;
1594
1595 import_map.insert_exact_alias(
1596 rcstr!("private-next-instrumentation-client"),
1597 ImportMapping::Direct(
1598 ResolveResult::source(ResolvedVc::upcast(virtual_source)).resolved_cell(),
1599 )
1600 .resolved_cell(),
1601 );
1602
1603 Ok(())
1604}
1605
1606fn insert_client_only_error_alias(import_map: &mut ImportMap) {
1607 import_map.insert_exact_alias(
1608 rcstr!("client-only"),
1609 ImportMapping::Error(ResolvedVc::upcast(
1610 InvalidImportIssue {
1611 title: StyledString::Line(vec![
1612 StyledString::Code(rcstr!("'client-only'")),
1613 StyledString::Text(rcstr!(
1614 " cannot be imported from a Server Component module"
1615 )),
1616 ])
1617 .resolved_cell(),
1618 description: Some(
1619 StyledString::Line(vec![StyledString::Text(
1620 "It should only be used from a Client Component.".into(),
1621 )])
1622 .resolved_cell(),
1623 ),
1624 }
1625 .resolved_cell(),
1626 ))
1627 .resolved_cell(),
1628 );
1629
1630 let mapping = ImportMapping::Error(ResolvedVc::upcast(
1633 InvalidImportIssue {
1634 title: StyledString::Line(vec![
1635 StyledString::Code(rcstr!("'styled-jsx'")),
1636 StyledString::Text(rcstr!(" cannot be imported from a Server Component module")),
1637 ])
1638 .resolved_cell(),
1639 description: Some(
1640 StyledString::Line(vec![StyledString::Text(
1641 "It only works in a Client Component but none of its parents are marked with \
1642 'use client', so they're Server Components by default."
1643 .into(),
1644 )])
1645 .resolved_cell(),
1646 ),
1647 }
1648 .resolved_cell(),
1649 ))
1650 .resolved_cell();
1651 import_map.insert_exact_alias(rcstr!("styled-jsx"), mapping);
1652 import_map.insert_wildcard_alias(rcstr!("styled-jsx/"), mapping);
1653}
1654
1655fn insert_server_only_error_alias(import_map: &mut ImportMap) {
1656 import_map.insert_exact_alias(
1657 rcstr!("server-only"),
1658 ImportMapping::Error(ResolvedVc::upcast(
1659 InvalidImportIssue {
1660 title: StyledString::Line(vec![
1661 StyledString::Code(rcstr!("'server-only'")),
1662 StyledString::Text(rcstr!(
1663 " cannot be imported from a Client Component module"
1664 )),
1665 ])
1666 .resolved_cell(),
1667 description: Some(
1668 StyledString::Line(vec![StyledString::Text(
1669 "It should only be used from a Server Component.".into(),
1670 )])
1671 .resolved_cell(),
1672 ),
1673 }
1674 .resolved_cell(),
1675 ))
1676 .resolved_cell(),
1677 );
1678}
1679
1680#[turbo_tasks::value(shared)]
1681struct InvalidImportIssue {
1682 title: ResolvedVc<StyledString>,
1683 description: Option<ResolvedVc<StyledString>>,
1684}
1685
1686#[async_trait]
1687#[turbo_tasks::value_impl]
1688impl Issue for InvalidImportIssue {
1689 fn severity(&self) -> IssueSeverity {
1690 IssueSeverity::Error
1691 }
1692
1693 async fn file_path(&self) -> Result<FileSystemPath> {
1694 panic!("InvalidImportIssue::file_path should not be called");
1695 }
1696
1697 fn stage(&self) -> IssueStage {
1698 IssueStage::Resolve
1699 }
1700
1701 async fn title(&self) -> Result<StyledString> {
1702 Ok((*self.title.await?).clone())
1703 }
1704
1705 async fn description(&self) -> Result<Option<StyledString>> {
1706 match self.description {
1707 Some(inner) => Ok(Some((*inner.await?).clone())),
1708 None => Ok(None),
1709 }
1710 }
1711}
1712
1713fn insert_exact_alias_or_js(
1715 import_map: &mut ImportMap,
1716 pattern: RcStr,
1717 mapping: ResolvedVc<ImportMapping>,
1718) {
1719 import_map.insert_exact_alias(format!("{pattern}.js"), mapping);
1720 import_map.insert_exact_alias(pattern, mapping);
1721}
1722
1723fn request_to_import_mapping(
1726 context_path: FileSystemPath,
1727 request: RcStr,
1728) -> ResolvedVc<ImportMapping> {
1729 ImportMapping::PrimaryAlternative(request, Some(context_path)).resolved_cell()
1730}
1731
1732fn external_request_to_cjs_import_mapping(
1735 context_dir: FileSystemPath,
1736 request: RcStr,
1737) -> ResolvedVc<ImportMapping> {
1738 ImportMapping::PrimaryAlternativeExternal {
1739 name: Some(request),
1740 ty: ExternalType::CommonJs,
1741 traced: ExternalTraced::Traced,
1742 lookup_dir: context_dir,
1743 }
1744 .resolved_cell()
1745}
1746
1747fn external_request_to_esm_import_mapping(
1750 context_dir: FileSystemPath,
1751 request: RcStr,
1752) -> ResolvedVc<ImportMapping> {
1753 ImportMapping::PrimaryAlternativeExternal {
1754 name: Some(request),
1755 ty: ExternalType::EcmaScriptModule,
1756 traced: ExternalTraced::Traced,
1757 lookup_dir: context_dir,
1758 }
1759 .resolved_cell()
1760}