1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-25 16:49:18 -05:00

feat(core): allow to specify entry point for snapshotted ES modules (#17771)

This commit adds "ExtensionBuilder::esm_entry_point()" function that
allows to specify which of the extension files should be treated as an
entry point. If the entry point is not provided all modules are loaded 
and evaluated, but if it is provided then only the entry point is explicitly
loaded and evaluated.

Co-authored-by: Leo Kettmeir <crowlkats@toaxl.com>
This commit is contained in:
Bartek Iwańczuk 2023-02-14 00:43:53 +01:00 committed by GitHub
parent f917d2e2c1
commit bd6ddd9b46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 30 deletions

View file

@ -43,6 +43,7 @@ impl OpDecl {
pub struct Extension {
js_files: Option<Vec<ExtensionFileSource>>,
esm_files: Option<Vec<ExtensionFileSource>>,
esm_entry_point: Option<&'static str>,
ops: Option<Vec<OpDecl>>,
opstate_fn: Option<Box<OpStateFn>>,
middleware_fn: Option<Box<OpMiddlewareFn>>,
@ -100,6 +101,10 @@ impl Extension {
}
}
pub fn get_esm_entry_point(&self) -> Option<&'static str> {
self.esm_entry_point
}
/// Called at JsRuntime startup to initialize ops in the isolate.
pub fn init_ops(&mut self) -> Option<Vec<OpDecl>> {
// TODO(@AaronO): maybe make op registration idempotent
@ -158,6 +163,7 @@ impl Extension {
pub struct ExtensionBuilder {
js: Vec<ExtensionFileSource>,
esm: Vec<ExtensionFileSource>,
esm_entry_point: Option<&'static str>,
ops: Vec<OpDecl>,
state: Option<Box<OpStateFn>>,
middleware: Option<Box<OpMiddlewareFn>>,
@ -197,6 +203,11 @@ impl ExtensionBuilder {
self
}
pub fn esm_entry_point(&mut self, entry_point: &'static str) -> &mut Self {
self.esm_entry_point = Some(entry_point);
self
}
pub fn ops(&mut self, ops: Vec<OpDecl>) -> &mut Self {
self.ops.extend(ops);
self
@ -234,6 +245,7 @@ impl ExtensionBuilder {
Extension {
js_files,
esm_files,
esm_entry_point: self.esm_entry_point.take(),
ops,
opstate_fn: self.state.take(),
middleware_fn: self.middleware.take(),

View file

@ -275,21 +275,27 @@ pub struct NoopModuleLoader;
impl ModuleLoader for NoopModuleLoader {
fn resolve(
&self,
_specifier: &str,
_referrer: &str,
specifier: &str,
referrer: &str,
_kind: ResolutionKind,
) -> Result<ModuleSpecifier, Error> {
Err(generic_error("Module loading is not supported"))
Err(generic_error(
format!("Module loading is not supported; attempted to resolve: \"{specifier}\" from \"{referrer}\"")
))
}
fn load(
&self,
_module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<ModuleSpecifier>,
module_specifier: &ModuleSpecifier,
maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool,
) -> Pin<Box<ModuleSourceFuture>> {
async { Err(generic_error("Module loading is not supported")) }
.boxed_local()
let err = generic_error(
format!(
"Module loading is not supported; attempted to load: \"{module_specifier}\" from \"{maybe_referrer:?}\"",
)
);
async move { Err(err) }.boxed_local()
}
}
@ -2720,14 +2726,20 @@ if (import.meta.url != 'file:///main_with_code.js') throw Error();
.resolve("file://foo", "file://bar", ResolutionKind::Import)
.err()
.map(|e| e.to_string()),
Some("Module loading is not supported".to_string())
Some(
"Module loading is not supported; attempted to resolve: \"file://foo\" from \"file://bar\""
.to_string()
)
);
assert_eq!(
loader
.resolve("file://foo", "internal:bar", ResolutionKind::Import)
.err()
.map(|e| e.to_string()),
Some("Module loading is not supported".to_string())
Some(
"Module loading is not supported; attempted to resolve: \"file://foo\" from \"internal:bar\""
.to_string()
)
);
assert_eq!(
resolve_helper(

View file

@ -829,26 +829,39 @@ impl JsRuntime {
/// Initializes JS of provided Extensions in the given realm
fn init_extension_js(&mut self, realm: &JsRealm) -> Result<(), Error> {
fn load_and_evaluate_module(
runtime: &mut JsRuntime,
file_source: &ExtensionFileSource,
) -> Result<(), Error> {
futures::executor::block_on(async {
let id = runtime
.load_side_module(
&ModuleSpecifier::parse(&file_source.specifier)?,
None,
)
.await?;
let receiver = runtime.mod_evaluate(id);
runtime.run_event_loop(false).await?;
receiver.await?
})
.with_context(|| format!("Couldn't execute '{}'", file_source.specifier))
}
// Take extensions to avoid double-borrow
let extensions = std::mem::take(&mut self.extensions_with_js);
for ext in &extensions {
{
let esm_files = ext.get_esm_sources();
for file_source in esm_files {
futures::executor::block_on(async {
let id = self
.load_side_module(
&ModuleSpecifier::parse(&file_source.specifier)?,
None,
)
.await?;
let receiver = self.mod_evaluate(id);
self.run_event_loop(false).await?;
receiver.await?
})
.with_context(|| {
format!("Couldn't execute '{}'", file_source.specifier)
})?;
if let Some(entry_point) = ext.get_esm_entry_point() {
let file_source = esm_files
.iter()
.find(|file| file.specifier == entry_point)
.unwrap();
load_and_evaluate_module(self, file_source)?;
} else {
for file_source in esm_files {
load_and_evaluate_module(self, file_source)?;
}
}
}
@ -1770,7 +1783,11 @@ impl JsRuntime {
.map(|handle| v8::Local::new(tc_scope, handle))
.expect("ModuleInfo not found");
let mut status = module.get_status();
assert_eq!(status, v8::ModuleStatus::Instantiated);
assert_eq!(
status,
v8::ModuleStatus::Instantiated,
"Module not instantiated {id}"
);
let (sender, receiver) = oneshot::channel();
@ -4974,7 +4991,7 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({
_is_dyn_import: bool,
) -> Pin<Box<ModuleSourceFuture>> {
let source = r#"
// This module doesn't really exist, just verifying that we'll get
// This module doesn't really exist, just verifying that we'll get
// an error when specifier starts with "internal:".
import { core } from "internal:core.js";
"#;

View file

@ -22,6 +22,7 @@ pub struct CreateSnapshotOptions {
}
pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) {
let start = std::time::Instant::now();
let js_runtime = JsRuntime::new(RuntimeOptions {
will_snapshot: true,
startup_snapshot: create_snapshot_options.startup_snapshot,
@ -33,7 +34,12 @@ pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) {
let snapshot = js_runtime.snapshot();
let snapshot_slice: &[u8] = &snapshot;
println!("Snapshot size: {}", snapshot_slice.len());
println!(
"Snapshot size: {}, took {}s ({})",
snapshot_slice.len(),
start.elapsed().as_secs_f64(),
create_snapshot_options.snapshot_path.display()
);
let maybe_compressed_snapshot: Box<dyn AsRef<[u8]>> =
if let Some(compression_cb) = create_snapshot_options.compression_cb {
@ -47,7 +53,12 @@ pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) {
(compression_cb)(&mut vec, snapshot_slice);
println!("Snapshot compressed size: {}", vec.len());
println!(
"Snapshot compressed size: {}, took {}s ({})",
vec.len(),
start.elapsed().as_secs_f64(),
create_snapshot_options.snapshot_path.display()
);
Box::new(vec)
} else {
@ -60,8 +71,9 @@ pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) {
)
.unwrap();
println!(
"Snapshot written to: {} ",
create_snapshot_options.snapshot_path.display()
"Snapshot written to: {}, took: {}s",
create_snapshot_options.snapshot_path.display(),
start.elapsed().as_secs_f64()
);
}