mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 16:19:12 -05:00
fix(compile): Support import maps (#13756)
This commit is contained in:
parent
4f07ee134d
commit
4fc9b5f3eb
6 changed files with 110 additions and 17 deletions
18
cli/main.rs
18
cli/main.rs
|
@ -396,19 +396,21 @@ async fn compile_command(
|
||||||
) -> Result<i32, AnyError> {
|
) -> Result<i32, AnyError> {
|
||||||
let debug = flags.log_level == Some(log::Level::Debug);
|
let debug = flags.log_level == Some(log::Level::Debug);
|
||||||
|
|
||||||
let run_flags =
|
let run_flags = tools::standalone::compile_to_runtime_flags(
|
||||||
tools::standalone::compile_to_runtime_flags(&flags, compile_flags.args)?;
|
&flags,
|
||||||
|
compile_flags.args.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let module_specifier = resolve_url_or_path(&compile_flags.source_file)?;
|
let module_specifier = resolve_url_or_path(&compile_flags.source_file)?;
|
||||||
let ps = ProcState::build(Arc::new(flags)).await?;
|
let ps = ProcState::build(Arc::new(flags)).await?;
|
||||||
let deno_dir = &ps.dir;
|
let deno_dir = &ps.dir;
|
||||||
|
|
||||||
let output = compile_flags.output.and_then(|output| {
|
let output = compile_flags.output.as_ref().and_then(|output| {
|
||||||
if fs_util::path_has_trailing_slash(&output) {
|
if fs_util::path_has_trailing_slash(output) {
|
||||||
let infer_file_name = infer_name_from_url(&module_specifier).map(PathBuf::from)?;
|
let infer_file_name = infer_name_from_url(&module_specifier).map(PathBuf::from)?;
|
||||||
Some(output.join(infer_file_name))
|
Some(output.join(infer_file_name))
|
||||||
} else {
|
} else {
|
||||||
Some(output)
|
Some(output.to_path_buf())
|
||||||
}
|
}
|
||||||
}).or_else(|| {
|
}).or_else(|| {
|
||||||
infer_name_from_url(&module_specifier).map(PathBuf::from)
|
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")
|
generic_error("There should only be one reference to ModuleGraph")
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
graph.valid().unwrap();
|
||||||
|
|
||||||
let eszip = eszip::EszipV2::from_graph(graph, Default::default())?;
|
let eszip = eszip::EszipV2::from_graph(graph, Default::default())?;
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
|
@ -441,7 +445,9 @@ async fn compile_command(
|
||||||
eszip,
|
eszip,
|
||||||
module_specifier.clone(),
|
module_specifier.clone(),
|
||||||
run_flags,
|
run_flags,
|
||||||
)?;
|
ps,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
info!("{} {}", colors::green("Emit"), output.display());
|
info!("{} {}", colors::green("Emit"), output.display());
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::flags::Flags;
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
use crate::proc_state::ProcState;
|
use crate::proc_state::ProcState;
|
||||||
use crate::version;
|
use crate::version;
|
||||||
|
use crate::ImportMapResolver;
|
||||||
use deno_core::anyhow::anyhow;
|
use deno_core::anyhow::anyhow;
|
||||||
use deno_core::anyhow::Context;
|
use deno_core::anyhow::Context;
|
||||||
use deno_core::error::type_error;
|
use deno_core::error::type_error;
|
||||||
|
@ -19,6 +20,7 @@ use deno_core::url::Url;
|
||||||
use deno_core::v8_set_flags;
|
use deno_core::v8_set_flags;
|
||||||
use deno_core::ModuleLoader;
|
use deno_core::ModuleLoader;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
|
use deno_graph::source::Resolver;
|
||||||
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
|
use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
|
||||||
use deno_runtime::deno_tls::create_default_root_cert_store;
|
use deno_runtime::deno_tls::create_default_root_cert_store;
|
||||||
use deno_runtime::deno_tls::rustls_pemfile;
|
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::MainWorker;
|
||||||
use deno_runtime::worker::WorkerOptions;
|
use deno_runtime::worker::WorkerOptions;
|
||||||
use deno_runtime::BootstrapOptions;
|
use deno_runtime::BootstrapOptions;
|
||||||
|
use import_map::parse_from_json;
|
||||||
use log::Level;
|
use log::Level;
|
||||||
use std::env::current_exe;
|
use std::env::current_exe;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
@ -51,6 +54,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 maybe_import_map: Option<(Url, String)>,
|
||||||
pub entrypoint: ModuleSpecifier,
|
pub entrypoint: ModuleSpecifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,17 +123,26 @@ fn u64_from_bytes(arr: &[u8]) -> Result<u64, AnyError> {
|
||||||
Ok(u64::from_be_bytes(*fixed_arr))
|
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 {
|
impl ModuleLoader for EmbeddedModuleLoader {
|
||||||
fn resolve(
|
fn resolve(
|
||||||
&self,
|
&self,
|
||||||
specifier: &str,
|
specifier: &str,
|
||||||
base: &str,
|
referrer: &str,
|
||||||
_is_main: bool,
|
_is_main: bool,
|
||||||
) -> Result<ModuleSpecifier, AnyError> {
|
) -> Result<ModuleSpecifier, AnyError> {
|
||||||
let resolve = deno_core::resolve_import(specifier, base)?;
|
let referrer = deno_core::resolve_url_or_path(referrer).unwrap();
|
||||||
Ok(resolve)
|
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(
|
fn load(
|
||||||
|
@ -143,7 +156,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||||
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 module = self
|
let module = self
|
||||||
.0
|
.eszip
|
||||||
.get_module(module_specifier.as_str())
|
.get_module(module_specifier.as_str())
|
||||||
.ok_or_else(|| type_error("Module not found"));
|
.ok_or_else(|| type_error("Module not found"));
|
||||||
|
|
||||||
|
@ -208,7 +221,16 @@ pub async fn run(
|
||||||
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(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(|_| {
|
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");
|
||||||
});
|
});
|
||||||
|
|
|
@ -450,6 +450,40 @@ fn standalone_runtime_flags() {
|
||||||
.contains("PermissionDenied: Requires write access"));
|
.contains("PermissionDenied: Requires write access"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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]
|
#[test]
|
||||||
// https://github.com/denoland/deno/issues/12670
|
// https://github.com/denoland/deno/issues/12670
|
||||||
fn skip_rebundle() {
|
fn skip_rebundle() {
|
||||||
|
|
5
cli/tests/testdata/standalone_import_map.json
vendored
Normal file
5
cli/tests/testdata/standalone_import_map.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"hello": "./001_hello.js"
|
||||||
|
}
|
||||||
|
}
|
1
cli/tests/testdata/standalone_import_map.ts
vendored
Normal file
1
cli/tests/testdata/standalone_import_map.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
import "hello";
|
|
@ -5,11 +5,17 @@ use crate::flags::CheckFlag;
|
||||||
use crate::flags::DenoSubcommand;
|
use crate::flags::DenoSubcommand;
|
||||||
use crate::flags::Flags;
|
use crate::flags::Flags;
|
||||||
use crate::flags::RunFlags;
|
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::bail;
|
||||||
|
use deno_core::anyhow::Context;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
|
use deno_core::url::Url;
|
||||||
use deno_graph::ModuleSpecifier;
|
use deno_graph::ModuleSpecifier;
|
||||||
use deno_runtime::deno_fetch::reqwest::Client;
|
use deno_runtime::deno_fetch::reqwest::Client;
|
||||||
|
use deno_runtime::permissions::Permissions;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::read;
|
use std::fs::read;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
@ -20,9 +26,6 @@ use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::standalone::Metadata;
|
|
||||||
use crate::standalone::MAGIC_TRAILER;
|
|
||||||
|
|
||||||
pub async fn get_base_binary(
|
pub async fn get_base_binary(
|
||||||
deno_dir: &DenoDir,
|
deno_dir: &DenoDir,
|
||||||
target: Option<String>,
|
target: Option<String>,
|
||||||
|
@ -85,11 +88,12 @@ async fn download_base_binary(
|
||||||
|
|
||||||
/// This functions creates a standalone deno binary by appending a bundle
|
/// This functions creates a standalone deno binary by appending a bundle
|
||||||
/// and magic trailer to the currently executing binary.
|
/// and magic trailer to the currently executing binary.
|
||||||
pub fn create_standalone_binary(
|
pub async fn create_standalone_binary(
|
||||||
mut original_bin: Vec<u8>,
|
mut original_bin: Vec<u8>,
|
||||||
eszip: eszip::EszipV2,
|
eszip: eszip::EszipV2,
|
||||||
entrypoint: ModuleSpecifier,
|
entrypoint: ModuleSpecifier,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
|
ps: ProcState,
|
||||||
) -> Result<Vec<u8>, AnyError> {
|
) -> Result<Vec<u8>, AnyError> {
|
||||||
let mut eszip_archive = eszip.into_bytes();
|
let mut eszip_archive = eszip.into_bytes();
|
||||||
|
|
||||||
|
@ -97,6 +101,26 @@ pub fn create_standalone_binary(
|
||||||
Some(ca_file) => Some(read(ca_file)?),
|
Some(ca_file) => Some(read(ca_file)?),
|
||||||
None => None,
|
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 {
|
let metadata = Metadata {
|
||||||
argv: flags.argv.clone(),
|
argv: flags.argv.clone(),
|
||||||
unstable: flags.unstable,
|
unstable: flags.unstable,
|
||||||
|
@ -111,6 +135,7 @@ pub fn create_standalone_binary(
|
||||||
ca_stores: flags.ca_stores,
|
ca_stores: flags.ca_stores,
|
||||||
ca_data,
|
ca_data,
|
||||||
entrypoint,
|
entrypoint,
|
||||||
|
maybe_import_map,
|
||||||
};
|
};
|
||||||
let mut metadata = serde_json::to_string(&metadata)?.as_bytes().to_vec();
|
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(),
|
coverage_dir: flags.coverage_dir.clone(),
|
||||||
enable_testing_features: false,
|
enable_testing_features: false,
|
||||||
ignore: vec![],
|
ignore: vec![],
|
||||||
import_map_path: None,
|
import_map_path: flags.import_map_path.clone(),
|
||||||
inspect_brk: None,
|
inspect_brk: None,
|
||||||
inspect: None,
|
inspect: None,
|
||||||
location: flags.location.clone(),
|
location: flags.location.clone(),
|
||||||
|
|
Loading…
Reference in a new issue