Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/ci.generated.yml
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ jobs:
run: ./tools/install_prebuilt.js wrk hyperfine
- name: Build deno
if: '(contains(github.event.pull_request.labels.*.name, ''ci-bench'') || github.ref == ''refs/heads/main'') && !startsWith(github.ref, ''refs/tags/'')'
env:
DENO_SNAPSHOT_MINIFY_SOURCES: '1'
run: cargo build --release -p deno
- name: Run benchmarks
if: '(contains(github.event.pull_request.labels.*.name, ''ci-bench'') || github.ref == ''refs/heads/main'') && !startsWith(github.ref, ''refs/tags/'')'
Expand Down Expand Up @@ -759,6 +761,8 @@ jobs:
run: echo "DENO_CANARY=true" >> $GITHUB_ENV
- name: Build release
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'') && github.repository == ''denoland/deno'''
env:
DENO_SNAPSHOT_MINIFY_SOURCES: '1'
run: |-
df -h
cargo build --release --locked -p deno -p denort -p test_server --bin deno --bin denort --bin test_server --features=deno/panic-trace
Expand Down Expand Up @@ -1766,6 +1770,8 @@ jobs:
run: echo "DENO_CANARY=true" >> $GITHUB_ENV
- name: Build release
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'') && github.repository == ''denoland/deno'''
env:
DENO_SNAPSHOT_MINIFY_SOURCES: '1'
run: |-
df -h
cargo build --release --locked -p deno -p denort -p test_server --bin deno --bin denort --bin test_server --features=deno/panic-trace
Expand Down Expand Up @@ -2627,6 +2633,11 @@ jobs:
- name: Clone submodule ./tests/util/std
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'')'
run: git submodule update --init --recursive --depth=1 -- ./tests/util/std
- name: Install Deno
uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'') && github.repository == ''denoland/deno'''
with:
deno-version: v2.x
- name: Restore cache cargo home
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'') && !startsWith(github.ref, ''refs/tags/'')'
Expand Down Expand Up @@ -2703,6 +2714,8 @@ jobs:
run: echo "DENO_CANARY=true" >> $GITHUB_ENV
- name: Build release
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'') && github.repository == ''denoland/deno'''
env:
DENO_SNAPSHOT_MINIFY_SOURCES: '1'
run: |-
df -h
cargo build --release --locked -p deno -p denort -p test_server --bin deno --bin denort --bin test_server --features=deno/panic-trace
Expand Down Expand Up @@ -3447,6 +3460,11 @@ jobs:
- name: Clone submodule ./tests/util/std
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'')'
run: git submodule update --init --recursive --depth=1 -- ./tests/util/std
- name: Install Deno
uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'') && github.repository == ''denoland/deno'''
with:
deno-version: v2.x
- name: Restore cache cargo home
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'') && !startsWith(github.ref, ''refs/tags/'')'
Expand Down Expand Up @@ -3523,6 +3541,8 @@ jobs:
run: echo "DENO_CANARY=true" >> $GITHUB_ENV
- name: Build release
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'') && github.repository == ''denoland/deno'''
env:
DENO_SNAPSHOT_MINIFY_SOURCES: '1'
run: |-
df -h
cargo build --release --locked -p deno -p denort -p test_server --bin deno --bin denort --bin test_server --features=deno/panic-trace
Expand Down Expand Up @@ -3919,6 +3939,10 @@ jobs:
mkdir -p target/release
tar --exclude=".git*" --exclude=target --exclude=third_party/prebuilt \
-czvf target/release/deno_src.tar.gz -C .. deno
- name: Install Deno
uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282
with:
deno-version: v2.x
- name: Restore cache cargo home
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830
if: '!startsWith(github.ref, ''refs/tags/'')'
Expand Down Expand Up @@ -4085,6 +4109,8 @@ jobs:
if: '!startsWith(github.ref, ''refs/tags/'')'
run: echo "DENO_CANARY=true" >> $GITHUB_ENV
- name: Build release
env:
DENO_SNAPSHOT_MINIFY_SOURCES: '1'
run: |-
df -h
cargo build --release --locked -p deno -p denort -p test_server --bin deno --bin denort --bin test_server --features=deno/panic-trace
Expand Down Expand Up @@ -5862,6 +5888,11 @@ jobs:
- name: Clone submodule ./tests/util/std
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'')'
run: git submodule update --init --recursive --depth=1 -- ./tests/util/std
- name: Install Deno
uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'')'
with:
deno-version: v2.x
- name: Restore cache cargo home
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'') && !startsWith(github.ref, ''refs/tags/'')'
Expand Down Expand Up @@ -6034,6 +6065,8 @@ jobs:
run: echo "DENO_CANARY=true" >> $GITHUB_ENV
- name: Build release
if: '!(!contains(github.event.pull_request.labels.*.name, ''ci-full'') && github.event_name == ''pull_request'')'
env:
DENO_SNAPSHOT_MINIFY_SOURCES: '1'
run: |-
df -h
cargo build --release --locked -p deno -p denort -p test_server --bin deno --bin denort --bin test_server --features=deno/panic-trace
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/ci.ts
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,7 @@ const buildJobs = buildItems.map((rawBuildItem) => {
)
.dependsOn(
installLldStep,
installDenoStep,
restoreCacheStep,
installRustStep,
sysRootStep,
Expand All @@ -886,6 +887,9 @@ const buildJobs = buildItems.map((rawBuildItem) => {
},
{
name: "Build release",
env: {
DENO_SNAPSHOT_MINIFY_SOURCES: "1",
},
run: [
// output fs space before and after building
"df -h",
Expand Down Expand Up @@ -1474,6 +1478,9 @@ const benchJob = job(
// we could optimize this to not need this.
{
name: "Build deno",
env: {
DENO_SNAPSHOT_MINIFY_SOURCES: "1",
},
run: "cargo build --release -p deno",
},
{
Expand Down
17 changes: 13 additions & 4 deletions cli/snapshot/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ fn main() {
#[allow(clippy::print_stdout, reason = "build script output")]
{
println!("cargo:rerun-if-env-changed=DENO_SNAPSHOT_IMPORT_GRAPH");
println!("cargo:rerun-if-env-changed=DENO_SNAPSHOT_MINIFY_SOURCES");
}
#[cfg(not(feature = "disable"))]
{
Expand Down Expand Up @@ -51,6 +52,8 @@ fn create_cli_snapshot(
let out_dir = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap());
let residual_sources_dir = out_dir.join("residual_sources");
std::fs::create_dir_all(&residual_sources_dir).unwrap();
let minify_sources =
std::env::var_os("DENO_SNAPSHOT_MINIFY_SOURCES").is_some();

let mut residual_js: Vec<(&str, std::path::PathBuf)> = Vec::new();
let mut residual_esm: Vec<(&str, std::path::PathBuf)> = Vec::new();
Expand All @@ -73,6 +76,7 @@ fn create_cli_snapshot(
&residual_sources_dir,
&file.specifier,
&file.path,
minify_sources,
);
match file.kind {
LazyExtensionFileKind::Js => {
Expand Down Expand Up @@ -109,9 +113,11 @@ fn transpile_residual_source(
out_dir: &std::path::Path,
specifier: &str,
src_path: &std::path::Path,
minify: bool,
) -> std::path::PathBuf {
use deno_runtime::deno_core::ModuleCodeString;
use deno_runtime::deno_core::ModuleName;
use deno_runtime::transpile::maybe_transpile_and_minify_source;
use deno_runtime::transpile::maybe_transpile_source;

let source = std::fs::read_to_string(src_path).unwrap_or_else(|e| {
Expand All @@ -120,10 +126,13 @@ fn transpile_residual_source(
src_path.display()
)
});
let (transpiled, _source_map) = maybe_transpile_source(
ModuleName::from(specifier.to_string()),
ModuleCodeString::from(source),
)
let name = ModuleName::from(specifier.to_string());
let source = ModuleCodeString::from(source);
let (transpiled, _source_map) = if minify {
maybe_transpile_and_minify_source(name, source)
} else {
maybe_transpile_source(name, source)
}
.unwrap_or_else(|e| {
panic!("failed to transpile residual lazy source {specifier}: {e}")
});
Expand Down
10 changes: 8 additions & 2 deletions runtime/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,20 @@ pub fn create_runtime_snapshot(
extensions.extend(custom_extensions);

let lazy_extension_files = collect_lazy_extension_files(&extensions);
let minify_sources =
std::env::var_os("DENO_SNAPSHOT_MINIFY_SOURCES").is_some();

let output = create_snapshot(
CreateSnapshotOptions {
cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
startup_snapshot: None,
extensions,
extension_transpiler: Some(Rc::new(|specifier, source| {
crate::transpile::maybe_transpile_source(specifier, source)
extension_transpiler: Some(Rc::new(move |specifier, source| {
if minify_sources {
crate::transpile::maybe_transpile_and_minify_source(specifier, source)
} else {
crate::transpile::maybe_transpile_source(specifier, source)
}
})),
with_runtime_cb: Some(Box::new(|rt| {
let isolate = rt.v8_isolate();
Expand Down
136 changes: 133 additions & 3 deletions runtime/transpile.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2018-2026 the Deno authors. MIT license.

use std::io::Write;
use std::path::Path;
use std::sync::OnceLock;

use deno_ast::MediaType;
use deno_ast::ParseParams;
Expand All @@ -25,6 +27,22 @@ pub fn maybe_transpile_source(
name: ModuleName,
source: ModuleCodeString,
) -> Result<(ModuleCodeString, Option<SourceMapData>), JsErrorBox> {
maybe_transpile_source_inner(name, source, false)
}

pub fn maybe_transpile_and_minify_source(
name: ModuleName,
source: ModuleCodeString,
) -> Result<(ModuleCodeString, Option<SourceMapData>), JsErrorBox> {
maybe_transpile_source_inner(name, source, true)
}

fn maybe_transpile_source_inner(
name: ModuleName,
source: ModuleCodeString,
minify: bool,
) -> Result<(ModuleCodeString, Option<SourceMapData>), JsErrorBox> {
let name_string = name.to_string();
// Always transpile `node:` built-in modules, since they might be TypeScript.
let media_type = if name.starts_with("node:") {
MediaType::TypeScript
Expand All @@ -34,8 +52,14 @@ pub fn maybe_transpile_source(

match media_type {
MediaType::TypeScript => {}
MediaType::JavaScript => return Ok((source, None)),
MediaType::Mjs => return Ok((source, None)),
MediaType::JavaScript | MediaType::Mjs => {
if minify {
let source =
minify_source_with_rolldown(&name_string, source.as_ref())?;
return Ok((source.into(), None));
}
return Ok((source, None));
}
_ => panic!(
"Unsupported media type for snapshotting {media_type:?} for file {}",
name
Expand Down Expand Up @@ -74,5 +98,111 @@ pub fn maybe_transpile_source(
.source_map
.map(|sm| sm.into_bytes().into());
let source_text = transpiled_source.text;
Ok((source_text.into(), maybe_source_map))
if minify {
let source_text = minify_source_with_rolldown(&name_string, &source_text)?;
Ok((source_text.into(), None))
} else {
Ok((source_text.into(), maybe_source_map))
}
}

#[allow(
clippy::disallowed_methods,
reason = "snapshot source minification runs at build time"
)]
fn minify_source_with_rolldown(
specifier: &str,
source: &str,
) -> Result<String, JsErrorBox> {
static MINIFIER_PATH: OnceLock<std::path::PathBuf> = OnceLock::new();
let minifier_path = MINIFIER_PATH.get_or_init(|| {
let path =
std::env::temp_dir().join("deno_snapshot_rolldown_minify_source.js");
std::fs::write(
&path,
r#"import { minifySync } from "npm:rolldown/experimental";

const filename = Deno.args[0] ?? "source.js";
const source = await new Response(Deno.stdin.readable).text();
const result = minifySync(filename, source, {
compress: false,
mangle: false,
codegen: {
removeWhitespace: true,
legalComments: "none",
},
});
if (result.errors?.length) {
console.error(JSON.stringify(result.errors, null, 2));
Deno.exit(1);
}
function escapeNonAscii(code) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this even reachable? I thought we have a check that ensures everything is ascii

let out = "";
for (let i = 0; i < code.length; i++) {
const unit = code.charCodeAt(i);
if (unit <= 0x7f) {
out += code[i];
} else {
out += "\\u" + unit.toString(16).padStart(4, "0");
}
}
return out;
}
const output = new TextEncoder().encode(escapeNonAscii(result.code));
let offset = 0;
while (offset < output.length) {
offset += await Deno.stdout.write(output.subarray(offset));
}
"#,
)
.unwrap();
path
});

let mut child = std::process::Command::new("deno")
.arg("run")
.arg("-A")
.arg(minifier_path)
.arg(specifier)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.map_err(|e| {
JsErrorBox::generic(format!(
"failed to run rolldown source minifier for {specifier}: {e}"
))
})?;
child
.stdin
.as_mut()
.unwrap()
.write_all(source.as_bytes())
.map_err(|e| {
JsErrorBox::generic(format!(
"failed to write source to rolldown minifier for {specifier}: {e}"
))
})?;
let output = child.wait_with_output().map_err(|e| {
JsErrorBox::generic(format!(
"failed to wait for rolldown source minifier for {specifier}: {e}"
))
})?;
if !output.status.success() {
return Err(JsErrorBox::generic(format!(
"failed to minify source {specifier}\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
)));
}
let output = String::from_utf8(output.stdout).map_err(|e| {
JsErrorBox::generic(format!(
"rolldown minifier produced non-utf8 output for {specifier}: {e}"
))
})?;
assert!(
output.is_ascii(),
"rolldown minifier produced non-ascii output for {specifier}"
);
Ok(output)
}
Loading