turbopack_core/chunk/
optimize.rs

1//! Traits and functions to optimize a list of chunks.
2//!
3//! Usually chunks are optimized by limiting their total count, restricting
4//! their size and eliminating duplicates between them.
5
6use anyhow::Result;
7use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc};
8use turbo_tasks_fs::{FileSystemPath, FileSystemPathOption};
9
10use crate::chunk::containment_tree::{ContainmentTree, ContainmentTreeKey};
11
12#[derive(Debug, Clone, Eq, PartialEq, Hash)]
13struct FileSystemPathKey(ResolvedVc<FileSystemPath>);
14
15impl FileSystemPathKey {
16    async fn new(path: Vc<FileSystemPath>) -> Result<Self> {
17        Ok(Self(path.to_resolved().await?))
18    }
19}
20
21#[async_trait::async_trait]
22impl ContainmentTreeKey for FileSystemPathKey {
23    async fn parent(&self) -> Result<Self> {
24        Ok(FileSystemPathKey::new(self.0.parent()).await?)
25    }
26}
27
28pub async fn optimize_by_common_parent<T, Acc, GetCommonParent, Optimize>(
29    chunks: &[T],
30    get_common_parent: GetCommonParent,
31    optimize: Optimize,
32) -> Result<Acc>
33where
34    T: Clone,
35    GetCommonParent: Fn(T) -> Vc<FileSystemPathOption> + Clone,
36    Optimize: Fn(Option<Vec<T>>, Vec<Acc>) -> Acc,
37{
38    let tree = ContainmentTree::build(
39        chunks
40            .iter()
41            .map(move |chunk| {
42                let get_common_parent = get_common_parent.clone();
43                async move {
44                    let common_parent = get_common_parent(chunk.clone()).await?;
45
46                    Ok((
47                        if let Some(common_parent) = &*common_parent {
48                            Some(FileSystemPathKey::new(**common_parent).await?)
49                        } else {
50                            None
51                        },
52                        chunk.clone(),
53                    ))
54                }
55            })
56            .try_join()
57            .await?,
58    )
59    .await?;
60
61    fn optimize_tree<K, V, Acc>(
62        tree: ContainmentTree<K, V>,
63        optimize: &impl Fn(Option<Vec<V>>, Vec<Acc>) -> Acc,
64    ) -> Acc {
65        let children = tree
66            .children
67            .into_iter()
68            .map(|tree| optimize_tree(tree, optimize))
69            .collect::<Vec<_>>();
70
71        optimize(tree.values, children)
72    }
73
74    Ok(optimize_tree(tree, &optimize))
75}