1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-12 00:54:02 -05:00

feat(cli): Replace bundling with eszip in deno compile (#13563)

Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
This commit is contained in:
William Tetlow 2022-02-15 12:33:46 +00:00 committed by GitHub
parent 760f4c9e24
commit 7b893bd57f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 256 additions and 172 deletions

123
Cargo.lock generated
View file

@ -308,6 +308,15 @@ dependencies = [
"generic-array", "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]] [[package]]
name = "block-modes" name = "block-modes"
version = "0.8.1" version = "0.8.1"
@ -469,15 +478,6 @@ dependencies = [
"winapi 0.3.9", "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]] [[package]]
name = "codespan-reporting" name = "codespan-reporting"
version = "0.11.1" version = "0.11.1"
@ -593,6 +593,15 @@ dependencies = [
"zeroize", "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]] [[package]]
name = "crypto-mac" name = "crypto-mac"
version = "0.11.1" version = "0.11.1"
@ -743,6 +752,7 @@ dependencies = [
"dprint-plugin-typescript", "dprint-plugin-typescript",
"encoding_rs", "encoding_rs",
"env_logger", "env_logger",
"eszip",
"fancy-regex", "fancy-regex",
"flaky_test", "flaky_test",
"fwdansi", "fwdansi",
@ -874,7 +884,7 @@ dependencies = [
"serde", "serde",
"serde_bytes", "serde_bytes",
"sha-1", "sha-1",
"sha2", "sha2 0.9.9",
"spki", "spki",
"tokio", "tokio",
"uuid", "uuid",
@ -882,9 +892,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_doc" name = "deno_doc"
version = "0.29.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51c8f938ff0c4a759e89a1c7194415597d01eae0c469d106d1784cbdb977415e" checksum = "c7e2982f488761ef90a31d3d2a873cb05bf6342ffba9d8fbf94b95a6366fa463"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"deno_ast", "deno_ast",
@ -928,9 +938,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_graph" name = "deno_graph"
version = "0.22.0" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cabd84b8d6294fa8174be6501d11893e1791149f4e33c34f036cef0c2387d5d5" checksum = "b3108bfa75e0f439f83ac8540d8e494b7d3c8a782db805d126e3a3125d84a38b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cfg-if 1.0.0", "cfg-if 1.0.0",
@ -1163,6 +1173,17 @@ dependencies = [
"generic-array", "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]] [[package]]
name = "dissimilar" name = "dissimilar"
version = "1.0.2" version = "1.0.2"
@ -1232,14 +1253,13 @@ dependencies = [
[[package]] [[package]]
name = "dprint-plugin-typescript" name = "dprint-plugin-typescript"
version = "0.62.2" version = "0.64.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85a2040b94cdda1fa059abc54e41101a7f77ee0fd16e55213f7f44e7e46f9278" checksum = "1f37bdb4c73ee3ed24e2630958bf1c9996799113ebb59359eea2c7827d867031"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"deno_ast", "deno_ast",
"dprint-core", "dprint-core",
"parking_lot_core",
"rustc-hash", "rustc-hash",
"serde", "serde",
] ]
@ -1372,6 +1392,25 @@ dependencies = [
"str-buf", "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]] [[package]]
name = "fallible-iterator" name = "fallible-iterator"
version = "0.2.0" version = "0.2.0"
@ -1423,7 +1462,7 @@ checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"redox_syscall 0.2.10", "redox_syscall",
"winapi 0.3.9", "winapi 0.3.9",
] ]
@ -1809,7 +1848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
dependencies = [ dependencies = [
"crypto-mac", "crypto-mac",
"digest", "digest 0.9.0",
] ]
[[package]] [[package]]
@ -2598,7 +2637,7 @@ checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186"
dependencies = [ dependencies = [
"ecdsa", "ecdsa",
"elliptic-curve", "elliptic-curve",
"sha2", "sha2 0.9.9",
] ]
[[package]] [[package]]
@ -2612,9 +2651,9 @@ dependencies = [
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [ dependencies = [
"instant", "instant",
"lock_api", "lock_api",
@ -2623,15 +2662,14 @@ dependencies = [
[[package]] [[package]]
name = "parking_lot_core" name = "parking_lot_core"
version = "0.8.0" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 1.0.0",
"cloudabi",
"instant", "instant",
"libc", "libc",
"redox_syscall 0.1.57", "redox_syscall",
"smallvec", "smallvec",
"winapi 0.3.9", "winapi 0.3.9",
] ]
@ -3043,12 +3081,6 @@ dependencies = [
"cty", "cty",
] ]
[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.10" version = "0.2.10"
@ -3185,7 +3217,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d" checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"digest", "digest 0.9.0",
"lazy_static", "lazy_static",
"num-bigint-dig", "num-bigint-dig",
"num-integer", "num-integer",
@ -3484,10 +3516,10 @@ version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
dependencies = [ dependencies = [
"block-buffer", "block-buffer 0.9.0",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"cpufeatures", "cpufeatures",
"digest", "digest 0.9.0",
"opaque-debug", "opaque-debug",
] ]
@ -3497,13 +3529,24 @@ version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [ dependencies = [
"block-buffer", "block-buffer 0.9.0",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"cpufeatures", "cpufeatures",
"digest", "digest 0.9.0",
"opaque-debug", "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]] [[package]]
name = "shell-escape" name = "shell-escape"
version = "0.1.5" version = "0.1.5"
@ -3525,7 +3568,7 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4"
dependencies = [ dependencies = [
"digest", "digest 0.9.0",
"rand_core 0.6.3", "rand_core 0.6.3",
] ]
@ -4175,7 +4218,7 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"rand 0.8.4", "rand 0.8.4",
"redox_syscall 0.2.10", "redox_syscall",
"remove_dir_all", "remove_dir_all",
"winapi 0.3.9", "winapi 0.3.9",
] ]

View file

@ -47,8 +47,8 @@ winres = "=0.1.11"
[dependencies] [dependencies]
deno_ast = { version = "0.11.0", features = ["bundler", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "transpiling", "typescript", "view", "visit"] } 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_core = { version = "0.118.0", path = "../core" }
deno_doc = "0.29.0" deno_doc = "0.31.0"
deno_graph = "0.22.0" deno_graph = "0.23.0"
deno_lint = { version = "0.24.0", features = ["docs"] } deno_lint = { version = "0.24.0", features = ["docs"] }
deno_runtime = { version = "0.44.0", path = "../runtime" } deno_runtime = { version = "0.44.0", path = "../runtime" }
@ -63,9 +63,10 @@ data-url = "=0.1.1"
dissimilar = "=1.0.2" dissimilar = "=1.0.2"
dprint-plugin-json = "=0.14.1" dprint-plugin-json = "=0.14.1"
dprint-plugin-markdown = "=0.12.2" dprint-plugin-markdown = "=0.12.2"
dprint-plugin-typescript = "=0.62.2" dprint-plugin-typescript = "=0.64.1"
encoding_rs = "=0.8.29" encoding_rs = "=0.8.29"
env_logger = "=0.8.4" env_logger = "=0.8.4"
eszip = "=0.16.0"
fancy-regex = "=0.7.1" fancy-regex = "=0.7.1"
http = "=0.2.4" http = "=0.2.4"
import_map = "=0.8.0" import_map = "=0.8.0"

View file

@ -164,7 +164,7 @@ impl Loader for FetchCacher {
Err(err) Err(err)
}, },
|file| { |file| {
Ok(Some(LoadResponse { Ok(Some(LoadResponse::Module {
specifier: file.specifier, specifier: file.specifier,
maybe_headers: file.maybe_headers, maybe_headers: file.maybe_headers,
content: file.source, content: file.source,
@ -288,11 +288,15 @@ impl Loader for MemoryCacher {
specifier_str = specifier_str[3..].to_string(); specifier_str = specifier_str[3..].to_string();
} }
} }
let response = self.sources.get(&specifier_str).map(|c| LoadResponse { let response =
specifier: specifier.clone(), self
maybe_headers: None, .sources
content: c.to_owned(), .get(&specifier_str)
}); .map(|c| LoadResponse::Module {
specifier: specifier.clone(),
maybe_headers: None,
content: c.to_owned(),
});
Box::pin(future::ready(Ok(response))) Box::pin(future::ready(Ok(response)))
} }
} }

View file

@ -415,23 +415,14 @@ async fn compile_command(
"An executable name was not provided. One could not be inferred from the URL. Aborting.", "An executable name was not provided. One could not be inferred from the URL. Aborting.",
))?; ))?;
let graph = let graph = Arc::try_unwrap(
create_graph_and_maybe_check(module_specifier.clone(), &ps, debug).await?; 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) let eszip = eszip::EszipV2::from_graph(graph, Default::default())?;
.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)
})?;
info!( info!(
"{} {}", "{} {}",
@ -446,7 +437,8 @@ async fn compile_command(
let final_bin = tools::standalone::create_standalone_binary( let final_bin = tools::standalone::create_standalone_binary(
original_binary, original_binary,
source, eszip,
module_specifier.clone(),
run_flags, run_flags,
)?; )?;
@ -1430,34 +1422,40 @@ pub fn main() {
colors::enable_ansi(); // For Windows 10 colors::enable_ansi(); // For Windows 10
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let standalone_res = match standalone::extract_standalone(args.clone()) {
Ok(Some((metadata, bundle))) => { let exit_code = async move {
run_basic(standalone::run(bundle, metadata)) 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) { let exit_code = unwrap_or_exit(run_basic(exit_code));
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)));
std::process::exit(exit_code); std::process::exit(exit_code);
} }

View file

@ -12,7 +12,6 @@ use deno_core::error::type_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::futures::FutureExt; use deno_core::futures::FutureExt;
use deno_core::located_script_name; use deno_core::located_script_name;
use deno_core::resolve_url;
use deno_core::serde::Deserialize; use deno_core::serde::Deserialize;
use deno_core::serde::Serialize; use deno_core::serde::Serialize;
use deno_core::serde_json; use deno_core::serde_json;
@ -31,16 +30,14 @@ use deno_runtime::worker::WorkerOptions;
use deno_runtime::BootstrapOptions; use deno_runtime::BootstrapOptions;
use log::Level; use log::Level;
use std::env::current_exe; use std::env::current_exe;
use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use std::io::Cursor; use std::io::Cursor;
use std::io::Read;
use std::io::Seek;
use std::io::SeekFrom; use std::io::SeekFrom;
use std::iter::once; use std::iter::once;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use tokio::io::{AsyncReadExt, AsyncSeekExt};
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct Metadata { pub struct Metadata {
@ -54,6 +51,7 @@ pub struct Metadata {
pub ca_stores: Option<Vec<String>>, pub ca_stores: Option<Vec<String>>,
pub ca_data: Option<Vec<u8>>, pub ca_data: Option<Vec<u8>>,
pub unsafely_ignore_certificate_errors: Option<Vec<String>>, pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
pub entrypoint: ModuleSpecifier,
} }
pub const MAGIC_TRAILER: &[u8; 8] = b"d3n0l4nd"; 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 /// These are dereferenced, and the bundle is executed under the configuration
/// specified by the metadata. If no magic trailer is present, this function /// specified by the metadata. If no magic trailer is present, this function
/// exits with `Ok(None)`. /// exits with `Ok(None)`.
pub fn extract_standalone( pub async fn extract_standalone(
args: Vec<String>, args: Vec<String>,
) -> Result<Option<(Metadata, String)>, AnyError> { ) -> Result<Option<(Metadata, eszip::EszipV2)>, AnyError> {
let current_exe_path = current_exe()?; let current_exe_path = current_exe()?;
let mut current_exe = File::open(current_exe_path)?; let file = tokio::fs::File::open(current_exe_path).await?;
let trailer_pos = current_exe.seek(SeekFrom::End(-24))?;
let mut bufreader = tokio::io::BufReader::new(file);
let trailer_pos = bufreader.seek(SeekFrom::End(-24)).await?;
let mut trailer = [0; 24]; 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); let (magic_trailer, rest) = trailer.split_at(8);
if magic_trailer != MAGIC_TRAILER { if magic_trailer != MAGIC_TRAILER {
return Ok(None); 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 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 metadata_pos = u64_from_bytes(metadata_pos)?;
let bundle_len = metadata_pos - bundle_pos;
let metadata_len = trailer_pos - metadata_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) bufreader.seek(SeekFrom::Start(eszip_archive_pos)).await?;
.context("Failed to read source bundle from the current executable")?;
let metadata = let (eszip, loader) = eszip::EszipV2::parse(bufreader)
read_string_slice(&mut current_exe, metadata_pos, metadata_len) .await
.context("Failed to read metadata from the current executable")?; .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(); let mut metadata: Metadata = serde_json::from_str(&metadata).unwrap();
metadata.argv.append(&mut args[1..].to_vec()); metadata.argv.append(&mut args[1..].to_vec());
Ok(Some((metadata, bundle)))
Ok(Some((metadata, eszip)))
} }
fn u64_from_bytes(arr: &[u8]) -> Result<u64, AnyError> { fn u64_from_bytes(arr: &[u8]) -> Result<u64, AnyError> {
@ -107,39 +119,17 @@ fn u64_from_bytes(arr: &[u8]) -> Result<u64, AnyError> {
Ok(u64::from_be_bytes(*fixed_arr)) Ok(u64::from_be_bytes(*fixed_arr))
} }
fn read_string_slice( struct EmbeddedModuleLoader(eszip::EszipV2);
file: &mut File,
pos: u64,
len: u64,
) -> Result<String, AnyError> {
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);
impl ModuleLoader for EmbeddedModuleLoader { impl ModuleLoader for EmbeddedModuleLoader {
fn resolve( fn resolve(
&self, &self,
specifier: &str, specifier: &str,
_referrer: &str, base: &str,
_is_main: bool, _is_main: bool,
) -> Result<ModuleSpecifier, AnyError> { ) -> Result<ModuleSpecifier, AnyError> {
if let Ok(module_specifier) = resolve_url(specifier) { let resolve = deno_core::resolve_import(specifier, base)?;
if get_source_from_data_url(&module_specifier).is_ok() Ok(resolve)
|| specifier == SPECIFIER
{
return Ok(module_specifier);
}
}
Err(type_error(
"Self-contained binaries don't support module loading",
))
} }
fn load( fn load(
@ -149,22 +139,36 @@ impl ModuleLoader for EmbeddedModuleLoader {
_is_dynamic: bool, _is_dynamic: bool,
) -> Pin<Box<deno_core::ModuleSourceFuture>> { ) -> Pin<Box<deno_core::ModuleSourceFuture>> {
let module_specifier = module_specifier.clone(); let module_specifier = module_specifier.clone();
let is_data_uri = get_source_from_data_url(&module_specifier).ok(); 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() let module = self
} else { .0
self.0.to_string() .get_module(module_specifier.as_str())
}; .ok_or_else(|| type_error("Module not found"));
async move { async move {
if is_data_uri.is_none() && module_specifier.to_string() != SPECIFIER { if let Some((ref source, _)) = is_data_uri {
return Err(type_error( return Ok(deno_core::ModuleSource {
"Self-contained binaries don't support module loading", 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 { Ok(deno_core::ModuleSource {
code, 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_specified: module_specifier.to_string(),
module_url_found: 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( pub async fn run(
source_code: String, eszip: eszip::EszipV2,
metadata: Metadata, metadata: Metadata,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let flags = metadata_to_flags(&metadata); 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 ps = ProcState::build(Arc::new(flags)).await?;
let permissions = Permissions::from_options(&metadata.permissions); let permissions = Permissions::from_options(&metadata.permissions);
let blob_store = BlobStore::default(); let blob_store = BlobStore::default();
let broadcast_channel = InMemoryBroadcastChannel::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(|_| { let create_web_worker_cb = Arc::new(|_| {
todo!("Worker are currently not supported in standalone binaries"); todo!("Worker are currently not supported in standalone binaries");
}); });
@ -276,7 +280,7 @@ pub async fn run(
permissions, permissions,
options, options,
); );
worker.execute_main_module(&main_module).await?; worker.execute_main_module(main_module).await?;
worker.dispatch_load_event(&located_script_name!())?; worker.dispatch_load_event(&located_script_name!())?;
worker.run_event_loop(true).await?; worker.run_event_loop(true).await?;
worker.dispatch_unload_event(&located_script_name!())?; worker.dispatch_unload_event(&located_script_name!())?;

View file

@ -107,8 +107,9 @@ fn standalone_error() {
} else { } else {
dir.path().join("error") dir.path().join("error")
}; };
let testdata_path = util::testdata_path();
let output = util::deno_cmd() let output = util::deno_cmd()
.current_dir(util::testdata_path()) .current_dir(&testdata_path)
.arg("compile") .arg("compile")
.arg("--unstable") .arg("--unstable")
.arg("--output") .arg("--output")
@ -130,26 +131,32 @@ fn standalone_error() {
.unwrap(); .unwrap();
assert!(!output.status.success()); assert!(!output.status.success());
assert_eq!(output.stdout, b""); 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(); 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] #[test]
fn standalone_no_module_load() { fn standalone_error_module_with_imports() {
let dir = TempDir::new().expect("tempdir fail"); let dir = TempDir::new().expect("tempdir fail");
let exe = if cfg!(windows) { let exe = if cfg!(windows) {
dir.path().join("hello.exe") dir.path().join("error.exe")
} else { } else {
dir.path().join("hello") dir.path().join("error")
}; };
let testdata_path = util::testdata_path();
let output = util::deno_cmd() let output = util::deno_cmd()
.current_dir(util::testdata_path()) .current_dir(&testdata_path)
.arg("compile") .arg("compile")
.arg("--unstable") .arg("--unstable")
.arg("--output") .arg("--output")
.arg(&exe) .arg(&exe)
.arg("./standalone_import.ts") .arg("./standalone_error_module_with_imports_1.ts")
.stdout(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped())
.spawn() .spawn()
.unwrap() .unwrap()
@ -157,6 +164,7 @@ fn standalone_no_module_load() {
.unwrap(); .unwrap();
assert!(output.status.success()); assert!(output.status.success());
let output = Command::new(exe) let output = Command::new(exe)
.env("NO_COLOR", "1")
.stdout(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped())
.spawn() .spawn()
@ -164,10 +172,13 @@ fn standalone_no_module_load() {
.wait_with_output() .wait_with_output()
.unwrap(); .unwrap();
assert!(!output.status.success()); assert!(!output.status.success());
assert_eq!(output.stdout, b"start\n"); println!("{:#?}", &output);
let stderr_str = String::from_utf8(output.stderr).unwrap(); assert_eq!(output.stdout, b"hello\n");
assert!(util::strip_ansi_codes(&stderr_str) let stderr = String::from_utf8(output.stderr).unwrap();
.contains("Self-contained binaries don't support module loading")); // 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] #[test]

View file

@ -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");
}
})();

View file

@ -0,0 +1 @@
import "./standalone_error_module_with_imports_2.ts";

View file

@ -0,0 +1,2 @@
console.log("hello");
throw new Error("boom!");

View file

@ -81,7 +81,7 @@ impl Loader for DocLoader {
.fetch(&specifier, &mut Permissions::allow_all()) .fetch(&specifier, &mut Permissions::allow_all())
.await .await
.map(|file| { .map(|file| {
Some(LoadResponse { Some(LoadResponse::Module {
specifier, specifier,
content: file.source.clone(), content: file.source.clone(),
maybe_headers: file.maybe_headers, maybe_headers: file.maybe_headers,

View file

@ -8,6 +8,7 @@ use crate::flags::RunFlags;
use deno_core::anyhow::bail; use deno_core::anyhow::bail;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::serde_json; use deno_core::serde_json;
use deno_graph::ModuleSpecifier;
use deno_runtime::deno_fetch::reqwest::Client; use deno_runtime::deno_fetch::reqwest::Client;
use std::env; use std::env;
use std::fs::read; use std::fs::read;
@ -86,10 +87,12 @@ async fn download_base_binary(
/// and magic trailer to the currently executing binary. /// and magic trailer to the currently executing binary.
pub fn create_standalone_binary( pub fn create_standalone_binary(
mut original_bin: Vec<u8>, mut original_bin: Vec<u8>,
source_code: String, eszip: eszip::EszipV2,
entrypoint: ModuleSpecifier,
flags: Flags, flags: Flags,
) -> Result<Vec<u8>, AnyError> { ) -> Result<Vec<u8>, 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 { let ca_data = match &flags.ca_file {
Some(ca_file) => Some(read(ca_file)?), Some(ca_file) => Some(read(ca_file)?),
None => None, None => None,
@ -107,19 +110,21 @@ pub fn create_standalone_binary(
log_level: flags.log_level, log_level: flags.log_level,
ca_stores: flags.ca_stores, ca_stores: flags.ca_stores,
ca_data, ca_data,
entrypoint,
}; };
let mut metadata = serde_json::to_string(&metadata)?.as_bytes().to_vec(); let mut metadata = serde_json::to_string(&metadata)?.as_bytes().to_vec();
let bundle_pos = original_bin.len(); let eszip_pos = original_bin.len();
let metadata_pos = bundle_pos + source_code.len(); let metadata_pos = eszip_pos + eszip_archive.len();
let mut trailer = MAGIC_TRAILER.to_vec(); 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())?; trailer.write_all(&metadata_pos.to_be_bytes())?;
let mut final_bin = let mut final_bin = Vec::with_capacity(
Vec::with_capacity(original_bin.len() + source_code.len() + trailer.len()); original_bin.len() + eszip_archive.len() + trailer.len(),
);
final_bin.append(&mut original_bin); 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 metadata);
final_bin.append(&mut trailer); final_bin.append(&mut trailer);

View file

@ -741,7 +741,7 @@ mod tests {
let source_path = self.fixtures.join(specifier_text); let source_path = self.fixtures.join(specifier_text);
let response = fs::read_to_string(&source_path) let response = fs::read_to_string(&source_path)
.map(|c| { .map(|c| {
Some(deno_graph::source::LoadResponse { Some(deno_graph::source::LoadResponse::Module {
specifier: specifier.clone(), specifier: specifier.clone(),
maybe_headers: None, maybe_headers: None,
content: Arc::new(c), content: Arc::new(c),