turbopack_ecmascript/manifest/
chunk_item.rs

1use anyhow::Result;
2use indoc::formatdoc;
3use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc};
4use turbopack_core::{
5    chunk::{ChunkData, ChunkItem, ChunkType, ChunkingContext, ChunksData},
6    ident::AssetIdent,
7    module::Module,
8    output::OutputAssets,
9};
10
11use super::chunk_asset::ManifestAsyncModule;
12use crate::{
13    chunk::{
14        EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkType,
15        data::EcmascriptChunkData,
16    },
17    runtime_functions::TURBOPACK_EXPORT_VALUE,
18    utils::StringifyJs,
19};
20
21/// The ManifestChunkItem generates a __turbopack_load__ call for every chunk
22/// necessary to load the real asset. Once all the loads resolve, it is safe to
23/// __turbopack_import__ the actual module that was dynamically imported.
24#[turbo_tasks::value(shared)]
25pub(super) struct ManifestChunkItem {
26    pub chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
27    pub manifest: ResolvedVc<ManifestAsyncModule>,
28}
29
30#[turbo_tasks::value_impl]
31impl ManifestChunkItem {
32    #[turbo_tasks::function]
33    async fn chunks_data(&self) -> Result<Vc<ChunksData>> {
34        Ok(ChunkData::from_assets(
35            self.chunking_context.output_root().owned().await?,
36            self.manifest.chunks(),
37        ))
38    }
39}
40
41#[turbo_tasks::value_impl]
42impl EcmascriptChunkItem for ManifestChunkItem {
43    #[turbo_tasks::function]
44    async fn content(self: Vc<Self>) -> Result<Vc<EcmascriptChunkItemContent>> {
45        let chunks_data = self.chunks_data().await?;
46        let chunks_data = chunks_data.iter().try_join().await?;
47        let chunks_data: Vec<_> = chunks_data
48            .iter()
49            .map(|chunk_data| EcmascriptChunkData::new(chunk_data))
50            .collect();
51
52        let code = formatdoc! {
53            r#"
54                {TURBOPACK_EXPORT_VALUE}({:#});
55            "#,
56            StringifyJs(&chunks_data)
57        };
58
59        Ok(EcmascriptChunkItemContent {
60            inner_code: code.into(),
61            ..Default::default()
62        }
63        .into())
64    }
65}
66
67#[turbo_tasks::value_impl]
68impl ChunkItem for ManifestChunkItem {
69    #[turbo_tasks::function]
70    fn asset_ident(&self) -> Vc<AssetIdent> {
71        self.manifest.ident()
72    }
73
74    #[turbo_tasks::function]
75    fn content_ident(&self) -> Vc<AssetIdent> {
76        self.manifest.content_ident()
77    }
78
79    #[turbo_tasks::function]
80    async fn references(self: Vc<Self>) -> Result<Vc<OutputAssets>> {
81        let mut references = vec![];
82        for chunk_data in &*self.chunks_data().await? {
83            references.extend(chunk_data.references().await?.iter());
84        }
85
86        Ok(Vc::cell(references))
87    }
88
89    #[turbo_tasks::function]
90    fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
91        *ResolvedVc::upcast(self.chunking_context)
92    }
93
94    #[turbo_tasks::function]
95    async fn ty(&self) -> Result<Vc<Box<dyn ChunkType>>> {
96        Ok(Vc::upcast(
97            Vc::<EcmascriptChunkType>::default().resolve().await?,
98        ))
99    }
100
101    #[turbo_tasks::function]
102    fn module(&self) -> Vc<Box<dyn Module>> {
103        *ResolvedVc::upcast(self.manifest)
104    }
105}