next_core/
emit.rs

1use anyhow::Result;
2use tracing::Instrument;
3use turbo_tasks::{TryFlatJoinIterExt, Vc};
4use turbo_tasks_fs::{FileSystemPath, rebase};
5use turbopack_core::{
6    asset::Asset,
7    output::{ExpandedOutputAssets, OutputAsset, OutputAssets},
8    reference::all_assets_from_entries,
9};
10
11/// Emits all assets transitively reachable from the given chunks, that are
12/// inside the node root or the client root.
13///
14/// Assets inside the given client root are rebased to the given client output
15/// path.
16#[turbo_tasks::function]
17pub async fn emit_all_assets(
18    assets: Vc<OutputAssets>,
19    node_root: FileSystemPath,
20    client_relative_path: FileSystemPath,
21    client_output_path: FileSystemPath,
22) -> Result<()> {
23    emit_assets(
24        all_assets_from_entries(assets),
25        node_root,
26        client_relative_path,
27        client_output_path,
28    )
29    .as_side_effect()
30    .await?;
31    Ok(())
32}
33
34/// Emits all assets transitively reachable from the given chunks, that are
35/// inside the node root or the client root.
36///
37/// Assets inside the given client root are rebased to the given client output
38/// path.
39#[turbo_tasks::function]
40pub async fn emit_assets(
41    assets: Vc<ExpandedOutputAssets>,
42    node_root: FileSystemPath,
43    client_relative_path: FileSystemPath,
44    client_output_path: FileSystemPath,
45) -> Result<()> {
46    let _: Vec<()> = assets
47        .await?
48        .iter()
49        .copied()
50        .map(|asset| {
51            let node_root = node_root.clone();
52            let client_relative_path = client_relative_path.clone();
53            let client_output_path = client_output_path.clone();
54
55            async move {
56                let path = asset.path().owned().await?;
57                let span = tracing::info_span!("emit asset", name = %path.value_to_string().await?);
58                async move {
59                    Ok(if path.is_inside_ref(&node_root) {
60                        Some(emit(*asset).as_side_effect().await?)
61                    } else if path.is_inside_ref(&client_relative_path) {
62                        // Client assets are emitted to the client output path, which is prefixed
63                        // with _next. We need to rebase them to remove that
64                        // prefix.
65                        Some(
66                            emit_rebase(*asset, client_relative_path, client_output_path)
67                                .as_side_effect()
68                                .await?,
69                        )
70                    } else {
71                        None
72                    })
73                }
74                .instrument(span)
75                .await
76            }
77        })
78        .try_flat_join()
79        .await?;
80    Ok(())
81}
82
83#[turbo_tasks::function]
84async fn emit(asset: Vc<Box<dyn OutputAsset>>) -> Result<()> {
85    asset
86        .content()
87        .resolve()
88        .await?
89        .write(asset.path().owned().await?)
90        .as_side_effect()
91        .await?;
92    Ok(())
93}
94
95#[turbo_tasks::function]
96async fn emit_rebase(
97    asset: Vc<Box<dyn OutputAsset>>,
98    from: FileSystemPath,
99    to: FileSystemPath,
100) -> Result<()> {
101    let path = rebase(asset.path().owned().await?, from, to)
102        .owned()
103        .await?;
104    let content = asset.content();
105    content
106        .resolve()
107        .await?
108        .write(path)
109        .as_side_effect()
110        .await?;
111    Ok(())
112}