mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -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> {
|
||||
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());
|
||||
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
|
|
|
@ -450,6 +450,40 @@ fn standalone_runtime_flags() {
|
|||
.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]
|
||||
// https://github.com/denoland/deno/issues/12670
|
||||
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::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(),
|
||||
|
|
Loading…
Reference in a new issue