turbopack_ecmascript/
inlined_bytes_module.rs1use std::io::{Read, Write};
2
3use anyhow::{Result, bail};
4use turbo_rcstr::rcstr;
5use turbo_tasks::{ResolvedVc, ValueToString, Vc};
6use turbo_tasks_fs::{FileContent, glob::Glob, rope::RopeBuilder};
7use turbopack_core::{
8 asset::{Asset, AssetContent},
9 chunk::{ChunkItem, ChunkType, ChunkableModule, ChunkingContext},
10 ident::AssetIdent,
11 module::Module,
12 module_graph::ModuleGraph,
13 source::Source,
14};
15
16use crate::{
17 chunk::{
18 EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkPlaceable,
19 EcmascriptChunkType, EcmascriptExports,
20 },
21 runtime_functions::TURBOPACK_EXPORT_VALUE,
22 utils::StringifyJs,
23};
24
25#[turbo_tasks::value]
26pub struct InlinedBytesJsModule {
27 source: ResolvedVc<Box<dyn Source>>,
28}
29
30#[turbo_tasks::value_impl]
31impl InlinedBytesJsModule {
32 #[turbo_tasks::function]
33 pub fn new(source: ResolvedVc<Box<dyn Source>>) -> Vc<Self> {
34 Self::cell(InlinedBytesJsModule { source })
35 }
36}
37
38#[turbo_tasks::value_impl]
39impl Module for InlinedBytesJsModule {
40 #[turbo_tasks::function]
41 fn ident(&self) -> Vc<AssetIdent> {
42 self.source
43 .ident()
44 .with_modifier(rcstr!("static bytes in ecmascript"))
45 }
46}
47
48#[turbo_tasks::value_impl]
49impl Asset for InlinedBytesJsModule {
50 #[turbo_tasks::function]
51 fn content(&self) -> Vc<AssetContent> {
52 self.source.content()
53 }
54}
55
56#[turbo_tasks::value_impl]
57impl ChunkableModule for InlinedBytesJsModule {
58 #[turbo_tasks::function]
59 fn as_chunk_item(
60 self: ResolvedVc<Self>,
61 _module_graph: Vc<ModuleGraph>,
62 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
63 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
64 Vc::upcast(InlinedBytesJsChunkItem::cell(InlinedBytesJsChunkItem {
65 module: self,
66 chunking_context,
67 }))
68 }
69}
70
71#[turbo_tasks::value_impl]
72impl EcmascriptChunkPlaceable for InlinedBytesJsModule {
73 #[turbo_tasks::function]
74 fn get_exports(&self) -> Vc<EcmascriptExports> {
75 EcmascriptExports::Value.cell()
76 }
77
78 #[turbo_tasks::function]
79 fn is_marked_as_side_effect_free(&self, _side_effect_free_packages: Vc<Glob>) -> Vc<bool> {
80 Vc::cell(true)
81 }
82}
83
84#[turbo_tasks::value]
85struct InlinedBytesJsChunkItem {
86 module: ResolvedVc<InlinedBytesJsModule>,
87 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
88}
89
90#[turbo_tasks::value_impl]
91impl ChunkItem for InlinedBytesJsChunkItem {
92 #[turbo_tasks::function]
93 fn asset_ident(&self) -> Vc<AssetIdent> {
94 self.module.ident()
95 }
96
97 #[turbo_tasks::function]
98 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
99 *self.chunking_context
100 }
101
102 #[turbo_tasks::function]
103 async fn ty(&self) -> Result<Vc<Box<dyn ChunkType>>> {
104 Ok(Vc::upcast(
105 Vc::<EcmascriptChunkType>::default().resolve().await?,
106 ))
107 }
108
109 #[turbo_tasks::function]
110 fn module(&self) -> Vc<Box<dyn Module>> {
111 Vc::upcast(*self.module)
112 }
113}
114
115#[turbo_tasks::value_impl]
116impl EcmascriptChunkItem for InlinedBytesJsChunkItem {
117 #[turbo_tasks::function]
118 async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
119 let content = self.module.content().file_content().await?;
120 match &*content {
121 FileContent::Content(data) => {
122 let mut inner_code = RopeBuilder::default();
123 inner_code += "
124var decode = Uint8Array.fromBase64 || function Uint8Array_fromBase64(base64) {
125 var binaryString = atob(base64);
126 var buffer = new Uint8Array(binaryString.length);
127 for (var i = 0; i < binaryString.length; i++) {
128 buffer[i] = binaryString.charCodeAt(i)
129 }
130 return buffer
131};\n";
132
133 let encoded = data_encoding::BASE64_NOPAD
134 .encode(&data.read().bytes().collect::<std::io::Result<Vec<u8>>>()?);
135 write!(
136 inner_code,
137 "{TURBOPACK_EXPORT_VALUE}(decode({}));",
138 StringifyJs(&encoded)
139 )?;
140
141 Ok(EcmascriptChunkItemContent {
142 inner_code: inner_code.build(),
143 ..Default::default()
144 }
145 .into())
146 }
147 FileContent::NotFound => {
148 bail!("File not found: {}", self.module.ident().to_string().await?);
149 }
150 }
151 }
152}