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