diff --git a/Cargo.lock b/Cargo.lock index 170272e9fc..113529785f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -308,6 +308,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +dependencies = [ + "generic-array", +] + [[package]] name = "block-modes" version = "0.8.1" @@ -469,15 +478,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "cloudabi" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" -dependencies = [ - "bitflags", -] - [[package]] name = "codespan-reporting" version = "0.11.1" @@ -593,6 +593,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-common" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" +dependencies = [ + "generic-array", +] + [[package]] name = "crypto-mac" version = "0.11.1" @@ -743,6 +752,7 @@ dependencies = [ "dprint-plugin-typescript", "encoding_rs", "env_logger", + "eszip", "fancy-regex", "flaky_test", "fwdansi", @@ -874,7 +884,7 @@ dependencies = [ "serde", "serde_bytes", "sha-1", - "sha2", + "sha2 0.9.9", "spki", "tokio", "uuid", @@ -882,9 +892,9 @@ dependencies = [ [[package]] name = "deno_doc" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51c8f938ff0c4a759e89a1c7194415597d01eae0c469d106d1784cbdb977415e" +checksum = "c7e2982f488761ef90a31d3d2a873cb05bf6342ffba9d8fbf94b95a6366fa463" dependencies = [ "cfg-if 1.0.0", "deno_ast", @@ -928,9 +938,9 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabd84b8d6294fa8174be6501d11893e1791149f4e33c34f036cef0c2387d5d5" +checksum = "b3108bfa75e0f439f83ac8540d8e494b7d3c8a782db805d126e3a3125d84a38b" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -1163,6 +1173,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" +dependencies = [ + "block-buffer 0.10.0", + "crypto-common", + "generic-array", +] + [[package]] name = "dissimilar" version = "1.0.2" @@ -1232,14 +1253,13 @@ dependencies = [ [[package]] name = "dprint-plugin-typescript" -version = "0.62.2" +version = "0.64.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a2040b94cdda1fa059abc54e41101a7f77ee0fd16e55213f7f44e7e46f9278" +checksum = "1f37bdb4c73ee3ed24e2630958bf1c9996799113ebb59359eea2c7827d867031" dependencies = [ "anyhow", "deno_ast", "dprint-core", - "parking_lot_core", "rustc-hash", "serde", ] @@ -1372,6 +1392,25 @@ dependencies = [ "str-buf", ] +[[package]] +name = "eszip" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eafe3b52142cad5f998f607b95fdc543f98b0425ebf9fd5fa1475cfc1e9c743" +dependencies = [ + "anyhow", + "base64 0.13.0", + "deno_ast", + "deno_graph", + "futures", + "serde", + "serde_json", + "sha2 0.10.1", + "thiserror", + "tokio", + "url", +] + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -1423,7 +1462,7 @@ checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "winapi 0.3.9", ] @@ -1809,7 +1848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ "crypto-mac", - "digest", + "digest 0.9.0", ] [[package]] @@ -2598,7 +2637,7 @@ checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186" dependencies = [ "ecdsa", "elliptic-curve", - "sha2", + "sha2 0.9.9", ] [[package]] @@ -2612,9 +2651,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -2623,15 +2662,14 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if 0.1.10", - "cloudabi", + "cfg-if 1.0.0", "instant", "libc", - "redox_syscall 0.1.57", + "redox_syscall", "smallvec", "winapi 0.3.9", ] @@ -3043,12 +3081,6 @@ dependencies = [ "cty", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "redox_syscall" version = "0.2.10" @@ -3185,7 +3217,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d" dependencies = [ "byteorder", - "digest", + "digest 0.9.0", "lazy_static", "num-bigint-dig", "num-integer", @@ -3484,10 +3516,10 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] @@ -3497,13 +3529,24 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.1", +] + [[package]] name = "shell-escape" version = "0.1.5" @@ -3525,7 +3568,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" dependencies = [ - "digest", + "digest 0.9.0", "rand_core 0.6.3", ] @@ -4175,7 +4218,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "rand 0.8.4", - "redox_syscall 0.2.10", + "redox_syscall", "remove_dir_all", "winapi 0.3.9", ] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 1943a635f3..702b2cf0f5 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -47,8 +47,8 @@ winres = "=0.1.11" [dependencies] deno_ast = { version = "0.11.0", features = ["bundler", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "transpiling", "typescript", "view", "visit"] } deno_core = { version = "0.118.0", path = "../core" } -deno_doc = "0.29.0" -deno_graph = "0.22.0" +deno_doc = "0.31.0" +deno_graph = "0.23.0" deno_lint = { version = "0.24.0", features = ["docs"] } deno_runtime = { version = "0.44.0", path = "../runtime" } @@ -63,9 +63,10 @@ data-url = "=0.1.1" dissimilar = "=1.0.2" dprint-plugin-json = "=0.14.1" dprint-plugin-markdown = "=0.12.2" -dprint-plugin-typescript = "=0.62.2" +dprint-plugin-typescript = "=0.64.1" encoding_rs = "=0.8.29" env_logger = "=0.8.4" +eszip = "=0.16.0" fancy-regex = "=0.7.1" http = "=0.2.4" import_map = "=0.8.0" diff --git a/cli/cache.rs b/cli/cache.rs index 1075230d18..8bd40fc8a4 100644 --- a/cli/cache.rs +++ b/cli/cache.rs @@ -164,7 +164,7 @@ impl Loader for FetchCacher { Err(err) }, |file| { - Ok(Some(LoadResponse { + Ok(Some(LoadResponse::Module { specifier: file.specifier, maybe_headers: file.maybe_headers, content: file.source, @@ -288,11 +288,15 @@ impl Loader for MemoryCacher { specifier_str = specifier_str[3..].to_string(); } } - let response = self.sources.get(&specifier_str).map(|c| LoadResponse { - specifier: specifier.clone(), - maybe_headers: None, - content: c.to_owned(), - }); + let response = + self + .sources + .get(&specifier_str) + .map(|c| LoadResponse::Module { + specifier: specifier.clone(), + maybe_headers: None, + content: c.to_owned(), + }); Box::pin(future::ready(Ok(response))) } } diff --git a/cli/main.rs b/cli/main.rs index f8c8e695ac..ca6b36f0a5 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -415,23 +415,14 @@ async fn compile_command( "An executable name was not provided. One could not be inferred from the URL. Aborting.", ))?; - let graph = - create_graph_and_maybe_check(module_specifier.clone(), &ps, debug).await?; + let graph = Arc::try_unwrap( + create_graph_and_maybe_check(module_specifier.clone(), &ps, debug).await?, + ) + .map_err(|_| { + generic_error("There should only be one reference to ModuleGraph") + })?; - let source = (graph.as_ref().modules().len() == 1) - .then(|| { - let root_module = graph.as_ref().modules()[0]; - match root_module.media_type { - MediaType::JavaScript if root_module.maybe_source.is_some() => { - Some(Ok(root_module.maybe_source.clone().unwrap().to_string())) - } - _ => None, - } - }) - .flatten() - .unwrap_or_else(|| { - bundle_module_graph(graph.as_ref(), &ps, &ps.flags).map(|r| r.0) - })?; + let eszip = eszip::EszipV2::from_graph(graph, Default::default())?; info!( "{} {}", @@ -446,7 +437,8 @@ async fn compile_command( let final_bin = tools::standalone::create_standalone_binary( original_binary, - source, + eszip, + module_specifier.clone(), run_flags, )?; @@ -1430,34 +1422,40 @@ pub fn main() { colors::enable_ansi(); // For Windows 10 let args: Vec = env::args().collect(); - let standalone_res = match standalone::extract_standalone(args.clone()) { - Ok(Some((metadata, bundle))) => { - run_basic(standalone::run(bundle, metadata)) + + let exit_code = async move { + let standalone_res = + match standalone::extract_standalone(args.clone()).await { + Ok(Some((metadata, eszip))) => standalone::run(eszip, metadata).await, + Ok(None) => Ok(()), + Err(err) => Err(err), + }; + // TODO(bartlomieju): doesn't handle exit code set by the runtime properly + unwrap_or_exit(standalone_res); + + let flags = match flags::flags_from_vec(args) { + Ok(flags) => flags, + Err(err @ clap::Error { .. }) + if err.kind == clap::ErrorKind::DisplayHelp + || err.kind == clap::ErrorKind::DisplayVersion => + { + err.print().unwrap(); + std::process::exit(0); + } + Err(err) => unwrap_or_exit(Err(AnyError::from(err))), + }; + if !flags.v8_flags.is_empty() { + init_v8_flags(&*flags.v8_flags); } - Ok(None) => Ok(()), - Err(err) => Err(err), + + logger::init(flags.log_level); + + let exit_code = get_subcommand(flags).await; + + exit_code }; - // TODO(bartlomieju): doesn't handle exit code set by the runtime properly - unwrap_or_exit(standalone_res); - let flags = match flags::flags_from_vec(args) { - Ok(flags) => flags, - Err(err @ clap::Error { .. }) - if err.kind == clap::ErrorKind::DisplayHelp - || err.kind == clap::ErrorKind::DisplayVersion => - { - err.print().unwrap(); - std::process::exit(0); - } - Err(err) => unwrap_or_exit(Err(AnyError::from(err))), - }; - if !flags.v8_flags.is_empty() { - init_v8_flags(&*flags.v8_flags); - } - - logger::init(flags.log_level); - - let exit_code = unwrap_or_exit(run_basic(get_subcommand(flags))); + let exit_code = unwrap_or_exit(run_basic(exit_code)); std::process::exit(exit_code); } diff --git a/cli/standalone.rs b/cli/standalone.rs index c47ec57366..9fa2107952 100644 --- a/cli/standalone.rs +++ b/cli/standalone.rs @@ -12,7 +12,6 @@ use deno_core::error::type_error; use deno_core::error::AnyError; use deno_core::futures::FutureExt; use deno_core::located_script_name; -use deno_core::resolve_url; use deno_core::serde::Deserialize; use deno_core::serde::Serialize; use deno_core::serde_json; @@ -31,16 +30,14 @@ use deno_runtime::worker::WorkerOptions; use deno_runtime::BootstrapOptions; use log::Level; use std::env::current_exe; -use std::fs::File; use std::io::BufReader; use std::io::Cursor; -use std::io::Read; -use std::io::Seek; use std::io::SeekFrom; use std::iter::once; use std::pin::Pin; use std::rc::Rc; use std::sync::Arc; +use tokio::io::{AsyncReadExt, AsyncSeekExt}; #[derive(Deserialize, Serialize)] pub struct Metadata { @@ -54,6 +51,7 @@ pub struct Metadata { pub ca_stores: Option>, pub ca_data: Option>, pub unsafely_ignore_certificate_errors: Option>, + pub entrypoint: ModuleSpecifier, } pub const MAGIC_TRAILER: &[u8; 8] = b"d3n0l4nd"; @@ -67,37 +65,51 @@ pub const MAGIC_TRAILER: &[u8; 8] = b"d3n0l4nd"; /// These are dereferenced, and the bundle is executed under the configuration /// specified by the metadata. If no magic trailer is present, this function /// exits with `Ok(None)`. -pub fn extract_standalone( +pub async fn extract_standalone( args: Vec, -) -> Result, AnyError> { +) -> Result, AnyError> { let current_exe_path = current_exe()?; - let mut current_exe = File::open(current_exe_path)?; - let trailer_pos = current_exe.seek(SeekFrom::End(-24))?; + let file = tokio::fs::File::open(current_exe_path).await?; + + let mut bufreader = tokio::io::BufReader::new(file); + + let trailer_pos = bufreader.seek(SeekFrom::End(-24)).await?; let mut trailer = [0; 24]; - current_exe.read_exact(&mut trailer)?; + bufreader.read_exact(&mut trailer).await?; let (magic_trailer, rest) = trailer.split_at(8); if magic_trailer != MAGIC_TRAILER { return Ok(None); } - let (bundle_pos, rest) = rest.split_at(8); + let (eszip_archive_pos, rest) = rest.split_at(8); let metadata_pos = rest; - let bundle_pos = u64_from_bytes(bundle_pos)?; + let eszip_archive_pos = u64_from_bytes(eszip_archive_pos)?; let metadata_pos = u64_from_bytes(metadata_pos)?; - let bundle_len = metadata_pos - bundle_pos; let metadata_len = trailer_pos - metadata_pos; - current_exe.seek(SeekFrom::Start(bundle_pos))?; - let bundle = read_string_slice(&mut current_exe, bundle_pos, bundle_len) - .context("Failed to read source bundle from the current executable")?; - let metadata = - read_string_slice(&mut current_exe, metadata_pos, metadata_len) - .context("Failed to read metadata from the current executable")?; + bufreader.seek(SeekFrom::Start(eszip_archive_pos)).await?; + + let (eszip, loader) = eszip::EszipV2::parse(bufreader) + .await + .context("Failed to parse eszip header")?; + + let mut bufreader = loader.await.context("Failed to parse eszip archive")?; + + bufreader.seek(SeekFrom::Start(metadata_pos)).await?; + + let mut metadata = String::new(); + + bufreader + .take(metadata_len) + .read_to_string(&mut metadata) + .await + .context("Failed to read metadata from the current executable")?; let mut metadata: Metadata = serde_json::from_str(&metadata).unwrap(); metadata.argv.append(&mut args[1..].to_vec()); - Ok(Some((metadata, bundle))) + + Ok(Some((metadata, eszip))) } fn u64_from_bytes(arr: &[u8]) -> Result { @@ -107,39 +119,17 @@ fn u64_from_bytes(arr: &[u8]) -> Result { Ok(u64::from_be_bytes(*fixed_arr)) } -fn read_string_slice( - file: &mut File, - pos: u64, - len: u64, -) -> Result { - let mut string = String::new(); - file.seek(SeekFrom::Start(pos))?; - file.take(len).read_to_string(&mut string)?; - // TODO: check amount of bytes read - Ok(string) -} - -const SPECIFIER: &str = "file://$deno$/bundle.js"; - -struct EmbeddedModuleLoader(String); +struct EmbeddedModuleLoader(eszip::EszipV2); impl ModuleLoader for EmbeddedModuleLoader { fn resolve( &self, specifier: &str, - _referrer: &str, + base: &str, _is_main: bool, ) -> Result { - if let Ok(module_specifier) = resolve_url(specifier) { - if get_source_from_data_url(&module_specifier).is_ok() - || specifier == SPECIFIER - { - return Ok(module_specifier); - } - } - Err(type_error( - "Self-contained binaries don't support module loading", - )) + let resolve = deno_core::resolve_import(specifier, base)?; + Ok(resolve) } fn load( @@ -149,22 +139,36 @@ impl ModuleLoader for EmbeddedModuleLoader { _is_dynamic: bool, ) -> Pin> { let module_specifier = module_specifier.clone(); + let is_data_uri = get_source_from_data_url(&module_specifier).ok(); - let code = if let Some((ref source, _)) = is_data_uri { - source.to_string() - } else { - self.0.to_string() - }; + + let module = self + .0 + .get_module(module_specifier.as_str()) + .ok_or_else(|| type_error("Module not found")); + async move { - if is_data_uri.is_none() && module_specifier.to_string() != SPECIFIER { - return Err(type_error( - "Self-contained binaries don't support module loading", - )); + if let Some((ref source, _)) = is_data_uri { + return Ok(deno_core::ModuleSource { + code: source.to_owned(), + module_type: deno_core::ModuleType::JavaScript, + module_url_specified: module_specifier.to_string(), + module_url_found: module_specifier.to_string(), + }); } + let module = module?; + let code = module.source().await; + let code = std::str::from_utf8(&code) + .map_err(|_| type_error("Module source is not utf-8"))? + .to_owned(); + Ok(deno_core::ModuleSource { code, - module_type: deno_core::ModuleType::JavaScript, + module_type: match module.kind { + eszip::ModuleKind::JavaScript => deno_core::ModuleType::JavaScript, + eszip::ModuleKind::Json => deno_core::ModuleType::Json, + }, module_url_specified: module_specifier.to_string(), module_url_found: module_specifier.to_string(), }) @@ -195,16 +199,16 @@ fn metadata_to_flags(metadata: &Metadata) -> Flags { } pub async fn run( - source_code: String, + eszip: eszip::EszipV2, metadata: Metadata, ) -> Result<(), AnyError> { let flags = metadata_to_flags(&metadata); - let main_module = resolve_url(SPECIFIER)?; + let main_module = &metadata.entrypoint; let ps = ProcState::build(Arc::new(flags)).await?; let permissions = Permissions::from_options(&metadata.permissions); let blob_store = BlobStore::default(); let broadcast_channel = InMemoryBroadcastChannel::default(); - let module_loader = Rc::new(EmbeddedModuleLoader(source_code)); + let module_loader = Rc::new(EmbeddedModuleLoader(eszip)); let create_web_worker_cb = Arc::new(|_| { todo!("Worker are currently not supported in standalone binaries"); }); @@ -276,7 +280,7 @@ pub async fn run( permissions, options, ); - worker.execute_main_module(&main_module).await?; + worker.execute_main_module(main_module).await?; worker.dispatch_load_event(&located_script_name!())?; worker.run_event_loop(true).await?; worker.dispatch_unload_event(&located_script_name!())?; diff --git a/cli/tests/integration/compile_tests.rs b/cli/tests/integration/compile_tests.rs index 1a81784afe..dcbbf158bb 100644 --- a/cli/tests/integration/compile_tests.rs +++ b/cli/tests/integration/compile_tests.rs @@ -107,8 +107,9 @@ fn standalone_error() { } else { dir.path().join("error") }; + let testdata_path = util::testdata_path(); let output = util::deno_cmd() - .current_dir(util::testdata_path()) + .current_dir(&testdata_path) .arg("compile") .arg("--unstable") .arg("--output") @@ -130,26 +131,32 @@ fn standalone_error() { .unwrap(); assert!(!output.status.success()); assert_eq!(output.stdout, b""); - let expected_stderr = "error: Error: boom!\n at boom (file://$deno$/bundle.js:6:11)\n at foo (file://$deno$/bundle.js:9:5)\n at file://$deno$/bundle.js:11:1\n"; let stderr = String::from_utf8(output.stderr).unwrap(); - assert_eq!(stderr, expected_stderr); + // On Windows, we cannot assert the file path (because '\'). + // Instead we just check for relevant output. + assert!(stderr.contains("error: Error: boom!\n at boom (file://")); + assert!(stderr.contains("standalone_error.ts:2:11")); + assert!(stderr.contains("at foo (file://")); + assert!(stderr.contains("standalone_error.ts:5:5")); + assert!(stderr.contains("standalone_error.ts:7:1")); } #[test] -fn standalone_no_module_load() { +fn standalone_error_module_with_imports() { let dir = TempDir::new().expect("tempdir fail"); let exe = if cfg!(windows) { - dir.path().join("hello.exe") + dir.path().join("error.exe") } else { - dir.path().join("hello") + dir.path().join("error") }; + let testdata_path = util::testdata_path(); let output = util::deno_cmd() - .current_dir(util::testdata_path()) + .current_dir(&testdata_path) .arg("compile") .arg("--unstable") .arg("--output") .arg(&exe) - .arg("./standalone_import.ts") + .arg("./standalone_error_module_with_imports_1.ts") .stdout(std::process::Stdio::piped()) .spawn() .unwrap() @@ -157,6 +164,7 @@ fn standalone_no_module_load() { .unwrap(); assert!(output.status.success()); let output = Command::new(exe) + .env("NO_COLOR", "1") .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) .spawn() @@ -164,10 +172,13 @@ fn standalone_no_module_load() { .wait_with_output() .unwrap(); assert!(!output.status.success()); - assert_eq!(output.stdout, b"start\n"); - let stderr_str = String::from_utf8(output.stderr).unwrap(); - assert!(util::strip_ansi_codes(&stderr_str) - .contains("Self-contained binaries don't support module loading")); + println!("{:#?}", &output); + assert_eq!(output.stdout, b"hello\n"); + let stderr = String::from_utf8(output.stderr).unwrap(); + // On Windows, we cannot assert the file path (because '\'). + // Instead we just check for relevant output. + assert!(stderr.contains("error: Error: boom!\n at file://")); + assert!(stderr.contains("standalone_error_module_with_imports_2.ts:2:7")); } #[test] diff --git a/cli/tests/testdata/standalone_dynamic_imports.ts b/cli/tests/testdata/standalone_dynamic_imports.ts new file mode 100644 index 0000000000..d4dc551524 --- /dev/null +++ b/cli/tests/testdata/standalone_dynamic_imports.ts @@ -0,0 +1,15 @@ +(async () => { + const { returnsHi, returnsFoo2, printHello3 } = await import( + "./subdir/mod1.ts" + ); + + printHello3(); + + if (returnsHi() !== "Hi") { + throw Error("Unexpected"); + } + + if (returnsFoo2() !== "Foo") { + throw Error("Unexpected"); + } +})(); diff --git a/cli/tests/testdata/standalone_error_module_with_imports_1.ts b/cli/tests/testdata/standalone_error_module_with_imports_1.ts new file mode 100644 index 0000000000..bf38f72634 --- /dev/null +++ b/cli/tests/testdata/standalone_error_module_with_imports_1.ts @@ -0,0 +1 @@ +import "./standalone_error_module_with_imports_2.ts"; diff --git a/cli/tests/testdata/standalone_error_module_with_imports_2.ts b/cli/tests/testdata/standalone_error_module_with_imports_2.ts new file mode 100644 index 0000000000..ef052b512e --- /dev/null +++ b/cli/tests/testdata/standalone_error_module_with_imports_2.ts @@ -0,0 +1,2 @@ +console.log("hello"); +throw new Error("boom!"); diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 38f8c29188..36fc34e5b5 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -81,7 +81,7 @@ impl Loader for DocLoader { .fetch(&specifier, &mut Permissions::allow_all()) .await .map(|file| { - Some(LoadResponse { + Some(LoadResponse::Module { specifier, content: file.source.clone(), maybe_headers: file.maybe_headers, diff --git a/cli/tools/standalone.rs b/cli/tools/standalone.rs index 2f8ca1533f..44150add80 100644 --- a/cli/tools/standalone.rs +++ b/cli/tools/standalone.rs @@ -8,6 +8,7 @@ use crate::flags::RunFlags; use deno_core::anyhow::bail; use deno_core::error::AnyError; use deno_core::serde_json; +use deno_graph::ModuleSpecifier; use deno_runtime::deno_fetch::reqwest::Client; use std::env; use std::fs::read; @@ -86,10 +87,12 @@ async fn download_base_binary( /// and magic trailer to the currently executing binary. pub fn create_standalone_binary( mut original_bin: Vec, - source_code: String, + eszip: eszip::EszipV2, + entrypoint: ModuleSpecifier, flags: Flags, ) -> Result, AnyError> { - let mut source_code = source_code.as_bytes().to_vec(); + let mut eszip_archive = eszip.into_bytes(); + let ca_data = match &flags.ca_file { Some(ca_file) => Some(read(ca_file)?), None => None, @@ -107,19 +110,21 @@ pub fn create_standalone_binary( log_level: flags.log_level, ca_stores: flags.ca_stores, ca_data, + entrypoint, }; let mut metadata = serde_json::to_string(&metadata)?.as_bytes().to_vec(); - let bundle_pos = original_bin.len(); - let metadata_pos = bundle_pos + source_code.len(); + let eszip_pos = original_bin.len(); + let metadata_pos = eszip_pos + eszip_archive.len(); let mut trailer = MAGIC_TRAILER.to_vec(); - trailer.write_all(&bundle_pos.to_be_bytes())?; + trailer.write_all(&eszip_pos.to_be_bytes())?; trailer.write_all(&metadata_pos.to_be_bytes())?; - let mut final_bin = - Vec::with_capacity(original_bin.len() + source_code.len() + trailer.len()); + let mut final_bin = Vec::with_capacity( + original_bin.len() + eszip_archive.len() + trailer.len(), + ); final_bin.append(&mut original_bin); - final_bin.append(&mut source_code); + final_bin.append(&mut eszip_archive); final_bin.append(&mut metadata); final_bin.append(&mut trailer); diff --git a/cli/tsc.rs b/cli/tsc.rs index 0e55d27e2e..b679b049e7 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -741,7 +741,7 @@ mod tests { let source_path = self.fixtures.join(specifier_text); let response = fs::read_to_string(&source_path) .map(|c| { - Some(deno_graph::source::LoadResponse { + Some(deno_graph::source::LoadResponse::Module { specifier: specifier.clone(), maybe_headers: None, content: Arc::new(c),