Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gzip compression for "deno compile" #1

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
feat: deno compile
  • Loading branch information
lucacasonato committed Nov 29, 2020
commit f42505215d9669735bba7c58975b54a72cfe1f08
4 changes: 3 additions & 1 deletion cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ mod resolve_addr;
mod signal;
mod source_maps;
mod specifier_handler;
mod standalone;
mod text_encoding;
mod tokio_util;
mod tools;
Expand Down Expand Up @@ -967,8 +968,9 @@ pub fn main() {
colors::enable_ansi(); // For Windows 10

let args: Vec<String> = env::args().collect();
let flags = flags::flags_from_vec(args);
standalone::standalone();

let flags = flags::flags_from_vec(args);
if let Some(ref v8_flags) = flags.v8_flags {
init_v8_flags(v8_flags);
}
Expand Down
123 changes: 123 additions & 0 deletions cli/standalone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use std::cell::RefCell;
use std::convert::TryInto;
use std::env::current_exe;
use std::fs::File;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom;
use std::pin::Pin;
use std::rc::Rc;

use deno_core::error::AnyError;
use deno_core::futures::FutureExt;
use deno_core::ModuleLoader;
use deno_core::ModuleSpecifier;
use deno_core::OpState;

use crate::colors;
use crate::flags::Flags;
use crate::permissions::Permissions;
use crate::program_state::ProgramState;
use crate::tokio_util;
use crate::worker::MainWorker;

pub fn standalone() {
let current_exe_path =
current_exe().expect("expect current exe path to be known");

let mut current_exe = File::open(current_exe_path)
.expect("expected to be able to open current exe");
let magic_trailer_pos = current_exe
.seek(SeekFrom::End(-12))
.expect("expected to be able to seek to magic trailer in current exe");
let mut magic_trailer = [0; 12];
current_exe
.read_exact(&mut magic_trailer)
.expect("expected to be able to read magic trailer from current exe");
let (magic_trailer, bundle_pos) = magic_trailer.split_at(4);
if magic_trailer == b"DENO" {
let bundle_pos_arr: &[u8; 8] =
bundle_pos.try_into().expect("slice with incorrect length");
let bundle_pos = u64::from_be_bytes(*bundle_pos_arr);
println!(
"standalone bin! bundle starting at {} and ending at {}.",
bundle_pos,
magic_trailer_pos - 1
);
current_exe
.seek(SeekFrom::Start(bundle_pos))
.expect("expected to be able to seek to bundle pos in current exe");

let bundle_len = magic_trailer_pos - bundle_pos;
let mut bundle = String::new();
current_exe
.take(bundle_len)
.read_to_string(&mut bundle)
.expect("expected to be able to read bundle from current exe");
// TODO: check amount of bytes read

// println!("standalone bin bundle:\n{}", bundle);

let result = tokio_util::run_basic(run(bundle));
if let Err(err) = result {
eprintln!("{}: {}", colors::red_bold("error"), err.to_string());
std::process::exit(1);
}
std::process::exit(0);
}
}

const SPECIFIER: &str = "file:https://$deno$/bundle.js";

struct EmbeddedModuleLoader(String);

impl ModuleLoader for EmbeddedModuleLoader {
fn resolve(
&self,
_op_state: Rc<RefCell<OpState>>,
specifier: &str,
_referrer: &str,
_is_main: bool,
) -> Result<ModuleSpecifier, AnyError> {
assert_eq!(specifier, SPECIFIER);
Ok(ModuleSpecifier::resolve_url(specifier)?)
}

fn load(
&self,
_op_state: Rc<RefCell<OpState>>,
module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<ModuleSpecifier>,
_is_dynamic: bool,
) -> Pin<Box<deno_core::ModuleSourceFuture>> {
let module_specifier = module_specifier.clone();
let code = self.0.to_string();
async move {
Ok(deno_core::ModuleSource {
code,
module_url_specified: module_specifier.to_string(),
module_url_found: module_specifier.to_string(),
})
}
.boxed_local()
}
}

async fn run(source_code: String) -> Result<(), AnyError> {
let flags = Flags::default();
let main_module = ModuleSpecifier::resolve_url(SPECIFIER)?;
let program_state = ProgramState::new(flags.clone())?;
let permissions = Permissions::allow_all();
let module_loader = Rc::new(EmbeddedModuleLoader(source_code));
let mut worker = MainWorker::from_options(
&program_state,
main_module.clone(),
permissions,
module_loader,
);
worker.execute_module(&main_module).await?;
worker.execute("window.dispatchEvent(new Event('load'))")?;
worker.run_event_loop().await?;
worker.execute("window.dispatchEvent(new Event('unload'))")?;
Ok(())
}
12 changes: 12 additions & 0 deletions cli/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ use deno_core::futures::future::FutureExt;
use deno_core::url::Url;
use deno_core::JsRuntime;
use deno_core::ModuleId;
use deno_core::ModuleLoader;
use deno_core::ModuleSpecifier;
use deno_core::RuntimeOptions;
use std::env;
use std::rc::Rc;
use std::sync::Arc;
use std::task::Context;
use std::task::Poll;
Expand All @@ -45,6 +47,16 @@ impl MainWorker {
) -> Self {
let module_loader =
CliModuleLoader::new(program_state.maybe_import_map.clone());

Self::from_options(program_state, main_module, permissions, module_loader)
}

pub fn from_options(
program_state: &Arc<ProgramState>,
main_module: ModuleSpecifier,
permissions: Permissions,
module_loader: Rc<dyn ModuleLoader>,
) -> Self {
let global_state_ = program_state.clone();

let js_error_create_fn = Box::new(move |core_js_error| {
Expand Down
26 changes: 26 additions & 0 deletions compile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const specifier = Deno.args[0];
const out = Deno.args[1];
const [_, bundle] = await Deno.bundle(specifier);

const originalBinaryPath = Deno.execPath();
const originalBin = await Deno.readFile(originalBinaryPath);

const encoder = new TextEncoder();
const bundleData = encoder.encode(bundle);
const magicTrailer = new Uint8Array(12);
magicTrailer.set(encoder.encode("DENO"), 0);
new DataView(magicTrailer.buffer).setBigUint64(
4,
BigInt(originalBin.byteLength),
false,
);

var newBin = new Uint8Array(
originalBin.byteLength + bundleData.byteLength + magicTrailer.byteLength,
);
newBin.set(originalBin, 0);
newBin.set(bundleData, originalBin.byteLength);
newBin.set(magicTrailer, originalBin.byteLength + bundleData.byteLength);

await Deno.writeFile(out, newBin);
console.log(`Created binary at ${out}`);