mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
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`.
This commit is contained in:
parent
e3276fbb71
commit
7a8bb3b611
9 changed files with 221 additions and 365 deletions
|
@ -10,9 +10,7 @@ use crate::profiling::is_profiling;
|
||||||
pub fn create_js_runtime(setup: impl FnOnce() -> Vec<Extension>) -> JsRuntime {
|
pub fn create_js_runtime(setup: impl FnOnce() -> Vec<Extension>) -> JsRuntime {
|
||||||
JsRuntime::new(RuntimeOptions {
|
JsRuntime::new(RuntimeOptions {
|
||||||
extensions: setup(),
|
extensions: setup(),
|
||||||
module_loader: Some(
|
module_loader: None,
|
||||||
std::rc::Rc::new(deno_core::ExtModuleLoader::default()),
|
|
||||||
),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
await import("ext:runtime/01_errors.js");
|
||||||
^
|
^
|
||||||
at [WILDCARD]/extension_dynamic_import.ts:1:1
|
at [WILDCARD]/extension_dynamic_import.ts:1:1
|
||||||
|
|
|
@ -10,7 +10,6 @@ use crate::error::is_instance_of_error;
|
||||||
use crate::error::JsStackFrame;
|
use crate::error::JsStackFrame;
|
||||||
use crate::modules::get_asserted_module_type_from_assertions;
|
use crate::modules::get_asserted_module_type_from_assertions;
|
||||||
use crate::modules::parse_import_assertions;
|
use crate::modules::parse_import_assertions;
|
||||||
use crate::modules::resolve_helper;
|
|
||||||
use crate::modules::validate_import_assertions;
|
use crate::modules::validate_import_assertions;
|
||||||
use crate::modules::ImportAssertionsKind;
|
use crate::modules::ImportAssertionsKind;
|
||||||
use crate::modules::ModuleMap;
|
use crate::modules::ModuleMap;
|
||||||
|
@ -259,46 +258,43 @@ pub fn host_import_module_dynamically_callback<'s>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_rust_string_lossy(scope);
|
.to_rust_string_lossy(scope);
|
||||||
|
|
||||||
let is_ext_module = specifier_str.starts_with("ext:");
|
|
||||||
let resolver = v8::PromiseResolver::new(scope).unwrap();
|
let resolver = v8::PromiseResolver::new(scope).unwrap();
|
||||||
let promise = resolver.get_promise(scope);
|
let promise = resolver.get_promise(scope);
|
||||||
|
|
||||||
if !is_ext_module {
|
let assertions = parse_import_assertions(
|
||||||
let assertions = parse_import_assertions(
|
scope,
|
||||||
scope,
|
import_assertions,
|
||||||
import_assertions,
|
ImportAssertionsKind::DynamicImport,
|
||||||
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 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);
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"dyn_import specifier {} referrer {} ",
|
||||||
|
specifier_str, referrer_name_str
|
||||||
);
|
);
|
||||||
|
ModuleMap::load_dynamic_import(
|
||||||
{
|
module_map_rc,
|
||||||
let tc_scope = &mut v8::TryCatch::new(scope);
|
&specifier_str,
|
||||||
validate_import_assertions(tc_scope, &assertions);
|
&referrer_name_str,
|
||||||
if tc_scope.has_caught() {
|
asserted_module_type,
|
||||||
let e = tc_scope.exception().unwrap();
|
resolver_handle,
|
||||||
resolver.reject(tc_scope, e);
|
);
|
||||||
}
|
state_rc.borrow_mut().notify_new_dynamic_import();
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
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
|
// 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
|
// 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();
|
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)
|
Some(promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,13 +361,7 @@ fn import_meta_resolve(
|
||||||
url_prop.to_rust_string_lossy(scope)
|
url_prop.to_rust_string_lossy(scope)
|
||||||
};
|
};
|
||||||
let module_map_rc = JsRuntime::module_map(scope);
|
let module_map_rc = JsRuntime::module_map(scope);
|
||||||
let (loader, snapshot_loaded_and_not_snapshotting) = {
|
let loader = module_map_rc.borrow().loader.clone();
|
||||||
let module_map = module_map_rc.borrow();
|
|
||||||
(
|
|
||||||
module_map.loader.clone(),
|
|
||||||
module_map.snapshot_loaded_and_not_snapshotting,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let specifier_str = specifier.to_rust_string_lossy(scope);
|
let specifier_str = specifier.to_rust_string_lossy(scope);
|
||||||
|
|
||||||
if specifier_str.starts_with("npm:") {
|
if specifier_str.starts_with("npm:") {
|
||||||
|
@ -389,13 +369,8 @@ fn import_meta_resolve(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match resolve_helper(
|
match loader.resolve(&specifier_str, &referrer, ResolutionKind::DynamicImport)
|
||||||
snapshot_loaded_and_not_snapshotting,
|
{
|
||||||
loader,
|
|
||||||
&specifier_str,
|
|
||||||
&referrer,
|
|
||||||
ResolutionKind::DynamicImport,
|
|
||||||
) {
|
|
||||||
Ok(resolved) => {
|
Ok(resolved) => {
|
||||||
let resolved_val = serde_v8::to_v8(scope, resolved.as_str()).unwrap();
|
let resolved_val = serde_v8::to_v8(scope, resolved.as_str()).unwrap();
|
||||||
rv.set(resolved_val);
|
rv.set(resolved_val);
|
||||||
|
|
|
@ -471,6 +471,16 @@ impl Extension {
|
||||||
pub fn disable(self) -> Self {
|
pub fn disable(self) -> Self {
|
||||||
self.enabled(false)
|
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
|
// Provides a convenient builder pattern to declare Extensions
|
||||||
|
|
276
core/modules.rs
276
core/modules.rs
|
@ -9,6 +9,7 @@ use crate::module_specifier::ModuleSpecifier;
|
||||||
use crate::resolve_import;
|
use crate::resolve_import;
|
||||||
use crate::resolve_url;
|
use crate::resolve_url;
|
||||||
use crate::snapshot_util::SnapshottedData;
|
use crate::snapshot_util::SnapshottedData;
|
||||||
|
use crate::Extension;
|
||||||
use crate::JsRuntime;
|
use crate::JsRuntime;
|
||||||
use crate::OpState;
|
use crate::OpState;
|
||||||
use anyhow::Error;
|
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
|
/// Function that can be passed to the `ExtModuleLoader` that allows to
|
||||||
/// transpile sources before passing to V8.
|
/// transpile sources before passing to V8.
|
||||||
pub type ExtModuleLoaderCb =
|
pub type ExtModuleLoaderCb =
|
||||||
|
@ -405,7 +387,8 @@ pub type ExtModuleLoaderCb =
|
||||||
|
|
||||||
pub struct ExtModuleLoader {
|
pub struct ExtModuleLoader {
|
||||||
module_loader: Rc<dyn ModuleLoader>,
|
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>>,
|
used_esm_sources: RefCell<HashMap<String, bool>>,
|
||||||
maybe_load_callback: Option<ExtModuleLoaderCb>,
|
maybe_load_callback: Option<ExtModuleLoaderCb>,
|
||||||
}
|
}
|
||||||
|
@ -414,7 +397,8 @@ impl Default for ExtModuleLoader {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
module_loader: Rc::new(NoopModuleLoader),
|
module_loader: Rc::new(NoopModuleLoader),
|
||||||
esm_sources: vec![],
|
extensions: Default::default(),
|
||||||
|
ext_resolution_allowed: Default::default(),
|
||||||
used_esm_sources: RefCell::new(HashMap::default()),
|
used_esm_sources: RefCell::new(HashMap::default()),
|
||||||
maybe_load_callback: None,
|
maybe_load_callback: None,
|
||||||
}
|
}
|
||||||
|
@ -424,70 +408,46 @@ impl Default for ExtModuleLoader {
|
||||||
impl ExtModuleLoader {
|
impl ExtModuleLoader {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
module_loader: Option<Rc<dyn ModuleLoader>>,
|
module_loader: Option<Rc<dyn ModuleLoader>>,
|
||||||
esm_sources: Vec<ExtensionFileSource>,
|
extensions: Rc<RefCell<Vec<Extension>>>,
|
||||||
maybe_load_callback: Option<ExtModuleLoaderCb>,
|
maybe_load_callback: Option<ExtModuleLoaderCb>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let used_esm_sources: HashMap<String, bool> = esm_sources
|
let used_esm_sources: HashMap<String, bool> = extensions
|
||||||
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
|
.flat_map(|e| e.get_esm_sources())
|
||||||
|
.flatten()
|
||||||
.map(|file_source| (file_source.specifier.to_string(), false))
|
.map(|file_source| (file_source.specifier.to_string(), false))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
ExtModuleLoader {
|
ExtModuleLoader {
|
||||||
module_loader: module_loader.unwrap_or_else(|| Rc::new(NoopModuleLoader)),
|
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),
|
used_esm_sources: RefCell::new(used_esm_sources),
|
||||||
maybe_load_callback,
|
maybe_load_callback,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for ExtModuleLoader {
|
pub fn resolve(
|
||||||
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(
|
|
||||||
&self,
|
&self,
|
||||||
specifier: &str,
|
specifier: &str,
|
||||||
referrer: &str,
|
referrer: &str,
|
||||||
kind: ResolutionKind,
|
kind: ResolutionKind,
|
||||||
) -> Result<ModuleSpecifier, Error> {
|
) -> Result<ModuleSpecifier, Error> {
|
||||||
if let Ok(url_specifier) = ModuleSpecifier::parse(specifier) {
|
if specifier.starts_with("ext:") {
|
||||||
if url_specifier.scheme() == "ext" {
|
if !referrer.starts_with("ext:") && referrer != "."
|
||||||
let referrer_specifier = ModuleSpecifier::parse(referrer).ok();
|
|| !*self.ext_resolution_allowed.borrow()
|
||||||
if referrer == "." || referrer_specifier.unwrap().scheme() == "ext" {
|
{
|
||||||
return Ok(url_specifier);
|
return Err(generic_error(
|
||||||
} else {
|
"Cannot load extension module from external code",
|
||||||
return Err(generic_error(
|
));
|
||||||
"Cannot load extension module from external code",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
return Ok(ModuleSpecifier::parse(specifier)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.module_loader.resolve(specifier, referrer, kind)
|
self.module_loader.resolve(specifier, referrer, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(
|
pub fn load(
|
||||||
&self,
|
&self,
|
||||||
module_specifier: &ModuleSpecifier,
|
module_specifier: &ModuleSpecifier,
|
||||||
maybe_referrer: Option<&ModuleSpecifier>,
|
maybe_referrer: Option<&ModuleSpecifier>,
|
||||||
|
@ -502,10 +462,10 @@ impl ModuleLoader for ExtModuleLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
let specifier = module_specifier.to_string();
|
let specifier = module_specifier.to_string();
|
||||||
let maybe_file_source = self
|
let extensions = self.extensions.borrow();
|
||||||
.esm_sources
|
let maybe_file_source = extensions
|
||||||
.iter()
|
.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 {
|
if let Some(file_source) = maybe_file_source {
|
||||||
{
|
{
|
||||||
|
@ -538,7 +498,7 @@ impl ModuleLoader for ExtModuleLoader {
|
||||||
.boxed_local()
|
.boxed_local()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_load(
|
pub fn prepare_load(
|
||||||
&self,
|
&self,
|
||||||
op_state: Rc<RefCell<OpState>>,
|
op_state: Rc<RefCell<OpState>>,
|
||||||
module_specifier: &ModuleSpecifier,
|
module_specifier: &ModuleSpecifier,
|
||||||
|
@ -556,6 +516,37 @@ impl ModuleLoader for ExtModuleLoader {
|
||||||
is_dyn_import,
|
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.
|
/// 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
|
// These three fields are copied from `module_map_rc`, but they are cloned
|
||||||
// ahead of time to avoid already-borrowed errors.
|
// ahead of time to avoid already-borrowed errors.
|
||||||
op_state: Rc<RefCell<OpState>>,
|
op_state: Rc<RefCell<OpState>>,
|
||||||
loader: Rc<dyn ModuleLoader>,
|
loader: Rc<ExtModuleLoader>,
|
||||||
snapshot_loaded_and_not_snapshotting: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecursiveModuleLoad {
|
impl RecursiveModuleLoad {
|
||||||
|
@ -700,9 +690,6 @@ impl RecursiveModuleLoad {
|
||||||
init,
|
init,
|
||||||
state: LoadState::Init,
|
state: LoadState::Init,
|
||||||
module_map_rc: module_map_rc.clone(),
|
module_map_rc: module_map_rc.clone(),
|
||||||
snapshot_loaded_and_not_snapshotting: module_map_rc
|
|
||||||
.borrow()
|
|
||||||
.snapshot_loaded_and_not_snapshotting,
|
|
||||||
op_state,
|
op_state,
|
||||||
loader,
|
loader,
|
||||||
pending: FuturesUnordered::new(),
|
pending: FuturesUnordered::new(),
|
||||||
|
@ -731,29 +718,17 @@ impl RecursiveModuleLoad {
|
||||||
|
|
||||||
fn resolve_root(&self) -> Result<ModuleSpecifier, Error> {
|
fn resolve_root(&self) -> Result<ModuleSpecifier, Error> {
|
||||||
match self.init {
|
match self.init {
|
||||||
LoadInit::Main(ref specifier) => resolve_helper(
|
LoadInit::Main(ref specifier) => {
|
||||||
self.snapshot_loaded_and_not_snapshotting,
|
self
|
||||||
self.loader.clone(),
|
.loader
|
||||||
specifier,
|
.resolve(specifier, ".", ResolutionKind::MainModule)
|
||||||
".",
|
|
||||||
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::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 {
|
let (module_specifier, maybe_referrer) = match self.init {
|
||||||
LoadInit::Main(ref specifier) => {
|
LoadInit::Main(ref specifier) => {
|
||||||
let spec = resolve_helper(
|
let spec =
|
||||||
self.snapshot_loaded_and_not_snapshotting,
|
self
|
||||||
self.loader.clone(),
|
.loader
|
||||||
specifier,
|
.resolve(specifier, ".", ResolutionKind::MainModule)?;
|
||||||
".",
|
|
||||||
ResolutionKind::MainModule,
|
|
||||||
)?;
|
|
||||||
(spec, None)
|
(spec, None)
|
||||||
}
|
}
|
||||||
LoadInit::Side(ref specifier) => {
|
LoadInit::Side(ref specifier) => {
|
||||||
let spec = resolve_helper(
|
let spec =
|
||||||
self.snapshot_loaded_and_not_snapshotting,
|
self
|
||||||
self.loader.clone(),
|
.loader
|
||||||
specifier,
|
.resolve(specifier, ".", ResolutionKind::Import)?;
|
||||||
".",
|
|
||||||
ResolutionKind::Import,
|
|
||||||
)?;
|
|
||||||
(spec, None)
|
(spec, None)
|
||||||
}
|
}
|
||||||
LoadInit::DynamicImport(ref specifier, ref referrer, _) => {
|
LoadInit::DynamicImport(ref specifier, ref referrer, _) => {
|
||||||
let spec = resolve_helper(
|
let spec = self.loader.resolve(
|
||||||
self.snapshot_loaded_and_not_snapshotting,
|
|
||||||
self.loader.clone(),
|
|
||||||
specifier,
|
specifier,
|
||||||
referrer,
|
referrer,
|
||||||
ResolutionKind::DynamicImport,
|
ResolutionKind::DynamicImport,
|
||||||
|
@ -1093,7 +1060,7 @@ pub(crate) struct ModuleMap {
|
||||||
pub(crate) next_load_id: ModuleLoadId,
|
pub(crate) next_load_id: ModuleLoadId,
|
||||||
|
|
||||||
// Handling of futures for loading module sources
|
// Handling of futures for loading module sources
|
||||||
pub loader: Rc<dyn ModuleLoader>,
|
pub loader: Rc<ExtModuleLoader>,
|
||||||
op_state: Rc<RefCell<OpState>>,
|
op_state: Rc<RefCell<OpState>>,
|
||||||
pub(crate) dynamic_import_map:
|
pub(crate) dynamic_import_map:
|
||||||
HashMap<ModuleLoadId, v8::Global<v8::PromiseResolver>>,
|
HashMap<ModuleLoadId, v8::Global<v8::PromiseResolver>>,
|
||||||
|
@ -1105,8 +1072,6 @@ pub(crate) struct ModuleMap {
|
||||||
// This store is used temporarly, to forward parsed JSON
|
// This store is used temporarly, to forward parsed JSON
|
||||||
// value from `new_json_module` to `json_module_evaluation_steps`
|
// value from `new_json_module` to `json_module_evaluation_steps`
|
||||||
json_value_store: HashMap<v8::Global<v8::Module>, v8::Global<v8::Value>>,
|
json_value_store: HashMap<v8::Global<v8::Module>, v8::Global<v8::Value>>,
|
||||||
|
|
||||||
pub(crate) snapshot_loaded_and_not_snapshotting: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleMap {
|
impl ModuleMap {
|
||||||
|
@ -1381,9 +1346,8 @@ impl ModuleMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
loader: Rc<dyn ModuleLoader>,
|
loader: Rc<ExtModuleLoader>,
|
||||||
op_state: Rc<RefCell<OpState>>,
|
op_state: Rc<RefCell<OpState>>,
|
||||||
snapshot_loaded_and_not_snapshotting: bool,
|
|
||||||
) -> ModuleMap {
|
) -> ModuleMap {
|
||||||
Self {
|
Self {
|
||||||
handles: vec![],
|
handles: vec![],
|
||||||
|
@ -1397,7 +1361,6 @@ impl ModuleMap {
|
||||||
preparing_dynamic_imports: FuturesUnordered::new(),
|
preparing_dynamic_imports: FuturesUnordered::new(),
|
||||||
pending_dynamic_imports: FuturesUnordered::new(),
|
pending_dynamic_imports: FuturesUnordered::new(),
|
||||||
json_value_store: HashMap::new(),
|
json_value_store: HashMap::new(),
|
||||||
snapshot_loaded_and_not_snapshotting,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1526,9 +1489,7 @@ impl ModuleMap {
|
||||||
return Err(ModuleError::Exception(exception));
|
return Err(ModuleError::Exception(exception));
|
||||||
}
|
}
|
||||||
|
|
||||||
let module_specifier = match resolve_helper(
|
let module_specifier = match self.loader.resolve(
|
||||||
self.snapshot_loaded_and_not_snapshotting,
|
|
||||||
self.loader.clone(),
|
|
||||||
&import_specifier,
|
&import_specifier,
|
||||||
name.as_ref(),
|
name.as_ref(),
|
||||||
if is_dynamic_import {
|
if is_dynamic_import {
|
||||||
|
@ -1717,20 +1678,9 @@ impl ModuleMap {
|
||||||
.dynamic_import_map
|
.dynamic_import_map
|
||||||
.insert(load.id, resolver_handle);
|
.insert(load.id, resolver_handle);
|
||||||
|
|
||||||
let (loader, snapshot_loaded_and_not_snapshotting) = {
|
let loader = module_map_rc.borrow().loader.clone();
|
||||||
let module_map = module_map_rc.borrow();
|
let resolve_result =
|
||||||
(
|
loader.resolve(specifier, referrer, ResolutionKind::DynamicImport);
|
||||||
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 fut = match resolve_result {
|
let fut = match resolve_result {
|
||||||
Ok(module_specifier) => {
|
Ok(module_specifier) => {
|
||||||
if module_map_rc
|
if module_map_rc
|
||||||
|
@ -1764,14 +1714,10 @@ impl ModuleMap {
|
||||||
referrer: &str,
|
referrer: &str,
|
||||||
import_assertions: HashMap<String, String>,
|
import_assertions: HashMap<String, String>,
|
||||||
) -> Option<v8::Local<'s, v8::Module>> {
|
) -> Option<v8::Local<'s, v8::Module>> {
|
||||||
let resolved_specifier = resolve_helper(
|
let resolved_specifier = self
|
||||||
self.snapshot_loaded_and_not_snapshotting,
|
.loader
|
||||||
self.loader.clone(),
|
.resolve(specifier, referrer, ResolutionKind::Import)
|
||||||
specifier,
|
.expect("Module should have been already resolved");
|
||||||
referrer,
|
|
||||||
ResolutionKind::Import,
|
|
||||||
)
|
|
||||||
.expect("Module should have been already resolved");
|
|
||||||
|
|
||||||
let module_type =
|
let module_type =
|
||||||
get_asserted_module_type_from_assertions(&import_assertions);
|
get_asserted_module_type_from_assertions(&import_assertions);
|
||||||
|
@ -3042,48 +2988,34 @@ if (import.meta.url != 'file:///main_with_code.js') throw Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ext_module_loader() {
|
fn ext_resolution() {
|
||||||
let loader = ExtModuleLoader::default();
|
let loader = ExtModuleLoader::default();
|
||||||
assert!(loader
|
loader.allow_ext_resolution();
|
||||||
.resolve("ext:foo", "ext:bar", ResolutionKind::Import)
|
loader
|
||||||
.is_ok());
|
.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();
|
||||||
|
loader.allow_ext_resolution();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
loader
|
loader
|
||||||
.resolve("ext:foo", "file://bar", ResolutionKind::Import)
|
.resolve("ext:core.js", "file://bar", ResolutionKind::Import,)
|
||||||
.err()
|
.err()
|
||||||
.map(|e| e.to_string()),
|
.map(|e| e.to_string()),
|
||||||
Some("Cannot load extension module from external code".to_string())
|
Some("Cannot load extension module from external code".to_string())
|
||||||
);
|
);
|
||||||
|
loader.disallow_ext_resolution();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
loader
|
loader
|
||||||
.resolve("file://foo", "file://bar", ResolutionKind::Import)
|
.resolve("ext:core.js", "ext:referrer.js", ResolutionKind::Import,)
|
||||||
.err()
|
.err()
|
||||||
.map(|e| e.to_string()),
|
.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())
|
Some("Cannot load extension module from external code".to_string())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
134
core/runtime.rs
134
core/runtime.rs
|
@ -132,7 +132,7 @@ pub struct JsRuntime {
|
||||||
v8_isolate: Option<v8::OwnedIsolate>,
|
v8_isolate: Option<v8::OwnedIsolate>,
|
||||||
snapshot_options: snapshot_util::SnapshotOptions,
|
snapshot_options: snapshot_util::SnapshotOptions,
|
||||||
allocations: IsolateAllocations,
|
allocations: IsolateAllocations,
|
||||||
extensions: Vec<Extension>,
|
extensions: Rc<RefCell<Vec<Extension>>>,
|
||||||
event_loop_middlewares: Vec<Box<OpEventLoopFn>>,
|
event_loop_middlewares: Vec<Box<OpEventLoopFn>>,
|
||||||
// Marks if this is considered the top-level runtime. Used only be inspector.
|
// Marks if this is considered the top-level runtime. Used only be inspector.
|
||||||
is_main: bool,
|
is_main: bool,
|
||||||
|
@ -416,7 +416,7 @@ impl JsRuntime {
|
||||||
let global_context;
|
let global_context;
|
||||||
let mut maybe_snapshotted_data = None;
|
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 =
|
let snapshot_creator =
|
||||||
snapshot_util::create_snapshot_creator(refs, options.startup_snapshot);
|
snapshot_util::create_snapshot_creator(refs, options.startup_snapshot);
|
||||||
let mut isolate = JsRuntime::setup_isolate(snapshot_creator);
|
let mut isolate = JsRuntime::setup_isolate(snapshot_creator);
|
||||||
|
@ -433,7 +433,7 @@ impl JsRuntime {
|
||||||
|
|
||||||
global_context = v8::Global::new(scope, context);
|
global_context = v8::Global::new(scope, context);
|
||||||
}
|
}
|
||||||
(isolate, snapshot_options)
|
isolate
|
||||||
} else {
|
} else {
|
||||||
#[cfg(not(target_env = "msvc"))]
|
#[cfg(not(target_env = "msvc"))]
|
||||||
let vtable: &'static v8::RustAllocatorVtable<
|
let vtable: &'static v8::RustAllocatorVtable<
|
||||||
|
@ -492,7 +492,7 @@ impl JsRuntime {
|
||||||
global_context = v8::Global::new(scope, context);
|
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
|
// SAFETY: this is first use of `isolate_ptr` so we are sure we're
|
||||||
|
@ -521,61 +521,33 @@ impl JsRuntime {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let loader = if snapshot_options != snapshot_util::SnapshotOptions::Load {
|
let loader = options
|
||||||
let esm_sources = 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
|
.extensions
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|ext| match ext.get_esm_sources() {
|
.flat_map(|e| vec![e.get_esm_sources(), e.get_js_sources()])
|
||||||
Some(s) => s.to_owned(),
|
.flatten()
|
||||||
None => vec![],
|
.flatten()
|
||||||
})
|
|
||||||
.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")]
|
|
||||||
{
|
{
|
||||||
let js_sources = options
|
use crate::ExtensionFileSourceCode;
|
||||||
.extensions
|
if let ExtensionFileSourceCode::LoadedFromFsDuringSnapshot(path) =
|
||||||
.iter()
|
&source.code
|
||||||
.flat_map(|ext| match ext.get_js_sources() {
|
{
|
||||||
Some(s) => s.to_owned(),
|
println!("cargo:rerun-if-changed={}", path.display())
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Rc::new(crate::modules::ExtModuleLoader::new(
|
let num_extensions = options.extensions.len();
|
||||||
options.module_loader,
|
let extensions = Rc::new(RefCell::new(options.extensions));
|
||||||
esm_sources,
|
let ext_loader = Rc::new(crate::modules::ExtModuleLoader::new(
|
||||||
options.snapshot_module_load_cb,
|
Some(loader.clone()),
|
||||||
))
|
extensions.clone(),
|
||||||
} else {
|
options.snapshot_module_load_cb,
|
||||||
options
|
));
|
||||||
.module_loader
|
|
||||||
.unwrap_or_else(|| Rc::new(NoopModuleLoader))
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = state_rc.borrow_mut();
|
let mut state = state_rc.borrow_mut();
|
||||||
|
@ -589,12 +561,8 @@ impl JsRuntime {
|
||||||
Self::STATE_DATA_OFFSET,
|
Self::STATE_DATA_OFFSET,
|
||||||
Rc::into_raw(state_rc.clone()) as *mut c_void,
|
Rc::into_raw(state_rc.clone()) as *mut c_void,
|
||||||
);
|
);
|
||||||
|
let module_map_rc =
|
||||||
let module_map_rc = Rc::new(RefCell::new(ModuleMap::new(
|
Rc::new(RefCell::new(ModuleMap::new(ext_loader, op_state)));
|
||||||
loader,
|
|
||||||
op_state,
|
|
||||||
snapshot_options == snapshot_util::SnapshotOptions::Load,
|
|
||||||
)));
|
|
||||||
if let Some(snapshotted_data) = maybe_snapshotted_data {
|
if let Some(snapshotted_data) = maybe_snapshotted_data {
|
||||||
let scope =
|
let scope =
|
||||||
&mut v8::HandleScope::with_context(&mut isolate, global_context);
|
&mut v8::HandleScope::with_context(&mut isolate, global_context);
|
||||||
|
@ -610,10 +578,10 @@ impl JsRuntime {
|
||||||
v8_isolate: Some(isolate),
|
v8_isolate: Some(isolate),
|
||||||
snapshot_options,
|
snapshot_options,
|
||||||
allocations: IsolateAllocations::default(),
|
allocations: IsolateAllocations::default(),
|
||||||
event_loop_middlewares: Vec::with_capacity(options.extensions.len()),
|
event_loop_middlewares: Vec::with_capacity(num_extensions),
|
||||||
extensions: options.extensions,
|
extensions,
|
||||||
state: state_rc,
|
state: state_rc,
|
||||||
module_map: Some(module_map_rc),
|
module_map: Some(module_map_rc.clone()),
|
||||||
is_main: options.is_main,
|
is_main: options.is_main,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -621,7 +589,9 @@ impl JsRuntime {
|
||||||
// available during the initialization process.
|
// available during the initialization process.
|
||||||
js_runtime.init_extension_ops().unwrap();
|
js_runtime.init_extension_ops().unwrap();
|
||||||
let realm = js_runtime.global_realm();
|
let realm = js_runtime.global_realm();
|
||||||
|
module_map_rc.borrow().loader.allow_ext_resolution();
|
||||||
js_runtime.init_extension_js(&realm).unwrap();
|
js_runtime.init_extension_js(&realm).unwrap();
|
||||||
|
module_map_rc.borrow().loader.disallow_ext_resolution();
|
||||||
|
|
||||||
js_runtime
|
js_runtime
|
||||||
}
|
}
|
||||||
|
@ -722,7 +692,21 @@ impl JsRuntime {
|
||||||
JsRealm::new(v8::Global::new(scope, context))
|
JsRealm::new(v8::Global::new(scope, context))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self
|
||||||
|
.module_map
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.loader
|
||||||
|
.allow_ext_resolution();
|
||||||
self.init_extension_js(&realm)?;
|
self.init_extension_js(&realm)?;
|
||||||
|
self
|
||||||
|
.module_map
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.loader
|
||||||
|
.disallow_ext_resolution();
|
||||||
Ok(realm)
|
Ok(realm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,7 +774,7 @@ impl JsRuntime {
|
||||||
|
|
||||||
// Take extensions to avoid double-borrow
|
// Take extensions to avoid double-borrow
|
||||||
let extensions = std::mem::take(&mut self.extensions);
|
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(esm_files) = ext.get_esm_sources() {
|
||||||
if let Some(entry_point) = ext.get_esm_entry_point() {
|
if let Some(entry_point) = ext.get_esm_entry_point() {
|
||||||
|
@ -863,23 +847,15 @@ impl JsRuntime {
|
||||||
/// Initializes ops of provided Extensions
|
/// Initializes ops of provided Extensions
|
||||||
fn init_extension_ops(&mut self) -> Result<(), Error> {
|
fn init_extension_ops(&mut self) -> Result<(), Error> {
|
||||||
let op_state = self.op_state();
|
let op_state = self.op_state();
|
||||||
// Take extensions to avoid double-borrow
|
// Setup state
|
||||||
{
|
for e in self.extensions.borrow_mut().iter_mut() {
|
||||||
let mut extensions: Vec<Extension> = std::mem::take(&mut self.extensions);
|
// ops are already registered during in bindings::initialize_context();
|
||||||
|
e.init_state(&mut op_state.borrow_mut());
|
||||||
|
|
||||||
// Setup state
|
// Setup event-loop middleware
|
||||||
for e in extensions.iter_mut() {
|
if let Some(middleware) = e.init_event_loop_middleware() {
|
||||||
// ops are already registered during in bindings::initialize_context();
|
self.event_loop_middlewares.push(middleware);
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
console.log("Hello world!");
|
console.log("Hello world!");
|
||||||
console.log(Deno);
|
console.log(Deno);
|
||||||
|
Extension.hello();
|
||||||
|
|
|
@ -1,72 +1,31 @@
|
||||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use deno_core::anyhow::Context;
|
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::FsModuleLoader;
|
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::permissions::PermissionsContainer;
|
||||||
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 std::path::Path;
|
use std::path::Path;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
fn get_error_class_name(e: &AnyError) -> &'static str {
|
deno_core::extension!(hello_runtime, esm = ["hello_runtime_bootstrap.js"]);
|
||||||
deno_runtime::errors::get_error_class_name(e).unwrap_or("Error")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), AnyError> {
|
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 =
|
let js_path =
|
||||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/hello_runtime.js");
|
Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/hello_runtime.js");
|
||||||
let main_module = deno_core::resolve_path(
|
let main_module = deno_core::resolve_path(
|
||||||
&js_path.to_string_lossy(),
|
&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(
|
let mut worker = MainWorker::bootstrap_from_options(
|
||||||
main_module.clone(),
|
main_module.clone(),
|
||||||
permissions,
|
PermissionsContainer::allow_all(),
|
||||||
options,
|
WorkerOptions {
|
||||||
|
module_loader: Rc::new(FsModuleLoader),
|
||||||
|
extensions: vec![hello_runtime::init_ops_and_esm()],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
);
|
);
|
||||||
worker.execute_main_module(&main_module).await?;
|
worker.execute_main_module(&main_module).await?;
|
||||||
worker.run_event_loop(false).await?;
|
worker.run_event_loop(false).await?;
|
||||||
|
|
5
runtime/examples/hello_runtime_bootstrap.js
Normal file
5
runtime/examples/hello_runtime_bootstrap.js
Normal file
|
@ -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 };
|
Loading…
Reference in a new issue