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