diff --git a/turbopack/crates/turbo-tasks-fs/src/rope.rs b/turbopack/crates/turbo-tasks-fs/src/rope.rs index 09583a15bffcd..1aa6cc3171ff0 100644 --- a/turbopack/crates/turbo-tasks-fs/src/rope.rs +++ b/turbopack/crates/turbo-tasks-fs/src/rope.rs @@ -18,7 +18,6 @@ use serde_bytes::ByteBuf; use tokio::io::{AsyncRead, ReadBuf}; use triomphe::Arc; use turbo_tasks_hash::{DeterministicHash, DeterministicHasher}; -use unsize::{CoerceUnsize, Coercion}; static EMPTY_BUF: &[u8] = &[]; @@ -42,7 +41,7 @@ pub struct Rope { /// An Arc container for ropes. This indirection allows for easily sharing the /// contents between Ropes (and also RopeBuilders/RopeReaders). #[derive(Clone, Debug)] -struct InnerRope(Arc<[RopeElem]>); +struct InnerRope(Arc>); /// Differentiates the types of stored bytes in a rope. #[derive(Clone, Debug)] @@ -117,6 +116,10 @@ impl Rope { pub fn to_bytes(&self) -> Cow<'_, [u8]> { self.data.to_bytes(self.length) } + + pub fn into_bytes(self) -> Bytes { + self.data.into_bytes(self.length) + } } impl From> for Rope { @@ -142,7 +145,7 @@ impl> From for Rope { } else { Rope { length: bytes.len(), - data: InnerRope(Arc::from([Local(bytes)]).unsize(Coercion::to_slice())), + data: InnerRope(Arc::from(vec![Local(bytes)])), } } } @@ -536,11 +539,33 @@ impl InnerRope { } } } + + fn into_bytes(mut self, len: usize) -> Bytes { + if self.0.is_empty() { + return Bytes::default(); + } else if self.0.len() == 1 { + let data = Arc::try_unwrap(self.0); + match data { + Ok(data) => { + return data.into_iter().next().unwrap().into_bytes(len); + } + Err(data) => { + self.0 = data; + } + } + } + + let mut read = RopeReader::new(&self, 0); + let mut buf = Vec::with_capacity(len); + read.read_to_end(&mut buf) + .expect("read of rope cannot fail"); + buf.into() + } } impl Default for InnerRope { fn default() -> Self { - InnerRope(Arc::new([]).unsize(Coercion::to_slice())) + InnerRope(Arc::new(vec![])) } } @@ -579,7 +604,7 @@ impl From> for InnerRope { } impl Deref for InnerRope { - type Target = Arc<[RopeElem]>; + type Target = Arc>; fn deref(&self) -> &Self::Target { &self.0 @@ -610,6 +635,13 @@ impl RopeElem { _ => None, } } + + fn into_bytes(self, len: usize) -> Bytes { + match self { + Local(bytes) => bytes, + Shared(inner) => inner.into_bytes(len), + } + } } impl DeterministicHash for RopeElem { diff --git a/turbopack/crates/turbopack-browser/src/ecmascript/content.rs b/turbopack/crates/turbopack-browser/src/ecmascript/content.rs index d970d1eaf17df..70c1f7a6647f6 100644 --- a/turbopack/crates/turbopack-browser/src/ecmascript/content.rs +++ b/turbopack/crates/turbopack-browser/src/ecmascript/content.rs @@ -128,7 +128,7 @@ impl EcmascriptBrowserChunkContent { let mut code = code.build(); if let MinifyType::Minify { mangle } = this.chunking_context.await?.minify_type() { - code = minify(&code, source_maps, mangle)?; + code = minify(code, source_maps, mangle)?; } Ok(code.cell()) diff --git a/turbopack/crates/turbopack-browser/src/ecmascript/evaluate/chunk.rs b/turbopack/crates/turbopack-browser/src/ecmascript/evaluate/chunk.rs index 241bac72b2a39..67b403defce4c 100644 --- a/turbopack/crates/turbopack-browser/src/ecmascript/evaluate/chunk.rs +++ b/turbopack/crates/turbopack-browser/src/ecmascript/evaluate/chunk.rs @@ -194,7 +194,7 @@ impl EcmascriptBrowserEvaluateChunk { let mut code = code.build(); if let MinifyType::Minify { mangle } = this.chunking_context.await?.minify_type() { - code = minify(&code, source_maps, mangle)?; + code = minify(code, source_maps, mangle)?; } Ok(code.cell()) diff --git a/turbopack/crates/turbopack-core/src/code_builder.rs b/turbopack/crates/turbopack-core/src/code_builder.rs index 92504dd214ded..693d84a7af3db 100644 --- a/turbopack/crates/turbopack-core/src/code_builder.rs +++ b/turbopack/crates/turbopack-core/src/code_builder.rs @@ -34,6 +34,11 @@ impl Code { pub fn has_source_map(&self) -> bool { !self.mappings.is_empty() } + + /// Take the source code out of the Code. + pub fn into_source_code(self) -> Rope { + self.code + } } /// CodeBuilder provides a mutable container to append source code. diff --git a/turbopack/crates/turbopack-ecmascript/src/minify.rs b/turbopack/crates/turbopack-ecmascript/src/minify.rs index a7e85af651ba1..365f35c0f4b61 100644 --- a/turbopack/crates/turbopack-ecmascript/src/minify.rs +++ b/turbopack/crates/turbopack-ecmascript/src/minify.rs @@ -31,17 +31,17 @@ use turbopack_core::{ use crate::parse::generate_js_source_map; #[instrument(level = Level::INFO, skip_all)] -pub fn minify(code: &Code, source_maps: bool, mangle: Option) -> Result { +pub fn minify(code: Code, source_maps: bool, mangle: Option) -> Result { let source_maps = source_maps .then(|| code.generate_source_map_ref()) .transpose()?; + let source_code = code.into_source_code().into_bytes().into(); + let source_code = String::from_utf8(source_code)?; + let cm = Arc::new(SwcSourceMap::new(FilePathMapping::empty())); let (src, mut src_map_buf) = { - let fm = cm.new_source_file( - FileName::Anon.into(), - code.source_code().to_str()?.into_owned(), - ); + let fm = cm.new_source_file(FileName::Anon.into(), source_code); let lexer = Lexer::new( Syntax::default(), @@ -57,10 +57,7 @@ pub fn minify(code: &Code, source_maps: bool, mangle: Option) -> Res Ok(program) => program, Err(err) => { err.into_diagnostic(handler).emit(); - bail!( - "failed to parse source code\n{}", - code.source_code().to_str()? - ) + bail!("failed to parse source code\n{}", fm.src) } }; let comments = SingleThreadedComments::default(); diff --git a/turbopack/crates/turbopack-nodejs/src/ecmascript/node/content.rs b/turbopack/crates/turbopack-nodejs/src/ecmascript/node/content.rs index 1c38092470959..079f9ba6bcc0a 100644 --- a/turbopack/crates/turbopack-nodejs/src/ecmascript/node/content.rs +++ b/turbopack/crates/turbopack-nodejs/src/ecmascript/node/content.rs @@ -78,7 +78,7 @@ impl EcmascriptBuildNodeChunkContent { let mut code = code.build(); if let MinifyType::Minify { mangle } = this.chunking_context.await?.minify_type() { - code = minify(&code, source_maps, mangle)?; + code = minify(code, source_maps, mangle)?; } Ok(code.cell())