summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2023-05-04 01:44:59 +0100
committerGitHub <noreply@github.com>2023-05-04 02:44:59 +0200
commit7a8bb3b611f02b272b1c19b6f3d8a85b099ca317 (patch)
tree04d37bb0f8c3fc719b3494114a054f5439733e7a
parente3276fbb71093faf4e8850f68ed2e080a9bda222 (diff)
fix(core): allow esm extensions not included in snapshot (#18980)
Fixes #18979. This changes the predicate for allowing `ext:` specifier resolution from `snapshot_loaded_and_not_snapshotting` to `ext_resolution_allowed` which is only set to true during the extension module loading phase. Module loaders as used in core are now declared as `ExtModuleLoader` rather than `dyn ModuleLoader`.
-rw-r--r--bench_util/js_runtime.rs4
-rw-r--r--cli/tests/testdata/run/extension_dynamic_import.ts.out2
-rw-r--r--core/bindings.rs91
-rw-r--r--core/extensions.rs10
-rw-r--r--core/modules.rs276
-rw-r--r--core/runtime.rs136
-rw-r--r--runtime/examples/hello_runtime.js1
-rw-r--r--runtime/examples/hello_runtime.rs57
-rw-r--r--runtime/examples/hello_runtime_bootstrap.js5
9 files changed, 219 insertions, 363 deletions
diff --git a/bench_util/js_runtime.rs b/bench_util/js_runtime.rs
index 57085ef96..a12e6ca62 100644
--- a/bench_util/js_runtime.rs
+++ b/bench_util/js_runtime.rs
@@ -10,9 +10,7 @@ use crate::profiling::is_profiling;
pub fn create_js_runtime(setup: impl FnOnce() -> Vec<Extension>) -> JsRuntime {
JsRuntime::new(RuntimeOptions {
extensions: setup(),
- module_loader: Some(
- std::rc::Rc::new(deno_core::ExtModuleLoader::default()),
- ),
+ module_loader: None,
..Default::default()
})
}
diff --git a/cli/tests/testdata/run/extension_dynamic_import.ts.out b/cli/tests/testdata/run/extension_dynamic_import.ts.out
index 18b05ea47..081318960 100644
--- a/cli/tests/testdata/run/extension_dynamic_import.ts.out
+++ b/cli/tests/testdata/run/extension_dynamic_import.ts.out
@@ -1,4 +1,4 @@
-error: Uncaught TypeError: Cannot load extension module from external code
+error: Uncaught (in promise) TypeError: Cannot load extension module from external code
await import("ext:runtime/01_errors.js");
^
at [WILDCARD]/extension_dynamic_import.ts:1:1
diff --git a/core/bindings.rs b/core/bindings.rs
index 2d9c91461..1437bc657 100644
--- a/core/bindings.rs
+++ b/core/bindings.rs
@@ -10,7 +10,6 @@ use crate::error::is_instance_of_error;
use crate::error::JsStackFrame;
use crate::modules::get_asserted_module_type_from_assertions;
use crate::modules::parse_import_assertions;
-use crate::modules::resolve_helper;
use crate::modules::validate_import_assertions;
use crate::modules::ImportAssertionsKind;
use crate::modules::ModuleMap;
@@ -259,46 +258,43 @@ pub fn host_import_module_dynamically_callback<'s>(
.unwrap()
.to_rust_string_lossy(scope);
- let is_ext_module = specifier_str.starts_with("ext:");
let resolver = v8::PromiseResolver::new(scope).unwrap();
let promise = resolver.get_promise(scope);
- if !is_ext_module {
- let assertions = parse_import_assertions(
- scope,
- import_assertions,
- ImportAssertionsKind::DynamicImport,
- );
+ let assertions = parse_import_assertions(
+ scope,
+ import_assertions,
+ ImportAssertionsKind::DynamicImport,
+ );
- {
- let tc_scope = &mut v8::TryCatch::new(scope);
- validate_import_assertions(tc_scope, &assertions);
- if tc_scope.has_caught() {
- let e = tc_scope.exception().unwrap();
- resolver.reject(tc_scope, e);
- }
+ {
+ let tc_scope = &mut v8::TryCatch::new(scope);
+ validate_import_assertions(tc_scope, &assertions);
+ if tc_scope.has_caught() {
+ let e = tc_scope.exception().unwrap();
+ resolver.reject(tc_scope, e);
}
- let asserted_module_type =
- get_asserted_module_type_from_assertions(&assertions);
+ }
+ let asserted_module_type =
+ get_asserted_module_type_from_assertions(&assertions);
- let resolver_handle = v8::Global::new(scope, resolver);
- {
- let state_rc = JsRuntime::state(scope);
- let module_map_rc = JsRuntime::module_map(scope);
+ let resolver_handle = v8::Global::new(scope, resolver);
+ {
+ let state_rc = JsRuntime::state(scope);
+ let module_map_rc = JsRuntime::module_map(scope);
- debug!(
- "dyn_import specifier {} referrer {} ",
- specifier_str, referrer_name_str
- );
- ModuleMap::load_dynamic_import(
- module_map_rc,
- &specifier_str,
- &referrer_name_str,
- asserted_module_type,
- resolver_handle,
- );
- state_rc.borrow_mut().notify_new_dynamic_import();
- }
+ debug!(
+ "dyn_import specifier {} referrer {} ",
+ specifier_str, referrer_name_str
+ );
+ ModuleMap::load_dynamic_import(
+ module_map_rc,
+ &specifier_str,
+ &referrer_name_str,
+ asserted_module_type,
+ resolver_handle,
+ );
+ state_rc.borrow_mut().notify_new_dynamic_import();
}
// Map errors from module resolution (not JS errors from module execution) to
// ones rethrown from this scope, so they include the call stack of the
@@ -311,16 +307,6 @@ pub fn host_import_module_dynamically_callback<'s>(
let promise = promise.catch(scope, map_err).unwrap();
- if is_ext_module {
- let message = v8::String::new_external_onebyte_static(
- scope,
- b"Cannot load extension module from external code",
- )
- .unwrap();
- let exception = v8::Exception::type_error(scope, message);
- resolver.reject(scope, exception);
- }
-
Some(promise)
}
@@ -375,13 +361,7 @@ fn import_meta_resolve(
url_prop.to_rust_string_lossy(scope)
};
let module_map_rc = JsRuntime::module_map(scope);
- let (loader, snapshot_loaded_and_not_snapshotting) = {
- let module_map = module_map_rc.borrow();
- (
- module_map.loader.clone(),
- module_map.snapshot_loaded_and_not_snapshotting,
- )
- };
+ let loader = module_map_rc.borrow().loader.clone();
let specifier_str = specifier.to_rust_string_lossy(scope);
if specifier_str.starts_with("npm:") {
@@ -389,13 +369,8 @@ fn import_meta_resolve(
return;
}
- match resolve_helper(
- snapshot_loaded_and_not_snapshotting,
- loader,
- &specifier_str,
- &referrer,
- ResolutionKind::DynamicImport,
- ) {
+ match loader.resolve(&specifier_str, &referrer, ResolutionKind::DynamicImport)
+ {
Ok(resolved) => {
let resolved_val = serde_v8::to_v8(scope, resolved.as_str()).unwrap();
rv.set(resolved_val);
diff --git a/core/extensions.rs b/core/extensions.rs
index a8b52eb3b..ba151da3d 100644
--- a/core/extensions.rs
+++ b/core/extensions.rs
@@ -471,6 +471,16 @@ impl Extension {
pub fn disable(self) -> Self {
self.enabled(false)
}
+
+ pub(crate) fn find_esm(
+ &self,
+ specifier: &str,
+ ) -> Option<&ExtensionFileSource> {
+ self
+ .get_esm_sources()?
+ .iter()
+ .find(|s| s.specifier == specifier)
+ }
}
// Provides a convenient builder pattern to declare Extensions
diff --git a/core/modules.rs b/core/modules.rs
index c63c4dd30..bc795de5c 100644
--- a/core/modules.rs
+++ b/core/modules.rs
@@ -9,6 +9,7 @@ use crate::module_specifier::ModuleSpecifier;
use crate::resolve_import;
use crate::resolve_url;
use crate::snapshot_util::SnapshottedData;
+use crate::Extension;
use crate::JsRuntime;
use crate::OpState;
use anyhow::Error;
@@ -379,25 +380,6 @@ impl ModuleLoader for NoopModuleLoader {
}
}
-/// Helper function, that calls into `loader.resolve()`, but denies resolution
-/// of `ext` scheme if we are running with a snapshot loaded and not
-/// creating a snapshot
-pub(crate) fn resolve_helper(
- snapshot_loaded_and_not_snapshotting: bool,
- loader: Rc<dyn ModuleLoader>,
- specifier: &str,
- referrer: &str,
- kind: ResolutionKind,
-) -> Result<ModuleSpecifier, Error> {
- if snapshot_loaded_and_not_snapshotting && specifier.starts_with("ext:") {
- return Err(generic_error(
- "Cannot load extension module from external code",
- ));
- }
-
- loader.resolve(specifier, referrer, kind)
-}
-
/// Function that can be passed to the `ExtModuleLoader` that allows to
/// transpile sources before passing to V8.
pub type ExtModuleLoaderCb =
@@ -405,7 +387,8 @@ pub type ExtModuleLoaderCb =
pub struct ExtModuleLoader {
module_loader: Rc<dyn ModuleLoader>,
- esm_sources: Vec<ExtensionFileSource>,
+ extensions: Rc<RefCell<Vec<Extension>>>,
+ ext_resolution_allowed: RefCell<bool>,
used_esm_sources: RefCell<HashMap<String, bool>>,
maybe_load_callback: Option<ExtModuleLoaderCb>,
}
@@ -414,7 +397,8 @@ impl Default for ExtModuleLoader {
fn default() -> Self {
Self {
module_loader: Rc::new(NoopModuleLoader),
- esm_sources: vec![],
+ extensions: Default::default(),
+ ext_resolution_allowed: Default::default(),
used_esm_sources: RefCell::new(HashMap::default()),
maybe_load_callback: None,
}
@@ -424,70 +408,46 @@ impl Default for ExtModuleLoader {
impl ExtModuleLoader {
pub fn new(
module_loader: Option<Rc<dyn ModuleLoader>>,
- esm_sources: Vec<ExtensionFileSource>,
+ extensions: Rc<RefCell<Vec<Extension>>>,
maybe_load_callback: Option<ExtModuleLoaderCb>,
) -> Self {
- let used_esm_sources: HashMap<String, bool> = esm_sources
+ let used_esm_sources: HashMap<String, bool> = extensions
+ .borrow()
.iter()
+ .flat_map(|e| e.get_esm_sources())
+ .flatten()
.map(|file_source| (file_source.specifier.to_string(), false))
.collect();
ExtModuleLoader {
module_loader: module_loader.unwrap_or_else(|| Rc::new(NoopModuleLoader)),
- esm_sources,
+ extensions,
+ ext_resolution_allowed: Default::default(),
used_esm_sources: RefCell::new(used_esm_sources),
maybe_load_callback,
}
}
-}
-
-impl Drop for ExtModuleLoader {
- fn drop(&mut self) {
- let used_esm_sources = self.used_esm_sources.get_mut();
- let unused_modules: Vec<_> = used_esm_sources
- .iter()
- .filter(|(_s, v)| !*v)
- .map(|(s, _)| s)
- .collect();
-
- if !unused_modules.is_empty() {
- let mut msg =
- "Following modules were passed to ExtModuleLoader but never used:\n"
- .to_string();
- for m in unused_modules {
- msg.push_str(" - ");
- msg.push_str(m);
- msg.push('\n');
- }
- panic!("{}", msg);
- }
- }
-}
-impl ModuleLoader for ExtModuleLoader {
- fn resolve(
+ pub fn resolve(
&self,
specifier: &str,
referrer: &str,
kind: ResolutionKind,
) -> Result<ModuleSpecifier, Error> {
- if let Ok(url_specifier) = ModuleSpecifier::parse(specifier) {
- if url_specifier.scheme() == "ext" {
- let referrer_specifier = ModuleSpecifier::parse(referrer).ok();
- if referrer == "." || referrer_specifier.unwrap().scheme() == "ext" {
- return Ok(url_specifier);
- } else {
- return Err(generic_error(
- "Cannot load extension module from external code",
- ));
- };
+ if specifier.starts_with("ext:") {
+ if !referrer.starts_with("ext:") && referrer != "."
+ || !*self.ext_resolution_allowed.borrow()
+ {
+ return Err(generic_error(
+ "Cannot load extension module from external code",
+ ));
}
+ return Ok(ModuleSpecifier::parse(specifier)?);
}
-
self.module_loader.resolve(specifier, referrer, kind)
}
- fn load(
+ pub fn load(
&self,
module_specifier: &ModuleSpecifier,
maybe_referrer: Option<&ModuleSpecifier>,
@@ -502,10 +462,10 @@ impl ModuleLoader for ExtModuleLoader {
}
let specifier = module_specifier.to_string();
- let maybe_file_source = self
- .esm_sources
+ let extensions = self.extensions.borrow();
+ let maybe_file_source = extensions
.iter()
- .find(|file_source| file_source.specifier == module_specifier.as_str());
+ .find_map(|e| e.find_esm(module_specifier.as_str()));
if let Some(file_source) = maybe_file_source {
{
@@ -538,7 +498,7 @@ impl ModuleLoader for ExtModuleLoader {
.boxed_local()
}
- fn prepare_load(
+ pub fn prepare_load(
&self,
op_state: Rc<RefCell<OpState>>,
module_specifier: &ModuleSpecifier,
@@ -556,6 +516,37 @@ impl ModuleLoader for ExtModuleLoader {
is_dyn_import,
)
}
+
+ pub fn allow_ext_resolution(&self) {
+ *self.ext_resolution_allowed.borrow_mut() = true;
+ }
+
+ pub fn disallow_ext_resolution(&self) {
+ *self.ext_resolution_allowed.borrow_mut() = false;
+ }
+}
+
+impl Drop for ExtModuleLoader {
+ fn drop(&mut self) {
+ let used_esm_sources = self.used_esm_sources.get_mut();
+ let unused_modules: Vec<_> = used_esm_sources
+ .iter()
+ .filter(|(_s, v)| !*v)
+ .map(|(s, _)| s)
+ .collect();
+
+ if !unused_modules.is_empty() {
+ let mut msg =
+ "Following modules were passed to ExtModuleLoader but never used:\n"
+ .to_string();
+ for m in unused_modules {
+ msg.push_str(" - ");
+ msg.push_str(m);
+ msg.push('\n');
+ }
+ panic!("{}", msg);
+ }
+ }
}
/// Basic file system module loader.
@@ -643,8 +634,7 @@ pub(crate) struct RecursiveModuleLoad {
// These three fields are copied from `module_map_rc`, but they are cloned
// ahead of time to avoid already-borrowed errors.
op_state: Rc<RefCell<OpState>>,
- loader: Rc<dyn ModuleLoader>,
- snapshot_loaded_and_not_snapshotting: bool,
+ loader: Rc<ExtModuleLoader>,
}
impl RecursiveModuleLoad {
@@ -700,9 +690,6 @@ impl RecursiveModuleLoad {
init,
state: LoadState::Init,
module_map_rc: module_map_rc.clone(),
- snapshot_loaded_and_not_snapshotting: module_map_rc
- .borrow()
- .snapshot_loaded_and_not_snapshotting,
op_state,
loader,
pending: FuturesUnordered::new(),
@@ -731,29 +718,17 @@ impl RecursiveModuleLoad {
fn resolve_root(&self) -> Result<ModuleSpecifier, Error> {
match self.init {
- LoadInit::Main(ref specifier) => resolve_helper(
- self.snapshot_loaded_and_not_snapshotting,
- self.loader.clone(),
- specifier,
- ".",
- ResolutionKind::MainModule,
- ),
- LoadInit::Side(ref specifier) => resolve_helper(
- self.snapshot_loaded_and_not_snapshotting,
- self.loader.clone(),
- specifier,
- ".",
- ResolutionKind::Import,
- ),
- LoadInit::DynamicImport(ref specifier, ref referrer, _) => {
- resolve_helper(
- self.snapshot_loaded_and_not_snapshotting,
- self.loader.clone(),
- specifier,
- referrer,
- ResolutionKind::DynamicImport,
- )
+ LoadInit::Main(ref specifier) => {
+ self
+ .loader
+ .resolve(specifier, ".", ResolutionKind::MainModule)
+ }
+ LoadInit::Side(ref specifier) => {
+ self.loader.resolve(specifier, ".", ResolutionKind::Import)
}
+ LoadInit::DynamicImport(ref specifier, ref referrer, _) => self
+ .loader
+ .resolve(specifier, referrer, ResolutionKind::DynamicImport),
}
}
@@ -762,29 +737,21 @@ impl RecursiveModuleLoad {
let (module_specifier, maybe_referrer) = match self.init {
LoadInit::Main(ref specifier) => {
- let spec = resolve_helper(
- self.snapshot_loaded_and_not_snapshotting,
- self.loader.clone(),
- specifier,
- ".",
- ResolutionKind::MainModule,
- )?;
+ let spec =
+ self
+ .loader
+ .resolve(specifier, ".", ResolutionKind::MainModule)?;
(spec, None)
}
LoadInit::Side(ref specifier) => {
- let spec = resolve_helper(
- self.snapshot_loaded_and_not_snapshotting,
- self.loader.clone(),
- specifier,
- ".",
- ResolutionKind::Import,
- )?;
+ let spec =
+ self
+ .loader
+ .resolve(specifier, ".", ResolutionKind::Import)?;
(spec, None)
}
LoadInit::DynamicImport(ref specifier, ref referrer, _) => {
- let spec = resolve_helper(
- self.snapshot_loaded_and_not_snapshotting,
- self.loader.clone(),
+ let spec = self.loader.resolve(
specifier,
referrer,
ResolutionKind::DynamicImport,
@@ -1093,7 +1060,7 @@ pub(crate) struct ModuleMap {
pub(crate) next_load_id: ModuleLoadId,
// Handling of futures for loading module sources
- pub loader: Rc<dyn ModuleLoader>,
+ pub loader: Rc<ExtModuleLoader>,
op_state: Rc<RefCell<OpState>>,
pub(crate) dynamic_import_map:
HashMap<ModuleLoadId, v8::Global<v8::PromiseResolver>>,
@@ -1105,8 +1072,6 @@ pub(crate) struct ModuleMap {
// This store is used temporarly, to forward parsed JSON
// value from `new_json_module` to `json_module_evaluation_steps`
json_value_store: HashMap<v8::Global<v8::Module>, v8::Global<v8::Value>>,
-
- pub(crate) snapshot_loaded_and_not_snapshotting: bool,
}
impl ModuleMap {
@@ -1381,9 +1346,8 @@ impl ModuleMap {
}
pub(crate) fn new(
- loader: Rc<dyn ModuleLoader>,
+ loader: Rc<ExtModuleLoader>,
op_state: Rc<RefCell<OpState>>,
- snapshot_loaded_and_not_snapshotting: bool,
) -> ModuleMap {
Self {
handles: vec![],
@@ -1397,7 +1361,6 @@ impl ModuleMap {
preparing_dynamic_imports: FuturesUnordered::new(),
pending_dynamic_imports: FuturesUnordered::new(),
json_value_store: HashMap::new(),
- snapshot_loaded_and_not_snapshotting,
}
}
@@ -1526,9 +1489,7 @@ impl ModuleMap {
return Err(ModuleError::Exception(exception));
}
- let module_specifier = match resolve_helper(
- self.snapshot_loaded_and_not_snapshotting,
- self.loader.clone(),
+ let module_specifier = match self.loader.resolve(
&import_specifier,
name.as_ref(),
if is_dynamic_import {
@@ -1717,20 +1678,9 @@ impl ModuleMap {
.dynamic_import_map
.insert(load.id, resolver_handle);
- let (loader, snapshot_loaded_and_not_snapshotting) = {
- let module_map = module_map_rc.borrow();
- (
- module_map.loader.clone(),
- module_map.snapshot_loaded_and_not_snapshotting,
- )
- };
- let resolve_result = resolve_helper(
- snapshot_loaded_and_not_snapshotting,
- loader,
- specifier,
- referrer,
- ResolutionKind::DynamicImport,
- );
+ let loader = module_map_rc.borrow().loader.clone();
+ let resolve_result =
+ loader.resolve(specifier, referrer, ResolutionKind::DynamicImport);
let fut = match resolve_result {
Ok(module_specifier) => {
if module_map_rc
@@ -1764,14 +1714,10 @@ impl ModuleMap {
referrer: &str,
import_assertions: HashMap<String, String>,
) -> Option<v8::Local<'s, v8::Module>> {
- let resolved_specifier = resolve_helper(
- self.snapshot_loaded_and_not_snapshotting,
- self.loader.clone(),
- specifier,
- referrer,
- ResolutionKind::Import,
- )
- .expect("Module should have been already resolved");
+ let resolved_specifier = self
+ .loader
+ .resolve(specifier, referrer, ResolutionKind::Import)
+ .expect("Module should have been already resolved");
let module_type =
get_asserted_module_type_from_assertions(&import_assertions);
@@ -3042,48 +2988,34 @@ if (import.meta.url != 'file:///main_with_code.js') throw Error();
}
#[test]
- fn ext_module_loader() {
+ fn ext_resolution() {
+ let loader = ExtModuleLoader::default();
+ loader.allow_ext_resolution();
+ loader
+ .resolve("ext:core.js", "ext:referrer.js", ResolutionKind::Import)
+ .unwrap();
+ loader
+ .resolve("ext:core.js", ".", ResolutionKind::Import)
+ .unwrap();
+ }
+
+ #[test]
+ fn ext_resolution_failure() {
let loader = ExtModuleLoader::default();
- assert!(loader
- .resolve("ext:foo", "ext:bar", ResolutionKind::Import)
- .is_ok());
+ loader.allow_ext_resolution();
assert_eq!(
loader
- .resolve("ext:foo", "file://bar", ResolutionKind::Import)
+ .resolve("ext:core.js", "file://bar", ResolutionKind::Import,)
.err()
.map(|e| e.to_string()),
Some("Cannot load extension module from external code".to_string())
);
+ loader.disallow_ext_resolution();
assert_eq!(
loader
- .resolve("file://foo", "file://bar", ResolutionKind::Import)
+ .resolve("ext:core.js", "ext:referrer.js", ResolutionKind::Import,)
.err()
.map(|e| e.to_string()),
- Some(
- "Module loading is not supported; attempted to resolve: \"file://foo\" from \"file://bar\""
- .to_string()
- )
- );
- assert_eq!(
- loader
- .resolve("file://foo", "ext:bar", ResolutionKind::Import)
- .err()
- .map(|e| e.to_string()),
- Some(
- "Module loading is not supported; attempted to resolve: \"file://foo\" from \"ext:bar\""
- .to_string()
- )
- );
- assert_eq!(
- resolve_helper(
- true,
- Rc::new(loader),
- "ext:core.js",
- "file://bar",
- ResolutionKind::Import,
- )
- .err()
- .map(|e| e.to_string()),
Some("Cannot load extension module from external code".to_string())
);
}
diff --git a/core/runtime.rs b/core/runtime.rs
index 9676ce571..1cbefb6fe 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -132,7 +132,7 @@ pub struct JsRuntime {
v8_isolate: Option<v8::OwnedIsolate>,
snapshot_options: snapshot_util::SnapshotOptions,
allocations: IsolateAllocations,
- extensions: Vec<Extension>,
+ extensions: Rc<RefCell<Vec<Extension>>>,
event_loop_middlewares: Vec<Box<OpEventLoopFn>>,
// Marks if this is considered the top-level runtime. Used only be inspector.
is_main: bool,
@@ -416,7 +416,7 @@ impl JsRuntime {
let global_context;
let mut maybe_snapshotted_data = None;
- let (mut isolate, snapshot_options) = if snapshot_options.will_snapshot() {
+ let mut isolate = if snapshot_options.will_snapshot() {
let snapshot_creator =
snapshot_util::create_snapshot_creator(refs, options.startup_snapshot);
let mut isolate = JsRuntime::setup_isolate(snapshot_creator);
@@ -433,7 +433,7 @@ impl JsRuntime {
global_context = v8::Global::new(scope, context);
}
- (isolate, snapshot_options)
+ isolate
} else {
#[cfg(not(target_env = "msvc"))]
let vtable: &'static v8::RustAllocatorVtable<
@@ -492,7 +492,7 @@ impl JsRuntime {
global_context = v8::Global::new(scope, context);
}
- (isolate, snapshot_options)
+ isolate
};
// SAFETY: this is first use of `isolate_ptr` so we are sure we're
@@ -521,61 +521,33 @@ impl JsRuntime {
None
};
- let loader = if snapshot_options != snapshot_util::SnapshotOptions::Load {
- let esm_sources = options
+ let loader = options
+ .module_loader
+ .unwrap_or_else(|| Rc::new(NoopModuleLoader));
+ #[cfg(feature = "include_js_files_for_snapshotting")]
+ if snapshot_options.will_snapshot() {
+ for source in options
.extensions
.iter()
- .flat_map(|ext| match ext.get_esm_sources() {
- Some(s) => s.to_owned(),
- None => vec![],
- })
- .collect::<Vec<ExtensionFileSource>>();
-
- #[cfg(feature = "include_js_files_for_snapshotting")]
- if snapshot_options != snapshot_util::SnapshotOptions::None {
- for source in &esm_sources {
- use crate::ExtensionFileSourceCode;
- if let ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(path) =
- &source.code
- {
- println!("cargo:rerun-if-changed={}", path.display())
- }
- }
- }
-
- #[cfg(feature = "include_js_files_for_snapshotting")]
+ .flat_map(|e| vec![e.get_esm_sources(), e.get_js_sources()])
+ .flatten()
+ .flatten()
{
- let js_sources = options
- .extensions
- .iter()
- .flat_map(|ext| match ext.get_js_sources() {
- Some(s) => s.to_owned(),
- None => vec![],
- })
- .collect::<Vec<ExtensionFileSource>>();
-
- if snapshot_options != snapshot_util::SnapshotOptions::None {
- for source in &js_sources {
- use crate::ExtensionFileSourceCode;
- if let ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(path) =
- &source.code
- {
- println!("cargo:rerun-if-changed={}", path.display())
- }
- }
+ use crate::ExtensionFileSourceCode;
+ if let ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(path) =
+ &source.code
+ {
+ println!("cargo:rerun-if-changed={}", path.display())
}
}
-
- Rc::new(crate::modules::ExtModuleLoader::new(
- options.module_loader,
- esm_sources,
- options.snapshot_module_load_cb,
- ))
- } else {
- options
- .module_loader
- .unwrap_or_else(|| Rc::new(NoopModuleLoader))
- };
+ }
+ let num_extensions = options.extensions.len();
+ let extensions = Rc::new(RefCell::new(options.extensions));
+ let ext_loader = Rc::new(crate::modules::ExtModuleLoader::new(
+ Some(loader.clone()),
+ extensions.clone(),
+ options.snapshot_module_load_cb,
+ ));
{
let mut state = state_rc.borrow_mut();
@@ -589,12 +561,8 @@ impl JsRuntime {
Self::STATE_DATA_OFFSET,
Rc::into_raw(state_rc.clone()) as *mut c_void,
);
-
- let module_map_rc = Rc::new(RefCell::new(ModuleMap::new(
- loader,
- op_state,
- snapshot_options == snapshot_util::SnapshotOptions::Load,
- )));
+ let module_map_rc =
+ Rc::new(RefCell::new(ModuleMap::new(ext_loader, op_state)));
if let Some(snapshotted_data) = maybe_snapshotted_data {
let scope =
&mut v8::HandleScope::with_context(&mut isolate, global_context);
@@ -610,10 +578,10 @@ impl JsRuntime {
v8_isolate: Some(isolate),
snapshot_options,
allocations: IsolateAllocations::default(),
- event_loop_middlewares: Vec::with_capacity(options.extensions.len()),
- extensions: options.extensions,
+ event_loop_middlewares: Vec::with_capacity(num_extensions),
+ extensions,
state: state_rc,
- module_map: Some(module_map_rc),
+ module_map: Some(module_map_rc.clone()),
is_main: options.is_main,
};
@@ -621,7 +589,9 @@ impl JsRuntime {
// available during the initialization process.
js_runtime.init_extension_ops().unwrap();
let realm = js_runtime.global_realm();
+ module_map_rc.borrow().loader.allow_ext_resolution();
js_runtime.init_extension_js(&realm).unwrap();
+ module_map_rc.borrow().loader.disallow_ext_resolution();
js_runtime
}
@@ -722,7 +692,21 @@ impl JsRuntime {
JsRealm::new(v8::Global::new(scope, context))
};
+ self
+ .module_map
+ .as_ref()
+ .unwrap()
+ .borrow()
+ .loader
+ .allow_ext_resolution();
self.init_extension_js(&realm)?;
+ self
+ .module_map
+ .as_ref()
+ .unwrap()
+ .borrow()
+ .loader
+ .disallow_ext_resolution();
Ok(realm)
}
@@ -790,7 +774,7 @@ impl JsRuntime {
// Take extensions to avoid double-borrow
let extensions = std::mem::take(&mut self.extensions);
- for ext in &extensions {
+ for ext in extensions.borrow().iter() {
{
if let Some(esm_files) = ext.get_esm_sources() {
if let Some(entry_point) = ext.get_esm_entry_point() {
@@ -863,23 +847,15 @@ impl JsRuntime {
/// Initializes ops of provided Extensions
fn init_extension_ops(&mut self) -> Result<(), Error> {
let op_state = self.op_state();
- // Take extensions to avoid double-borrow
- {
- let mut extensions: Vec<Extension> = std::mem::take(&mut self.extensions);
-
- // Setup state
- for e in extensions.iter_mut() {
- // ops are already registered during in bindings::initialize_context();
- e.init_state(&mut op_state.borrow_mut());
-
- // Setup event-loop middleware
- if let Some(middleware) = e.init_event_loop_middleware() {
- self.event_loop_middlewares.push(middleware);
- }
+ // Setup state
+ for e in self.extensions.borrow_mut().iter_mut() {
+ // ops are already registered during in bindings::initialize_context();
+ e.init_state(&mut op_state.borrow_mut());
+
+ // Setup event-loop middleware
+ if let Some(middleware) = e.init_event_loop_middleware() {
+ self.event_loop_middlewares.push(middleware);
}
-
- // Restore extensions
- self.extensions = extensions;
}
Ok(())
}
diff --git a/runtime/examples/hello_runtime.js b/runtime/examples/hello_runtime.js
index 066fa21d6..5b079d8d8 100644
--- a/runtime/examples/hello_runtime.js
+++ b/runtime/examples/hello_runtime.js
@@ -1,3 +1,4 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
console.log("Hello world!");
console.log(Deno);
+Extension.hello();
diff --git a/runtime/examples/hello_runtime.rs b/runtime/examples/hello_runtime.rs
index 2e930a03f..157a200f4 100644
--- a/runtime/examples/hello_runtime.rs
+++ b/runtime/examples/hello_runtime.rs
@@ -1,72 +1,31 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use deno_core::anyhow::Context;
use deno_core::error::AnyError;
use deno_core::FsModuleLoader;
-use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel;
-use deno_runtime::deno_web::BlobStore;
use deno_runtime::permissions::PermissionsContainer;
use deno_runtime::worker::MainWorker;
use deno_runtime::worker::WorkerOptions;
-use deno_runtime::BootstrapOptions;
use std::path::Path;
use std::rc::Rc;
-use std::sync::Arc;
-fn get_error_class_name(e: &AnyError) -> &'static str {
- deno_runtime::errors::get_error_class_name(e).unwrap_or("Error")
-}
+deno_core::extension!(hello_runtime, esm = ["hello_runtime_bootstrap.js"]);
#[tokio::main]
async fn main() -> Result<(), AnyError> {
- let module_loader = Rc::new(FsModuleLoader);
- let create_web_worker_cb = Arc::new(|_| {
- todo!("Web workers are not supported in the example");
- });
- let web_worker_event_cb = Arc::new(|_| {
- todo!("Web workers are not supported in the example");
- });
-
- let options = WorkerOptions {
- bootstrap: BootstrapOptions::default(),
- extensions: vec![],
- startup_snapshot: None,
- unsafely_ignore_certificate_errors: None,
- root_cert_store_provider: None,
- seed: None,
- source_map_getter: None,
- format_js_error_fn: None,
- web_worker_preload_module_cb: web_worker_event_cb.clone(),
- web_worker_pre_execute_module_cb: web_worker_event_cb,
- create_web_worker_cb,
- maybe_inspector_server: None,
- should_break_on_first_statement: false,
- should_wait_for_inspector_session: false,
- module_loader,
- node_fs: None,
- npm_resolver: None,
- get_error_class_fn: Some(&get_error_class_name),
- cache_storage_dir: None,
- origin_storage_dir: None,
- blob_store: BlobStore::default(),
- broadcast_channel: InMemoryBroadcastChannel::default(),
- shared_array_buffer_store: None,
- compiled_wasm_module_store: None,
- stdio: Default::default(),
- };
-
let js_path =
Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/hello_runtime.js");
let main_module = deno_core::resolve_path(
&js_path.to_string_lossy(),
- &std::env::current_dir().context("Unable to get CWD")?,
+ &std::env::current_dir()?,
)?;
- let permissions = PermissionsContainer::allow_all();
-
let mut worker = MainWorker::bootstrap_from_options(
main_module.clone(),
- permissions,
- options,
+ PermissionsContainer::allow_all(),
+ WorkerOptions {
+ module_loader: Rc::new(FsModuleLoader),
+ extensions: vec![hello_runtime::init_ops_and_esm()],
+ ..Default::default()
+ },
);
worker.execute_main_module(&main_module).await?;
worker.run_event_loop(false).await?;
diff --git a/runtime/examples/hello_runtime_bootstrap.js b/runtime/examples/hello_runtime_bootstrap.js
new file mode 100644
index 000000000..759dde939
--- /dev/null
+++ b/runtime/examples/hello_runtime_bootstrap.js
@@ -0,0 +1,5 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+function hello() {
+ console.log("Hello from extension!");
+}
+globalThis.Extension = { hello };