diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2022-02-24 18:58:00 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-24 18:58:00 +0530 |
commit | 03c55b497035001cba77b0ddd8b22f0f9c25190d (patch) | |
tree | e4fded4e37329d5e56a79e1a3f49e5030c611ccf | |
parent | 3e8180c793f1dd7437a497ffdb0cf7e919a9a5c3 (diff) |
fix(compile): Support import maps (#13756)
-rw-r--r-- | cli/main.rs | 18 | ||||
-rw-r--r-- | cli/standalone.rs | 34 | ||||
-rw-r--r-- | cli/tests/integration/compile_tests.rs | 34 | ||||
-rw-r--r-- | cli/tests/testdata/standalone_import_map.json | 5 | ||||
-rw-r--r-- | cli/tests/testdata/standalone_import_map.ts | 1 | ||||
-rw-r--r-- | cli/tools/standalone.rs | 35 |
6 files changed, 110 insertions, 17 deletions
diff --git a/cli/main.rs b/cli/main.rs index 091c33b13..16f7d6b9b 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -396,19 +396,21 @@ async fn compile_command( ) -> Result<i32, AnyError> { let debug = flags.log_level == Some(log::Level::Debug); - let run_flags = - tools::standalone::compile_to_runtime_flags(&flags, compile_flags.args)?; + let run_flags = tools::standalone::compile_to_runtime_flags( + &flags, + compile_flags.args.clone(), + )?; let module_specifier = resolve_url_or_path(&compile_flags.source_file)?; let ps = ProcState::build(Arc::new(flags)).await?; let deno_dir = &ps.dir; - let output = compile_flags.output.and_then(|output| { - if fs_util::path_has_trailing_slash(&output) { + let output = compile_flags.output.as_ref().and_then(|output| { + if fs_util::path_has_trailing_slash(output) { let infer_file_name = infer_name_from_url(&module_specifier).map(PathBuf::from)?; Some(output.join(infer_file_name)) } else { - Some(output) + Some(output.to_path_buf()) } }).or_else(|| { infer_name_from_url(&module_specifier).map(PathBuf::from) @@ -423,6 +425,8 @@ async fn compile_command( generic_error("There should only be one reference to ModuleGraph") })?; + graph.valid().unwrap(); + let eszip = eszip::EszipV2::from_graph(graph, Default::default())?; info!( @@ -441,7 +445,9 @@ async fn compile_command( eszip, module_specifier.clone(), run_flags, - )?; + ps, + ) + .await?; info!("{} {}", colors::green("Emit"), output.display()); diff --git a/cli/standalone.rs b/cli/standalone.rs index 9fa210795..b7c026cec 100644 --- a/cli/standalone.rs +++ b/cli/standalone.rs @@ -6,6 +6,7 @@ use crate::flags::Flags; use crate::ops; use crate::proc_state::ProcState; use crate::version; +use crate::ImportMapResolver; use deno_core::anyhow::anyhow; use deno_core::anyhow::Context; use deno_core::error::type_error; @@ -19,6 +20,7 @@ use deno_core::url::Url; use deno_core::v8_set_flags; use deno_core::ModuleLoader; use deno_core::ModuleSpecifier; +use deno_graph::source::Resolver; use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; use deno_runtime::deno_tls::create_default_root_cert_store; use deno_runtime::deno_tls::rustls_pemfile; @@ -28,6 +30,7 @@ use deno_runtime::permissions::PermissionsOptions; use deno_runtime::worker::MainWorker; use deno_runtime::worker::WorkerOptions; use deno_runtime::BootstrapOptions; +use import_map::parse_from_json; use log::Level; use std::env::current_exe; use std::io::BufReader; @@ -51,6 +54,7 @@ pub struct Metadata { pub ca_stores: Option<Vec<String>>, pub ca_data: Option<Vec<u8>>, pub unsafely_ignore_certificate_errors: Option<Vec<String>>, + pub maybe_import_map: Option<(Url, String)>, pub entrypoint: ModuleSpecifier, } @@ -119,17 +123,26 @@ fn u64_from_bytes(arr: &[u8]) -> Result<u64, AnyError> { Ok(u64::from_be_bytes(*fixed_arr)) } -struct EmbeddedModuleLoader(eszip::EszipV2); +struct EmbeddedModuleLoader { + eszip: eszip::EszipV2, + maybe_import_map_resolver: Option<ImportMapResolver>, +} impl ModuleLoader for EmbeddedModuleLoader { fn resolve( &self, specifier: &str, - base: &str, + referrer: &str, _is_main: bool, ) -> Result<ModuleSpecifier, AnyError> { - let resolve = deno_core::resolve_import(specifier, base)?; - Ok(resolve) + let referrer = deno_core::resolve_url_or_path(referrer).unwrap(); + self.maybe_import_map_resolver.as_ref().map_or_else( + || { + deno_core::resolve_import(specifier, referrer.as_str()) + .map_err(|err| err.into()) + }, + |r| r.resolve(specifier, &referrer).to_result(), + ) } fn load( @@ -143,7 +156,7 @@ impl ModuleLoader for EmbeddedModuleLoader { let is_data_uri = get_source_from_data_url(&module_specifier).ok(); let module = self - .0 + .eszip .get_module(module_specifier.as_str()) .ok_or_else(|| type_error("Module not found")); @@ -208,7 +221,16 @@ pub async fn run( let permissions = Permissions::from_options(&metadata.permissions); let blob_store = BlobStore::default(); let broadcast_channel = InMemoryBroadcastChannel::default(); - let module_loader = Rc::new(EmbeddedModuleLoader(eszip)); + let module_loader = Rc::new(EmbeddedModuleLoader { + eszip, + maybe_import_map_resolver: metadata.maybe_import_map.map( + |(base, source)| { + ImportMapResolver::new(Arc::new( + parse_from_json(&base, &source).unwrap().import_map, + )) + }, + ), + }); let create_web_worker_cb = Arc::new(|_| { todo!("Worker are currently not supported in standalone binaries"); }); diff --git a/cli/tests/integration/compile_tests.rs b/cli/tests/integration/compile_tests.rs index dcbbf158b..fbe6ffcf5 100644 --- a/cli/tests/integration/compile_tests.rs +++ b/cli/tests/integration/compile_tests.rs @@ -451,6 +451,40 @@ fn standalone_runtime_flags() { } #[test] +fn standalone_import_map() { + let dir = TempDir::new().expect("tempdir fail"); + let exe = if cfg!(windows) { + dir.path().join("import_map.exe") + } else { + dir.path().join("import_map") + }; + let output = util::deno_cmd() + .current_dir(util::testdata_path()) + .arg("compile") + .arg("--unstable") + .arg("--allow-read") + .arg("--import-map") + .arg("standalone_import_map.json") + .arg("--output") + .arg(&exe) + .arg("./standalone_import_map.ts") + .stdout(std::process::Stdio::piped()) + .spawn() + .unwrap() + .wait_with_output() + .unwrap(); + assert!(output.status.success()); + let output = Command::new(exe) + .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap() + .wait_with_output() + .unwrap(); + assert!(output.status.success()); +} + +#[test] // https://github.com/denoland/deno/issues/12670 fn skip_rebundle() { let dir = TempDir::new().expect("tempdir fail"); diff --git a/cli/tests/testdata/standalone_import_map.json b/cli/tests/testdata/standalone_import_map.json new file mode 100644 index 000000000..6f978d6be --- /dev/null +++ b/cli/tests/testdata/standalone_import_map.json @@ -0,0 +1,5 @@ +{ + "imports": { + "hello": "./001_hello.js" + } +} diff --git a/cli/tests/testdata/standalone_import_map.ts b/cli/tests/testdata/standalone_import_map.ts new file mode 100644 index 000000000..097b96356 --- /dev/null +++ b/cli/tests/testdata/standalone_import_map.ts @@ -0,0 +1 @@ +import "hello"; diff --git a/cli/tools/standalone.rs b/cli/tools/standalone.rs index 44150add8..8d574aec7 100644 --- a/cli/tools/standalone.rs +++ b/cli/tools/standalone.rs @@ -5,11 +5,17 @@ use crate::flags::CheckFlag; use crate::flags::DenoSubcommand; use crate::flags::Flags; use crate::flags::RunFlags; +use crate::standalone::Metadata; +use crate::standalone::MAGIC_TRAILER; +use crate::ProcState; use deno_core::anyhow::bail; +use deno_core::anyhow::Context; use deno_core::error::AnyError; use deno_core::serde_json; +use deno_core::url::Url; use deno_graph::ModuleSpecifier; use deno_runtime::deno_fetch::reqwest::Client; +use deno_runtime::permissions::Permissions; use std::env; use std::fs::read; use std::fs::File; @@ -20,9 +26,6 @@ use std::io::Write; use std::path::Path; use std::path::PathBuf; -use crate::standalone::Metadata; -use crate::standalone::MAGIC_TRAILER; - pub async fn get_base_binary( deno_dir: &DenoDir, target: Option<String>, @@ -85,11 +88,12 @@ async fn download_base_binary( /// This functions creates a standalone deno binary by appending a bundle /// and magic trailer to the currently executing binary. -pub fn create_standalone_binary( +pub async fn create_standalone_binary( mut original_bin: Vec<u8>, eszip: eszip::EszipV2, entrypoint: ModuleSpecifier, flags: Flags, + ps: ProcState, ) -> Result<Vec<u8>, AnyError> { let mut eszip_archive = eszip.into_bytes(); @@ -97,6 +101,26 @@ pub fn create_standalone_binary( Some(ca_file) => Some(read(ca_file)?), None => None, }; + let maybe_import_map: Option<(Url, String)> = match flags + .import_map_path + .as_ref() + { + None => None, + Some(import_map_url) => { + let import_map_specifier = deno_core::resolve_url_or_path(import_map_url) + .context(format!("Bad URL (\"{}\") for import map.", import_map_url))?; + let file = ps + .file_fetcher + .fetch(&import_map_specifier, &mut Permissions::allow_all()) + .await + .context(format!( + "Unable to load '{}' import map", + import_map_specifier + ))?; + + Some((import_map_specifier, file.source.to_string())) + } + }; let metadata = Metadata { argv: flags.argv.clone(), unstable: flags.unstable, @@ -111,6 +135,7 @@ pub fn create_standalone_binary( ca_stores: flags.ca_stores, ca_data, entrypoint, + maybe_import_map, }; let mut metadata = serde_json::to_string(&metadata)?.as_bytes().to_vec(); @@ -233,7 +258,7 @@ pub fn compile_to_runtime_flags( coverage_dir: flags.coverage_dir.clone(), enable_testing_features: false, ignore: vec![], - import_map_path: None, + import_map_path: flags.import_map_path.clone(), inspect_brk: None, inspect: None, location: flags.location.clone(), |