Skip to content

Commit

Permalink
Merge e8ee3b7 into c7e797a
Browse files Browse the repository at this point in the history
  • Loading branch information
wbinnssmith committed Jul 26, 2023
2 parents c7e797a + e8ee3b7 commit bc6ccb2
Show file tree
Hide file tree
Showing 13 changed files with 378 additions and 349 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ lto = "off"
# Declare dependencies used across workspace packages requires single version bump.
# ref: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#inheriting-a-dependency-from-a-workspace
[workspace.dependencies]
async-recursion = "1.0.2"
# Keep consistent with preset_env_base through swc_core
browserslist-rs = { version = "0.12.2" }
mdxjs = { version = "0.1.14" }
Expand Down Expand Up @@ -213,6 +214,7 @@ serde_qs = "0.11.0"
serde_with = "2.3.2"
serde_yaml = "0.9.17"
sha2 = "0.10.6"
sourcemap = "6.0.2"
syn = "1.0.107"
tempfile = "3.3.0"
test-case = "3.0.0"
Expand Down
2 changes: 2 additions & 0 deletions crates/turbopack-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ indoc = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
serde_qs = { workspace = true }
sourcemap = "6.0.2"
swc_core = { workspace = true, features = ["__parser", "ecma_minifier"] }

turbo-tasks = { workspace = true }
turbo-tasks-fs = { workspace = true }
Expand Down
18 changes: 18 additions & 0 deletions crates/turbopack-build/src/chunking_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,23 @@ use crate::ecmascript::node::{
chunk::EcmascriptBuildNodeChunk, entry::chunk::EcmascriptBuildNodeEntryChunk,
};

#[turbo_tasks::value(shared)]
pub enum MinifyType {
Minify,
NoMinify,
}

/// A builder for [`Vc<BuildChunkingContext>`].
pub struct BuildChunkingContextBuilder {
context: BuildChunkingContext,
}

impl BuildChunkingContextBuilder {
pub fn minify_type(mut self, minify_type: Vc<MinifyType>) -> Self {
self.context.minify_type = minify_type;
self
}

pub fn runtime_type(mut self, runtime_type: RuntimeType) -> Self {
self.context.runtime_type = runtime_type;
self
Expand Down Expand Up @@ -63,6 +74,8 @@ pub struct BuildChunkingContext {
environment: Vc<Environment>,
/// The kind of runtime to include in the output.
runtime_type: RuntimeType,
/// Whether to minify resulting chunks
minify_type: Vc<MinifyType>,
}

impl BuildChunkingContext {
Expand All @@ -83,6 +96,7 @@ impl BuildChunkingContext {
layer: None,
environment,
runtime_type: Default::default(),
minify_type: MinifyType::Minify.cell(),
},
}
}
Expand All @@ -96,6 +110,10 @@ impl BuildChunkingContext {
pub fn runtime_type(&self) -> RuntimeType {
self.runtime_type
}

pub fn minify_type(&self) -> Vc<MinifyType> {
self.minify_type
}
}

#[turbo_tasks::value_impl]
Expand Down
16 changes: 12 additions & 4 deletions crates/turbopack-build/src/ecmascript/node/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use turbopack_ecmascript::{
};

use super::chunk::EcmascriptBuildNodeChunk;
use crate::BuildChunkingContext;
use crate::{chunking_context::MinifyType, minify::minify, BuildChunkingContext};

#[turbo_tasks::value]
pub(super) struct EcmascriptBuildNodeChunkContent {
Expand Down Expand Up @@ -47,7 +47,8 @@ impl EcmascriptBuildNodeChunkContent {
#[turbo_tasks::function]
async fn code(self: Vc<Self>) -> Result<Vc<Code>> {
let this = self.await?;
let chunk_path = this.chunk.ident().path().await?;
let chunk_path_vc = this.chunk.ident().path();
let chunk_path = chunk_path_vc.await?;

let mut code = CodeBuilder::default();

Expand Down Expand Up @@ -85,8 +86,15 @@ impl EcmascriptBuildNodeChunkContent {
write!(code, "\n\n//# sourceMappingURL={}.map", filename)?;
}

let code = code.build();
Ok(code.cell())
let code = code.build().cell();
if matches!(
&*this.chunking_context.await?.minify_type().await?,
MinifyType::Minify
) {
return Ok(minify(chunk_path_vc, code));
}

Ok(code)
}

#[turbo_tasks::function]
Expand Down
3 changes: 2 additions & 1 deletion crates/turbopack-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

pub(crate) mod chunking_context;
pub(crate) mod ecmascript;
pub(crate) mod minify;

pub use chunking_context::{BuildChunkingContext, BuildChunkingContextBuilder};
pub use chunking_context::{BuildChunkingContext, BuildChunkingContextBuilder, MinifyType};

pub fn register() {
turbo_tasks::register();
Expand Down
130 changes: 130 additions & 0 deletions crates/turbopack-build/src/minify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use std::{io::Write, sync::Arc};

use anyhow::{Context, Result};
use swc_core::{
base::{try_with_handler, Compiler},
common::{
BytePos, FileName, FilePathMapping, LineCol, Mark, SourceMap as SwcSourceMap, GLOBALS,
},
ecma::{self, ast::Program, codegen::Node},
};
use turbo_tasks::Vc;
use turbo_tasks_fs::FileSystemPath;
use turbopack_core::{
code_builder::{Code, CodeBuilder},
source_map::GenerateSourceMap,
};
use turbopack_ecmascript::ParseResultSourceMap;

#[turbo_tasks::function]
pub async fn minify(path: Vc<FileSystemPath>, code: Vc<Code>) -> Result<Vc<Code>> {
let original_map = *code.generate_source_map().await?;
let minified_code = perform_minify(path, code);

let merged = match (original_map, *minified_code.generate_source_map().await?) {
(Some(original_map), Some(minify_map)) => Some(Vc::upcast(original_map.trace(minify_map))),
_ => None,
};

let mut builder = CodeBuilder::default();
builder.push_source(minified_code.await?.source_code(), merged);
let path = &*path.await?;
let filename = path.file_name();
write!(builder, "\n\n//# sourceMappingURL={}.map", filename)?;
Ok(builder.build().cell())
}

#[turbo_tasks::function]
async fn perform_minify(path: Vc<FileSystemPath>, code_vc: Vc<Code>) -> Result<Vc<Code>> {
let code = &*code_vc.await?;
let cm = Arc::new(SwcSourceMap::new(FilePathMapping::empty()));
let compiler = Arc::new(Compiler::new(cm.clone()));
let fm = compiler.cm.new_source_file(
FileName::Custom((*path.await?.path).to_string()),
code.source_code().to_str()?.to_string(),
);

let lexer = ecma::parser::lexer::Lexer::new(
ecma::parser::Syntax::default(),
ecma::ast::EsVersion::latest(),
ecma::parser::StringInput::from(&*fm),
None,
);
let mut parser = ecma::parser::Parser::new_from(lexer);
let program = try_with_handler(cm.clone(), Default::default(), |handler| {
GLOBALS.set(&Default::default(), || {
let program = parser.parse_program().unwrap();
let unresolved_mark = Mark::new();
let top_level_mark = Mark::new();

Ok(compiler.run_transform(handler, false, || {
swc_core::ecma::minifier::optimize(
program,
cm.clone(),
None,
None,
&ecma::minifier::option::MinifyOptions {
compress: Some(Default::default()),
..Default::default()
},
&ecma::minifier::option::ExtraOptions {
top_level_mark,
unresolved_mark,
},
)
}))
})
})?;

let (src, src_map_buf) = print_program(cm.clone(), program)?;

let mut builder = CodeBuilder::default();
builder.push_source(
&src.into(),
Some(*Box::new(Vc::upcast(
ParseResultSourceMap::new(cm, src_map_buf).cell(),
))),
);

Ok(builder.build().cell())
}

// From https://github.com/swc-project/swc/blob/11efd4e7c5e8081f8af141099d3459c3534c1e1d/crates/swc/src/lib.rs#L523-L560
fn print_program(
cm: Arc<SwcSourceMap>,
program: Program,
) -> Result<(String, Vec<(BytePos, LineCol)>)> {
let mut src_map_buf = vec![];

let src = {
let mut buf = vec![];
{
let wr = Box::new(swc_core::ecma::codegen::text_writer::omit_trailing_semi(
Box::new(swc_core::ecma::codegen::text_writer::JsWriter::new(
cm.clone(),
"\n",
&mut buf,
Some(&mut src_map_buf),
)),
)) as Box<dyn swc_core::ecma::codegen::text_writer::WriteJs>;

let mut emitter = swc_core::ecma::codegen::Emitter {
cfg: swc_core::ecma::codegen::Config {
minify: true,
..Default::default()
},
comments: None,
cm: cm.clone(),
wr,
};

program
.emit_with(&mut emitter)
.context("failed to emit module")?;
}
// Invalid utf8 is valid in javascript world.
String::from_utf8(buf).expect("invalid utf8 character detected")
};

Ok((src, src_map_buf))
}
4 changes: 4 additions & 0 deletions crates/turbopack-cli/src/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,8 @@ pub struct DevArguments {
pub struct BuildArguments {
#[clap(flatten)]
pub common: CommonArguments,

/// Don't minify build output.
#[clap(long)]
pub no_minify: bool,
}
21 changes: 18 additions & 3 deletions crates/turbopack-cli/src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use turbo_tasks::{unit, TransientInstance, TryJoinIterExt, TurboTasks, Value, Vc
use turbo_tasks_fs::FileSystem;
use turbo_tasks_memory::MemoryBackend;
use turbopack::ecmascript::EcmascriptModuleAsset;
use turbopack_build::BuildChunkingContext;
use turbopack_build::{BuildChunkingContext, MinifyType};
use turbopack_cli_utils::issue::{ConsoleUi, LogOptions};
use turbopack_core::{
asset::Asset,
Expand Down Expand Up @@ -53,6 +53,7 @@ pub struct TurbopackBuildBuilder {
log_level: IssueSeverity,
show_all: bool,
log_detail: bool,
minify_type: MinifyType,
}

impl TurbopackBuildBuilder {
Expand All @@ -70,6 +71,7 @@ impl TurbopackBuildBuilder {
log_level: IssueSeverity::Warning,
show_all: false,
log_detail: false,
minify_type: MinifyType::Minify,
}
}

Expand Down Expand Up @@ -98,6 +100,11 @@ impl TurbopackBuildBuilder {
self
}

pub fn minify_type(mut self, minify_type: MinifyType) -> Self {
self.minify_type = minify_type;
self
}

pub async fn build(self) -> Result<()> {
let task = self.turbo_tasks.spawn_once_task(async move {
let build_result = build_internal(
Expand All @@ -112,6 +119,7 @@ impl TurbopackBuildBuilder {
)
.cell(),
self.browserslist_query,
self.minify_type.cell(),
);

// Await the result to propagate any errors.
Expand Down Expand Up @@ -150,6 +158,7 @@ async fn build_internal(
root_dir: String,
entry_requests: Vc<EntryRequests>,
browserslist_query: String,
minify_type: Vc<MinifyType>,
) -> Result<Vc<()>> {
let env = Environment::new(Value::new(ExecutionEnvironment::Browser(
BrowserEnvironment {
Expand Down Expand Up @@ -178,6 +187,7 @@ async fn build_internal(
build_output_root,
env,
)
.minify_type(minify_type)
.build(),
);

Expand Down Expand Up @@ -298,12 +308,17 @@ pub async fn build(args: &BuildArguments) -> Result<()> {

let mut builder = TurbopackBuildBuilder::new(tt, project_dir, root_dir)
.log_detail(args.common.log_detail)
.show_all(args.common.show_all)
.log_level(
args.common
.log_level
.map_or_else(|| IssueSeverity::Warning, |l| l.0),
);
)
.minify_type(if args.no_minify {
MinifyType::NoMinify
} else {
MinifyType::Minify
})
.show_all(args.common.show_all);

for entry in normalize_entries(&args.common.entries) {
builder = builder.entry_request(EntryRequest::Relative(entry));
Expand Down
1 change: 1 addition & 0 deletions crates/turbopack-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ bench = false

[dependencies]
anyhow = { workspace = true }
async-recursion = { workspace = true }
async-trait = { workspace = true }
auto-hash-map = { workspace = true }
browserslist-rs = { workspace = true }
Expand Down
Loading

0 comments on commit bc6ccb2

Please sign in to comment.