Skip to main content

turbopack_node/
lib.rs

1#![feature(min_specialization)]
2#![feature(arbitrary_self_types)]
3#![feature(arbitrary_self_types_pointers)]
4
5use anyhow::Result;
6use rustc_hash::FxHashMap;
7use turbo_tasks::{ResolvedVc, TryFlatJoinIterExt, Vc};
8use turbo_tasks_fs::{File, FileContent, FileSystemPath};
9use turbopack_core::{
10    asset::{Asset, AssetContent},
11    output::{ExpandOutputAssetsInput, OutputAsset, OutputAssets, expand_output_assets},
12    source_map::GenerateSourceMap,
13    virtual_output::VirtualOutputAsset,
14};
15
16mod backend;
17pub mod debug;
18pub mod embed_js;
19pub mod evaluate;
20pub mod execution_context;
21mod format;
22mod pool_stats;
23// The child-process pool needs `tokio::process` and a TCP listener, neither of which exists on
24// wasi, so `process_pool` is inert on wasm and `worker_pool` is the only available backend there.
25#[cfg(all(feature = "process_pool", not(target_family = "wasm")))]
26pub mod process_pool;
27pub mod source_map;
28pub mod transforms;
29#[cfg(feature = "worker_pool")]
30pub mod worker_pool;
31
32pub use backend::{CreatePoolFuture, CreatePoolOptions, NodeBackend};
33#[cfg(all(feature = "process_pool", not(target_family = "wasm")))]
34pub fn child_process_backend() -> Vc<Box<dyn NodeBackend>> {
35    Vc::upcast(process_pool::ChildProcessesBackend.cell())
36}
37#[cfg(feature = "worker_pool")]
38pub fn worker_threads_backend() -> Vc<Box<dyn NodeBackend>> {
39    Vc::upcast(worker_pool::WorkerThreadsBackend.cell())
40}
41
42#[turbo_tasks::function]
43async fn emit(
44    intermediate_asset: Vc<Box<dyn OutputAsset>>,
45    intermediate_output_path: FileSystemPath,
46) -> Result<()> {
47    for asset in internal_assets(intermediate_asset, intermediate_output_path).await? {
48        let _ = asset
49            .content()
50            .write(asset.path().owned().await?)
51            .to_resolved()
52            .await?;
53    }
54    Ok(())
55}
56
57/// Extracts the subgraph of "internal" assets (assets within the passes
58/// directory). Also lists all boundary assets that are not part of the
59/// "internal" subgraph.
60#[turbo_tasks::function]
61async fn internal_assets(
62    intermediate_asset: ResolvedVc<Box<dyn OutputAsset>>,
63    intermediate_output_path: FileSystemPath,
64) -> Result<Vc<OutputAssets>> {
65    let all_assets = expand_output_assets(
66        std::iter::once(ExpandOutputAssetsInput::Asset(intermediate_asset)),
67        true,
68    )
69    .await?;
70    let internal_assets = all_assets
71        .into_iter()
72        .map(async |asset| {
73            let path = asset.path().await?;
74            if path.is_inside_ref(&intermediate_output_path) {
75                Ok(Some(asset))
76            } else {
77                Ok(None)
78            }
79        })
80        .try_flat_join()
81        .await?;
82    Ok(Vc::cell(internal_assets))
83}
84
85#[turbo_tasks::value(transparent)]
86pub struct AssetsForSourceMapping(FxHashMap<String, ResolvedVc<Box<dyn GenerateSourceMap>>>);
87
88/// Extracts a map of "internal" assets ([`internal_assets`]) which implement
89/// the [GenerateSourceMap] trait.
90#[turbo_tasks::function]
91async fn internal_assets_for_source_mapping(
92    intermediate_asset: Vc<Box<dyn OutputAsset>>,
93    intermediate_output_path: FileSystemPath,
94) -> Result<Vc<AssetsForSourceMapping>> {
95    let internal_assets =
96        internal_assets(intermediate_asset, intermediate_output_path.clone()).await?;
97    let intermediate_output_path = intermediate_output_path.clone();
98    let mut internal_assets_for_source_mapping = FxHashMap::default();
99    for asset in internal_assets.iter() {
100        if let Some(generate_source_map) =
101            ResolvedVc::try_sidecast::<Box<dyn GenerateSourceMap>>(*asset)
102            && let Some(path) = intermediate_output_path.get_path_to(&*asset.path().await?)
103        {
104            internal_assets_for_source_mapping.insert(path.to_string(), generate_source_map);
105        }
106    }
107    Ok(Vc::cell(internal_assets_for_source_mapping))
108}
109
110/// Emit a basic package.json that sets the type of the package to commonjs.
111/// Currently code generated for Node is CommonJS, while authored code may be
112/// ESM, for example.
113fn emit_package_json(dir: FileSystemPath) -> Result<Vc<()>> {
114    Ok(emit(
115        Vc::upcast(VirtualOutputAsset::new(
116            dir.join("package.json")?,
117            AssetContent::file(FileContent::Content(File::from("{\"type\": \"commonjs\"}")).cell()),
118        )),
119        dir,
120    ))
121}