Skip to main content

turbopack_ecmascript/
text_source_transform.rs

1use anyhow::{Result, bail};
2use turbo_tasks::Vc;
3use turbo_tasks_fs::{File, FileContent};
4use turbopack_core::{
5    asset::{Asset, AssetContent},
6    context::AssetContext,
7    source::Source,
8    source_transform::SourceTransform,
9    virtual_source::VirtualSource,
10};
11
12use crate::utils::{StringifyJs, inline_source_map_comment};
13
14/// A source transform that converts any file into an ES module that exports
15/// the file's content as a default string export.
16///
17/// This is used for `import text from './file.txt' with { type: 'text' }`.
18#[turbo_tasks::value]
19pub struct TextSourceTransform;
20
21#[turbo_tasks::value_impl]
22impl TextSourceTransform {
23    #[turbo_tasks::function]
24    pub fn new() -> Vc<Self> {
25        TextSourceTransform.cell()
26    }
27}
28
29#[turbo_tasks::value_impl]
30impl SourceTransform for TextSourceTransform {
31    #[turbo_tasks::function]
32    async fn transform(
33        self: Vc<Self>,
34        source: Vc<Box<dyn Source>>,
35        _asset_context: Vc<Box<dyn AssetContext>>,
36    ) -> Result<Vc<Box<dyn Source>>> {
37        let ident = source.ident();
38        let path = ident.path().await?;
39        let content = source.content().file_content().await?;
40        let text = match &*content {
41            FileContent::Content(data) => data.content().to_str()?,
42            FileContent::NotFound => {
43                // This shouldn't happen because the import was already resolved
44                bail!("File not found: {:?}", path);
45            }
46        };
47
48        // Generate ES module with inline source map pointing back to the original file.
49        let code = format!(
50            "\"use turbopack no side effects\";\nexport default {};\n{}",
51            StringifyJs(&text),
52            inline_source_map_comment(&path.path, &text)
53        );
54
55        // Rename to .mjs so module rules recognize it as ESM.
56        // The inline source map ensures debuggers show the original file.
57        let new_ident = ident.rename_as(format!("{}.[text].mjs", path.path).into());
58
59        Ok(Vc::upcast(VirtualSource::new_with_ident(
60            new_ident,
61            AssetContent::file(FileContent::Content(File::from(code)).cell()),
62        )))
63    }
64}