mirror of
https://github.com/denoland/deno.git
synced 2025-08-04 10:59:13 +00:00
refactor: allow lazy main module (#28929)
implement lazy(?) mode. an unconfigured jsruntime is created if DENO_UNSTABLE_CONTROL_SOCK is present, and later passed into deno_runtime to be configured and used.
This commit is contained in:
parent
8c57929058
commit
bc1ced8260
32 changed files with 764 additions and 257 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1563,6 +1563,7 @@ dependencies = [
|
|||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tokio-vsock",
|
||||
"tower 0.5.2",
|
||||
"tracing",
|
||||
"tracing-opentelemetry",
|
||||
|
|
|
@ -192,6 +192,7 @@ winapi = { workspace = true, features = ["knownfolders", "mswsock", "objbase", "
|
|||
[target.'cfg(unix)'.dependencies]
|
||||
nix.workspace = true
|
||||
shell-escape = "=0.1.5"
|
||||
tokio-vsock.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
deno_bench_util.workspace = true
|
||||
|
|
|
@ -29,6 +29,7 @@ use deno_lib::npm::NpmRegistryReadPermissionChecker;
|
|||
use deno_lib::npm::NpmRegistryReadPermissionCheckerMode;
|
||||
use deno_lib::worker::LibMainWorkerFactory;
|
||||
use deno_lib::worker::LibMainWorkerOptions;
|
||||
use deno_lib::worker::LibWorkerFactoryRoots;
|
||||
use deno_npm::npm_rc::ResolvedNpmRc;
|
||||
use deno_npm_cache::NpmCacheSetting;
|
||||
use deno_resolver::cjs::IsCjsResolutionMode;
|
||||
|
@ -1203,6 +1204,15 @@ impl CliFactory {
|
|||
|
||||
pub async fn create_cli_main_worker_factory(
|
||||
&self,
|
||||
) -> Result<CliMainWorkerFactory, AnyError> {
|
||||
self
|
||||
.create_cli_main_worker_factory_with_roots(Default::default())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_cli_main_worker_factory_with_roots(
|
||||
&self,
|
||||
roots: LibWorkerFactoryRoots,
|
||||
) -> Result<CliMainWorkerFactory, AnyError> {
|
||||
let cli_options = self.cli_options()?;
|
||||
let fs = self.fs();
|
||||
|
@ -1286,6 +1296,7 @@ impl CliFactory {
|
|||
cli_options.resolve_storage_key_resolver(),
|
||||
self.sys(),
|
||||
self.create_lib_main_worker_options()?,
|
||||
roots,
|
||||
);
|
||||
|
||||
Ok(CliMainWorkerFactory::new(
|
||||
|
|
|
@ -190,6 +190,12 @@ pub struct LibMainWorkerOptions {
|
|||
pub serve_host: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct LibWorkerFactoryRoots {
|
||||
pub compiled_wasm_module_store: CompiledWasmModuleStore,
|
||||
pub shared_array_buffer_store: SharedArrayBufferStore,
|
||||
}
|
||||
|
||||
struct LibWorkerFactorySharedState<TSys: DenoLibSys> {
|
||||
blob_store: Arc<BlobStore>,
|
||||
broadcast_channel: InMemoryBroadcastChannel,
|
||||
|
@ -370,13 +376,14 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
|
|||
storage_key_resolver: StorageKeyResolver,
|
||||
sys: TSys,
|
||||
options: LibMainWorkerOptions,
|
||||
roots: LibWorkerFactoryRoots,
|
||||
) -> Self {
|
||||
Self {
|
||||
shared: Arc::new(LibWorkerFactorySharedState {
|
||||
blob_store,
|
||||
broadcast_channel: Default::default(),
|
||||
code_cache,
|
||||
compiled_wasm_module_store: Default::default(),
|
||||
compiled_wasm_module_store: roots.compiled_wasm_module_store,
|
||||
deno_rt_native_addon_loader,
|
||||
feature_checker,
|
||||
fs,
|
||||
|
@ -386,7 +393,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
|
|||
npm_process_state_provider,
|
||||
pkg_json_resolver,
|
||||
root_cert_store_provider,
|
||||
shared_array_buffer_store: Default::default(),
|
||||
shared_array_buffer_store: roots.shared_array_buffer_store,
|
||||
storage_key_resolver,
|
||||
sys,
|
||||
options,
|
||||
|
@ -406,6 +413,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
|
|||
permissions,
|
||||
vec![],
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -416,6 +424,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
|
|||
permissions: PermissionsContainer,
|
||||
custom_extensions: Vec<Extension>,
|
||||
stdio: deno_runtime::deno_io::Stdio,
|
||||
unconfigured_runtime: Option<deno_runtime::UnconfiguredRuntime>,
|
||||
) -> Result<LibMainWorker, CoreError> {
|
||||
let shared = &self.shared;
|
||||
let CreateModuleLoaderResult {
|
||||
|
@ -516,6 +525,7 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
|
|||
stdio,
|
||||
skip_op_registration: shared.options.skip_op_registration,
|
||||
enable_stack_trace_arg_in_ops: has_trace_permissions_enabled(),
|
||||
unconfigured_runtime,
|
||||
};
|
||||
|
||||
let worker =
|
||||
|
|
152
cli/main.rs
152
cli/main.rs
|
@ -44,10 +44,12 @@ use deno_core::error::CoreError;
|
|||
use deno_core::futures::FutureExt;
|
||||
use deno_core::unsync::JoinHandle;
|
||||
use deno_lib::util::result::any_and_jserrorbox_downcast_ref;
|
||||
use deno_lib::worker::LibWorkerFactoryRoots;
|
||||
use deno_resolver::npm::ByonmResolvePkgFolderFromDenoReqError;
|
||||
use deno_resolver::npm::ResolvePkgFolderFromDenoReqError;
|
||||
use deno_runtime::fmt_errors::format_js_error;
|
||||
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
|
||||
use deno_runtime::UnconfiguredRuntime;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
pub use deno_runtime::UNSTABLE_FEATURES;
|
||||
use deno_telemetry::OtelConfig;
|
||||
|
@ -106,7 +108,11 @@ fn spawn_subcommand<F: Future<Output = T> + 'static, T: SubcommandOutput>(
|
|||
)
|
||||
}
|
||||
|
||||
async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
||||
async fn run_subcommand(
|
||||
flags: Arc<Flags>,
|
||||
unconfigured_runtime: Option<UnconfiguredRuntime>,
|
||||
roots: LibWorkerFactoryRoots,
|
||||
) -> Result<i32, AnyError> {
|
||||
let handle = match flags.subcommand.clone() {
|
||||
DenoSubcommand::Add(add_flags) => spawn_subcommand(async {
|
||||
tools::pm::add(flags, add_flags, tools::pm::AddCommandName::Add).await
|
||||
|
@ -217,11 +223,11 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
DenoSubcommand::Run(run_flags) => spawn_subcommand(async move {
|
||||
if run_flags.is_stdin() {
|
||||
// these futures are boxed to prevent stack overflows on Windows
|
||||
tools::run::run_from_stdin(flags.clone()).boxed_local().await
|
||||
tools::run::run_from_stdin(flags.clone(), unconfigured_runtime, roots).boxed_local().await
|
||||
} else if flags.eszip {
|
||||
tools::run::run_eszip(flags, run_flags).boxed_local().await
|
||||
tools::run::run_eszip(flags, run_flags, unconfigured_runtime, roots).boxed_local().await
|
||||
} else {
|
||||
let result = tools::run::run_script(WorkerExecutionMode::Run, flags.clone(), run_flags.watch).await;
|
||||
let result = tools::run::run_script(WorkerExecutionMode::Run, flags.clone(), run_flags.watch, unconfigured_runtime, roots.clone()).await;
|
||||
match result {
|
||||
Ok(v) => Ok(v),
|
||||
Err(script_err) => {
|
||||
|
@ -237,7 +243,7 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
if flags.frozen_lockfile.is_none() {
|
||||
flags.internal.lockfile_skip_write = true;
|
||||
}
|
||||
return tools::run::run_script(WorkerExecutionMode::Run, Arc::new(flags), watch).boxed_local().await;
|
||||
return tools::run::run_script(WorkerExecutionMode::Run, Arc::new(flags), watch, None, roots).boxed_local().await;
|
||||
}
|
||||
}
|
||||
let script_err_msg = script_err.to_string();
|
||||
|
@ -451,11 +457,38 @@ pub fn main() {
|
|||
|
||||
let args: Vec<_> = env::args_os().collect();
|
||||
let future = async move {
|
||||
let roots = LibWorkerFactoryRoots::default();
|
||||
|
||||
#[cfg(unix)]
|
||||
let (waited_unconfigured_runtime, waited_args) =
|
||||
match wait_for_start(&args, roots.clone()) {
|
||||
Some(f) => match f.await {
|
||||
Ok(v) => match v {
|
||||
Some((u, a)) => (Some(u), Some(a)),
|
||||
None => (None, None),
|
||||
},
|
||||
Err(e) => {
|
||||
panic!("Failure from control sock: {e}");
|
||||
}
|
||||
},
|
||||
None => (None, None),
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let (waited_unconfigured_runtime, waited_args) = (None, None);
|
||||
|
||||
let args = waited_args.unwrap_or(args);
|
||||
|
||||
// NOTE(lucacasonato): due to new PKU feature introduced in V8 11.6 we need to
|
||||
// initialize the V8 platform on a parent thread of all threads that will spawn
|
||||
// V8 isolates.
|
||||
let flags = resolve_flags_and_init(args)?;
|
||||
run_subcommand(Arc::new(flags)).await
|
||||
|
||||
if waited_unconfigured_runtime.is_none() {
|
||||
init_v8(&flags);
|
||||
}
|
||||
|
||||
run_subcommand(Arc::new(flags), waited_unconfigured_runtime, roots).await
|
||||
};
|
||||
|
||||
let result = create_and_run_current_thread_with_maybe_metrics(future);
|
||||
|
@ -505,6 +538,10 @@ fn resolve_flags_and_init(
|
|||
);
|
||||
}
|
||||
|
||||
Ok(flags)
|
||||
}
|
||||
|
||||
fn init_v8(flags: &Flags) {
|
||||
let default_v8_flags = match flags.subcommand {
|
||||
DenoSubcommand::Lsp => vec![
|
||||
"--stack-size=1024".to_string(),
|
||||
|
@ -527,13 +564,12 @@ fn resolve_flags_and_init(
|
|||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// TODO(bartlomieju): remove last argument once Deploy no longer needs it
|
||||
deno_core::JsRuntime::init_platform(
|
||||
v8_platform,
|
||||
/* import assertions enabled */ false,
|
||||
);
|
||||
|
||||
Ok(flags)
|
||||
}
|
||||
|
||||
fn init_logging(
|
||||
|
@ -551,3 +587,103 @@ fn init_logging(
|
|||
on_log_end: DrawThread::show,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn wait_for_start(
|
||||
args: &[std::ffi::OsString],
|
||||
roots: LibWorkerFactoryRoots,
|
||||
) -> Option<
|
||||
impl Future<
|
||||
Output = Result<
|
||||
Option<(UnconfiguredRuntime, Vec<std::ffi::OsString>)>,
|
||||
AnyError,
|
||||
>,
|
||||
>,
|
||||
> {
|
||||
let startup_snapshot = deno_snapshots::CLI_SNAPSHOT?;
|
||||
let addr = std::env::var("DENO_UNSTABLE_CONTROL_SOCK").ok()?;
|
||||
std::env::remove_var("DENO_UNSTABLE_CONTROL_SOCK");
|
||||
|
||||
let argv0 = args[0].clone();
|
||||
|
||||
Some(async move {
|
||||
use tokio::io::AsyncBufReadExt;
|
||||
use tokio::io::AsyncRead;
|
||||
use tokio::io::BufReader;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::net::UnixSocket;
|
||||
use tokio_vsock::VsockAddr;
|
||||
use tokio_vsock::VsockListener;
|
||||
|
||||
init_v8(&Flags::default());
|
||||
|
||||
let unconfigured = deno_runtime::UnconfiguredRuntime::new::<
|
||||
deno_resolver::npm::DenoInNpmPackageChecker,
|
||||
crate::npm::CliNpmResolver,
|
||||
crate::sys::CliSys,
|
||||
>(
|
||||
startup_snapshot,
|
||||
deno_lib::worker::create_isolate_create_params(),
|
||||
Some(roots.shared_array_buffer_store.clone()),
|
||||
Some(roots.compiled_wasm_module_store.clone()),
|
||||
vec![],
|
||||
);
|
||||
|
||||
let stream: Box<dyn AsyncRead + Unpin> = match addr.split_once(':') {
|
||||
Some(("tcp", addr)) => {
|
||||
let listener = TcpListener::bind(addr).await?;
|
||||
let (stream, _) = listener.accept().await?;
|
||||
Box::new(stream)
|
||||
}
|
||||
Some(("unix", path)) => {
|
||||
let socket = UnixSocket::new_stream()?;
|
||||
socket.bind(path)?;
|
||||
let listener = socket.listen(1)?;
|
||||
let (stream, _) = listener.accept().await?;
|
||||
Box::new(stream)
|
||||
}
|
||||
Some(("vsock", addr)) => {
|
||||
let Some((cid, port)) = addr.split_once(':') else {
|
||||
deno_core::anyhow::bail!("invalid vsock addr");
|
||||
};
|
||||
let cid = if cid == "-1" { u32::MAX } else { cid.parse()? };
|
||||
let port = port.parse()?;
|
||||
let addr = VsockAddr::new(cid, port);
|
||||
let listener = VsockListener::bind(addr)?;
|
||||
let (stream, _) = listener.accept().await?;
|
||||
Box::new(stream)
|
||||
}
|
||||
_ => {
|
||||
deno_core::anyhow::bail!("invalid control sock");
|
||||
}
|
||||
};
|
||||
|
||||
let mut stream = BufReader::new(stream);
|
||||
|
||||
let mut buf = Vec::with_capacity(1024);
|
||||
stream.read_until(b'\n', &mut buf).await?;
|
||||
|
||||
#[derive(deno_core::serde::Deserialize)]
|
||||
struct Start {
|
||||
cwd: String,
|
||||
args: Vec<String>,
|
||||
env: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
let cmd: Start = deno_core::serde_json::from_slice(&buf)?;
|
||||
|
||||
std::env::set_current_dir(cmd.cwd)?;
|
||||
|
||||
for (k, v) in cmd.env {
|
||||
std::env::set_var(k, v);
|
||||
}
|
||||
|
||||
let args = [argv0]
|
||||
.into_iter()
|
||||
.chain(cmd.args.into_iter().map(Into::into))
|
||||
.collect();
|
||||
|
||||
Ok(Some((unconfigured, args)))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -984,6 +984,7 @@ pub async fn run(
|
|||
StorageKeyResolver::empty(),
|
||||
sys.clone(),
|
||||
lib_main_worker_options,
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
// Initialize v8 once from the main thread.
|
||||
|
|
|
@ -192,6 +192,7 @@ async fn bench_specifier_inner(
|
|||
permissions_container,
|
||||
vec![ops::bench::deno_bench::init(sender.clone())],
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
|
|
@ -344,6 +344,8 @@ async fn init_npm(name: &str, args: Vec<String>) -> Result<i32, AnyError> {
|
|||
WorkerExecutionMode::Run,
|
||||
new_flags.into(),
|
||||
None,
|
||||
None,
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ pub async fn kernel(
|
|||
stdout: StdioPipe::file(stdout),
|
||||
stderr: StdioPipe::file(stderr),
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
worker.setup_repl().await?;
|
||||
|
|
|
@ -166,6 +166,7 @@ async fn create_plugin_runner_inner(
|
|||
permissions,
|
||||
vec![crate::ops::lint::deno_lint_ext::init(logger.clone())],
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
|
|
@ -192,6 +192,7 @@ pub async fn run(
|
|||
permissions.clone(),
|
||||
vec![crate::ops::testing::deno_test::init(test_event_sender)],
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
worker.setup_repl().await?;
|
||||
|
|
|
@ -10,6 +10,7 @@ use deno_core::error::AnyError;
|
|||
use deno_core::futures::FutureExt;
|
||||
use deno_core::resolve_url_or_path;
|
||||
use deno_lib::standalone::binary::SerializedWorkspaceResolverImportMap;
|
||||
use deno_lib::worker::LibWorkerFactoryRoots;
|
||||
use deno_runtime::WorkerExecutionMode;
|
||||
use eszip::EszipV2;
|
||||
use jsonc_parser::ParseOptions;
|
||||
|
@ -52,6 +53,8 @@ pub async fn run_script(
|
|||
mode: WorkerExecutionMode,
|
||||
flags: Arc<Flags>,
|
||||
watch: Option<WatchFlagsWithPaths>,
|
||||
unconfigured_runtime: Option<deno_runtime::UnconfiguredRuntime>,
|
||||
roots: LibWorkerFactoryRoots,
|
||||
) -> Result<i32, AnyError> {
|
||||
check_permission_before_script(&flags);
|
||||
|
||||
|
@ -82,16 +85,26 @@ pub async fn run_script(
|
|||
|
||||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let worker_factory = factory
|
||||
.create_cli_main_worker_factory_with_roots(roots)
|
||||
.await?;
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(mode, main_module.clone())
|
||||
.create_main_worker_with_unconfigured_runtime(
|
||||
mode,
|
||||
main_module.clone(),
|
||||
unconfigured_runtime,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let exit_code = worker.run().await?;
|
||||
Ok(exit_code)
|
||||
}
|
||||
|
||||
pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
||||
pub async fn run_from_stdin(
|
||||
flags: Arc<Flags>,
|
||||
unconfigured_runtime: Option<deno_runtime::UnconfiguredRuntime>,
|
||||
roots: LibWorkerFactoryRoots,
|
||||
) -> Result<i32, AnyError> {
|
||||
let factory = CliFactory::from_flags(flags);
|
||||
let cli_options = factory.cli_options()?;
|
||||
let main_module = cli_options.resolve_main_module()?;
|
||||
|
@ -99,7 +112,9 @@ pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
maybe_npm_install(&factory).await?;
|
||||
|
||||
let file_fetcher = factory.file_fetcher()?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let worker_factory = factory
|
||||
.create_cli_main_worker_factory_with_roots(roots)
|
||||
.await?;
|
||||
let mut source = Vec::new();
|
||||
std::io::stdin().read_to_end(&mut source)?;
|
||||
// Save a fake file into file fetcher cache
|
||||
|
@ -111,7 +126,11 @@ pub async fn run_from_stdin(flags: Arc<Flags>) -> Result<i32, AnyError> {
|
|||
});
|
||||
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(WorkerExecutionMode::Run, main_module.clone())
|
||||
.create_main_worker_with_unconfigured_runtime(
|
||||
WorkerExecutionMode::Run,
|
||||
main_module.clone(),
|
||||
unconfigured_runtime,
|
||||
)
|
||||
.await?;
|
||||
let exit_code = worker.run().await?;
|
||||
Ok(exit_code)
|
||||
|
@ -232,6 +251,8 @@ pub async fn maybe_npm_install(factory: &CliFactory) -> Result<(), AnyError> {
|
|||
pub async fn run_eszip(
|
||||
flags: Arc<Flags>,
|
||||
run_flags: RunFlags,
|
||||
unconfigured_runtime: Option<deno_runtime::UnconfiguredRuntime>,
|
||||
roots: LibWorkerFactoryRoots,
|
||||
) -> Result<i32, AnyError> {
|
||||
// TODO(bartlomieju): actually I think it will also fail if there's an import
|
||||
// map specified and bare specifier is used on the command line
|
||||
|
@ -246,9 +267,15 @@ pub async fn run_eszip(
|
|||
|
||||
let mode = WorkerExecutionMode::Run;
|
||||
let main_module = resolve_url_or_path(entrypoint, cli_options.initial_cwd())?;
|
||||
let worker_factory = factory.create_cli_main_worker_factory().await?;
|
||||
let worker_factory = factory
|
||||
.create_cli_main_worker_factory_with_roots(roots)
|
||||
.await?;
|
||||
let mut worker = worker_factory
|
||||
.create_main_worker(mode, main_module.clone())
|
||||
.create_main_worker_with_unconfigured_runtime(
|
||||
mode,
|
||||
main_module.clone(),
|
||||
unconfigured_runtime,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let exit_code = worker.run().await?;
|
||||
|
|
|
@ -640,6 +640,7 @@ async fn configure_main_worker(
|
|||
stdout: StdioPipe::file(worker_sender.stdout),
|
||||
stderr: StdioPipe::file(worker_sender.stderr),
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let coverage_collector = worker.maybe_setup_coverage_collector().await?;
|
||||
|
|
|
@ -365,6 +365,25 @@ impl CliMainWorkerFactory {
|
|||
self.root_permissions.clone(),
|
||||
vec![],
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_main_worker_with_unconfigured_runtime(
|
||||
&self,
|
||||
mode: WorkerExecutionMode,
|
||||
main_module: ModuleSpecifier,
|
||||
unconfigured_runtime: Option<deno_runtime::UnconfiguredRuntime>,
|
||||
) -> Result<CliMainWorker, CreateCustomWorkerError> {
|
||||
self
|
||||
.create_custom_worker(
|
||||
mode,
|
||||
main_module,
|
||||
self.root_permissions.clone(),
|
||||
vec![],
|
||||
Default::default(),
|
||||
unconfigured_runtime,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
@ -376,6 +395,7 @@ impl CliMainWorkerFactory {
|
|||
permissions: PermissionsContainer,
|
||||
custom_extensions: Vec<Extension>,
|
||||
stdio: deno_runtime::deno_io::Stdio,
|
||||
unconfigured_runtime: Option<deno_runtime::UnconfiguredRuntime>,
|
||||
) -> Result<CliMainWorker, CreateCustomWorkerError> {
|
||||
let main_module = if let Ok(package_ref) =
|
||||
NpmPackageReqReference::from_specifier(&main_module)
|
||||
|
@ -432,6 +452,7 @@ impl CliMainWorkerFactory {
|
|||
permissions,
|
||||
custom_extensions,
|
||||
stdio,
|
||||
unconfigured_runtime,
|
||||
)?;
|
||||
|
||||
if self.needs_test_modules {
|
||||
|
|
|
@ -21,8 +21,8 @@ Object.defineProperty(globalThis, "console", {
|
|||
});
|
||||
```
|
||||
|
||||
Then from rust, provide `deno_console::deno_console::init_ops_and_esm()` in the
|
||||
`extensions` field of your `RuntimeOptions`
|
||||
Then from rust, provide `deno_console::deno_console::init()` in the `extensions`
|
||||
field of your `RuntimeOptions`
|
||||
|
||||
## Provided ops
|
||||
|
||||
|
|
|
@ -41,9 +41,8 @@ Object.defineProperty(globalThis, "SubtleCrypto", {
|
|||
});
|
||||
```
|
||||
|
||||
Then from rust, provide:
|
||||
`deno_crypto::deno_crypto::init_ops_and_esm(Option<u64>)` in the `extensions`
|
||||
field of your `RuntimeOptions`
|
||||
Then from rust, provide: `deno_crypto::deno_crypto::init(Option<u64>)` in the
|
||||
`extensions` field of your `RuntimeOptions`
|
||||
|
||||
Where the `Option<u64>` represents an optional seed for initialization.
|
||||
|
||||
|
|
|
@ -57,8 +57,8 @@ Object.defineProperty(globalThis, "FormData", {
|
|||
```
|
||||
|
||||
Then from rust, provide
|
||||
`deno_fetch::deno_fetch::init_ops_and_esm<Permissions>(Default::default())` in
|
||||
the `extensions` field of your `RuntimeOptions`
|
||||
`deno_fetch::deno_fetch::init<Permissions>(Default::default())` in the
|
||||
`extensions` field of your `RuntimeOptions`
|
||||
|
||||
Where:
|
||||
|
||||
|
|
|
@ -11,9 +11,8 @@ From javascript, include the extension's source:
|
|||
import * as io from "ext:deno_io/12_io.js";
|
||||
```
|
||||
|
||||
Then from rust, provide:
|
||||
`deno_io::deno_io::init_ops_and_esm(Option<deno_io::Stdio>)` in the `extensions`
|
||||
field of your `RuntimeOptions`
|
||||
Then from rust, provide: `deno_io::deno_io::init(Option<deno_io::Stdio>)` in the
|
||||
`extensions` field of your `RuntimeOptions`
|
||||
|
||||
Where `deno_io::Stdio` implements `Default`, and can therefore be provided as
|
||||
`Some(deno_io::Stdio::default())`
|
||||
|
|
|
@ -13,7 +13,7 @@ import * as tls from "ext:deno_net/02_tls.js";
|
|||
```
|
||||
|
||||
Then from rust, provide:
|
||||
`deno_net::deno_net::init_ops_and_esm::<Permissions>(root_cert_store_provider, unsafely_ignore_certificate_errors)`
|
||||
`deno_net::deno_net::init::<Permissions>(root_cert_store_provider, unsafely_ignore_certificate_errors)`
|
||||
|
||||
Where:
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ Object.defineProperty(globalThis, "URLSearchParams", {
|
|||
});
|
||||
```
|
||||
|
||||
Then from rust, provide `deno_url::deno_url::init_ops_and_esm()` in the
|
||||
`extensions` field of your `RuntimeOptions`
|
||||
Then from rust, provide `deno_url::deno_url::init()` in the `extensions` field
|
||||
of your `RuntimeOptions`
|
||||
|
||||
## Dependencies
|
||||
|
||||
|
|
|
@ -98,8 +98,8 @@ Object.defineProperty(globalThis, "AbortController", {
|
|||
| structuredClone | messagePort.structuredClone | true | true | true |
|
||||
|
||||
Then from rust, provide:
|
||||
`deno_web::deno_web::init_ops_and_esm::<Permissions>(Arc<BlobStore>, Option<Url>)`
|
||||
in the `extensions` field of your `RuntimeOptions`
|
||||
`deno_web::deno_web::init::<Permissions>(Arc<BlobStore>, Option<Url>)` in the
|
||||
`extensions` field of your `RuntimeOptions`
|
||||
|
||||
Where:
|
||||
|
||||
|
|
|
@ -20,5 +20,5 @@ Object.defineProperty(globalThis, webidl.brand, {
|
|||
});
|
||||
```
|
||||
|
||||
Then from rust, provide `init_webidl::init_webidl::init_ops_and_esm()` in the
|
||||
`extensions` field of your `RuntimeOptions`
|
||||
Then from rust, provide `init_webidl::init_webidl::init()` in the `extensions`
|
||||
field of your `RuntimeOptions`
|
||||
|
|
|
@ -8,6 +8,7 @@ import { core, internals, primordials } from "ext:core/mod.js";
|
|||
const ops = core.ops;
|
||||
import {
|
||||
op_bootstrap_args,
|
||||
op_bootstrap_is_from_unconfigured_runtime,
|
||||
op_bootstrap_no_color,
|
||||
op_bootstrap_pid,
|
||||
op_bootstrap_stderr_no_color,
|
||||
|
@ -116,6 +117,8 @@ ObjectDefineProperties(Symbol, {
|
|||
},
|
||||
});
|
||||
|
||||
internals.isFromUnconfiguredRuntime = op_bootstrap_is_from_unconfigured_runtime;
|
||||
|
||||
// https://docs.rs/log/latest/log/enum.Level.html
|
||||
const LOG_LEVELS = {
|
||||
error: 1,
|
||||
|
|
|
@ -46,6 +46,7 @@ pub mod web_worker;
|
|||
pub mod worker;
|
||||
|
||||
mod worker_bootstrap;
|
||||
pub use worker::UnconfiguredRuntime;
|
||||
pub use worker_bootstrap::BootstrapOptions;
|
||||
pub use worker_bootstrap::WorkerExecutionMode;
|
||||
pub use worker_bootstrap::WorkerLogLevel;
|
||||
|
|
|
@ -21,15 +21,18 @@ deno_core::extension!(
|
|||
op_bootstrap_stdout_no_color,
|
||||
op_bootstrap_stderr_no_color,
|
||||
op_bootstrap_unstable_args,
|
||||
op_bootstrap_is_from_unconfigured_runtime,
|
||||
op_snapshot_options,
|
||||
],
|
||||
options = {
|
||||
snapshot_options: Option<SnapshotOptions>,
|
||||
is_from_unconfigured_runtime: bool,
|
||||
},
|
||||
state = |state, options| {
|
||||
if let Some(snapshot_options) = options.snapshot_options {
|
||||
state.put::<SnapshotOptions>(snapshot_options);
|
||||
}
|
||||
state.put(IsFromUnconfiguredRuntime(options.is_from_unconfigured_runtime));
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -41,6 +44,8 @@ pub struct SnapshotOptions {
|
|||
pub target: String,
|
||||
}
|
||||
|
||||
struct IsFromUnconfiguredRuntime(bool);
|
||||
|
||||
impl Default for SnapshotOptions {
|
||||
fn default() -> Self {
|
||||
let arch = std::env::consts::ARCH;
|
||||
|
@ -151,3 +156,8 @@ pub fn op_bootstrap_stderr_no_color(_state: &mut OpState) -> bool {
|
|||
|
||||
!deno_terminal::is_stderr_tty() || !deno_terminal::colors::use_color()
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_bootstrap_is_from_unconfigured_runtime(state: &mut OpState) -> bool {
|
||||
state.borrow::<IsFromUnconfiguredRuntime>().0
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use deno_core::snapshot::*;
|
||||
use deno_core::v8;
|
||||
|
@ -25,62 +24,49 @@ pub fn create_runtime_snapshot(
|
|||
// NOTE(bartlomieju): ordering is important here, keep it in sync with
|
||||
// `runtime/worker.rs`, `runtime/web_worker.rs`, `runtime/snapshot_info.rs`
|
||||
// and `runtime/snapshot.rs`!
|
||||
let fs = std::sync::Arc::new(deno_fs::RealFs);
|
||||
let mut extensions: Vec<Extension> = vec![
|
||||
deno_telemetry::deno_telemetry::init(),
|
||||
deno_webidl::deno_webidl::init(),
|
||||
deno_console::deno_console::init(),
|
||||
deno_url::deno_url::init(),
|
||||
deno_web::deno_web::init::<Permissions>(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
),
|
||||
deno_webgpu::deno_webgpu::init(),
|
||||
deno_canvas::deno_canvas::init(),
|
||||
deno_fetch::deno_fetch::init::<Permissions>(Default::default()),
|
||||
deno_cache::deno_cache::init(None),
|
||||
deno_websocket::deno_websocket::init::<Permissions>(
|
||||
"".to_owned(),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
deno_webstorage::deno_webstorage::init(None),
|
||||
deno_crypto::deno_crypto::init(None),
|
||||
deno_broadcast_channel::deno_broadcast_channel::init(
|
||||
deno_broadcast_channel::InMemoryBroadcastChannel::default(),
|
||||
),
|
||||
deno_ffi::deno_ffi::init::<Permissions>(None),
|
||||
deno_net::deno_net::init::<Permissions>(None, None),
|
||||
deno_tls::deno_tls::init(),
|
||||
deno_kv::deno_kv::init(
|
||||
deno_kv::sqlite::SqliteDbHandler::<Permissions>::new(None, None),
|
||||
deno_kv::KvConfig::builder().build(),
|
||||
deno_telemetry::deno_telemetry::lazy_init(),
|
||||
deno_webidl::deno_webidl::lazy_init(),
|
||||
deno_console::deno_console::lazy_init(),
|
||||
deno_url::deno_url::lazy_init(),
|
||||
deno_web::deno_web::lazy_init::<Permissions>(),
|
||||
deno_webgpu::deno_webgpu::lazy_init(),
|
||||
deno_canvas::deno_canvas::lazy_init(),
|
||||
deno_fetch::deno_fetch::lazy_init::<Permissions>(),
|
||||
deno_cache::deno_cache::lazy_init(),
|
||||
deno_websocket::deno_websocket::lazy_init::<Permissions>(),
|
||||
deno_webstorage::deno_webstorage::lazy_init(),
|
||||
deno_crypto::deno_crypto::lazy_init(),
|
||||
deno_broadcast_channel::deno_broadcast_channel::lazy_init::<
|
||||
deno_broadcast_channel::InMemoryBroadcastChannel,
|
||||
>(),
|
||||
deno_ffi::deno_ffi::lazy_init::<Permissions>(),
|
||||
deno_net::deno_net::lazy_init::<Permissions>(),
|
||||
deno_tls::deno_tls::lazy_init(),
|
||||
deno_kv::deno_kv::lazy_init::<deno_kv::sqlite::SqliteDbHandler<Permissions>>(
|
||||
),
|
||||
deno_cron::deno_cron::init(deno_cron::local::LocalCronHandler::new()),
|
||||
deno_napi::deno_napi::init::<Permissions>(None),
|
||||
deno_http::deno_http::init(deno_http::Options::default()),
|
||||
deno_io::deno_io::init(Default::default()),
|
||||
deno_fs::deno_fs::init::<Permissions>(fs.clone()),
|
||||
deno_os::deno_os::init(Default::default()),
|
||||
deno_process::deno_process::init(Default::default()),
|
||||
deno_node::deno_node::init::<
|
||||
deno_napi::deno_napi::lazy_init::<Permissions>(),
|
||||
deno_http::deno_http::lazy_init(),
|
||||
deno_io::deno_io::lazy_init(),
|
||||
deno_fs::deno_fs::lazy_init::<Permissions>(),
|
||||
deno_os::deno_os::lazy_init(),
|
||||
deno_process::deno_process::lazy_init(),
|
||||
deno_node::deno_node::lazy_init::<
|
||||
Permissions,
|
||||
DenoInNpmPackageChecker,
|
||||
NpmResolver<sys_traits::impls::RealSys>,
|
||||
sys_traits::impls::RealSys,
|
||||
>(None, fs.clone()),
|
||||
ops::runtime::deno_runtime::init("deno:runtime".parse().unwrap()),
|
||||
ops::worker_host::deno_worker_host::init(
|
||||
Arc::new(|_| unreachable!("not used in snapshot.")),
|
||||
None,
|
||||
),
|
||||
ops::fs_events::deno_fs_events::init(),
|
||||
ops::permissions::deno_permissions::init(),
|
||||
ops::tty::deno_tty::init(),
|
||||
ops::http::deno_http_runtime::init(),
|
||||
ops::bootstrap::deno_bootstrap::init(Some(snapshot_options)),
|
||||
runtime::init(),
|
||||
ops::web_worker::deno_web_worker::init(),
|
||||
>(),
|
||||
ops::runtime::deno_runtime::lazy_init(),
|
||||
ops::worker_host::deno_worker_host::lazy_init(),
|
||||
ops::fs_events::deno_fs_events::lazy_init(),
|
||||
ops::permissions::deno_permissions::lazy_init(),
|
||||
ops::tty::deno_tty::lazy_init(),
|
||||
ops::http::deno_http_runtime::lazy_init(),
|
||||
ops::bootstrap::deno_bootstrap::init(Some(snapshot_options), false),
|
||||
runtime::lazy_init(),
|
||||
ops::web_worker::deno_web_worker::lazy_init(),
|
||||
];
|
||||
extensions.extend(custom_extensions);
|
||||
|
||||
|
|
|
@ -321,7 +321,7 @@ pub fn get_extensions_in_snapshot() -> Vec<Extension> {
|
|||
ops::permissions::deno_permissions::init(),
|
||||
ops::tty::deno_tty::init(),
|
||||
ops::http::deno_http_runtime::init(),
|
||||
ops::bootstrap::deno_bootstrap::init(None),
|
||||
ops::bootstrap::deno_bootstrap::init(None, false),
|
||||
runtime::init(),
|
||||
ops::web_worker::deno_web_worker::init(),
|
||||
]
|
||||
|
|
|
@ -568,11 +568,8 @@ impl WebWorker {
|
|||
ops::tty::deno_tty::init(),
|
||||
ops::http::deno_http_runtime::init(),
|
||||
ops::bootstrap::deno_bootstrap::init(
|
||||
if options.startup_snapshot.is_some() {
|
||||
None
|
||||
} else {
|
||||
Some(Default::default())
|
||||
},
|
||||
options.startup_snapshot.and_then(|_| Default::default()),
|
||||
false,
|
||||
),
|
||||
runtime::init(),
|
||||
ops::web_worker::deno_web_worker::init(),
|
||||
|
|
|
@ -96,6 +96,17 @@ pub fn validate_import_attributes_callback(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn make_wait_for_inspector_disconnect_callback() -> Box<dyn Fn()> {
|
||||
let has_notified_of_inspector_disconnect = AtomicBool::new(false);
|
||||
Box::new(move || {
|
||||
if !has_notified_of_inspector_disconnect
|
||||
.swap(true, std::sync::atomic::Ordering::SeqCst)
|
||||
{
|
||||
log::info!("Program finished. Waiting for inspector to disconnect to exit the process...");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// This worker is created and used by almost all
|
||||
/// subcommands in Deno executable.
|
||||
///
|
||||
|
@ -204,6 +215,8 @@ pub struct WorkerOptions {
|
|||
pub origin_storage_dir: Option<std::path::PathBuf>,
|
||||
pub stdio: Stdio,
|
||||
pub enable_stack_trace_arg_in_ops: bool,
|
||||
|
||||
pub unconfigured_runtime: Option<UnconfiguredRuntime>,
|
||||
}
|
||||
|
||||
impl Default for WorkerOptions {
|
||||
|
@ -228,6 +241,7 @@ impl Default for WorkerOptions {
|
|||
bootstrap: Default::default(),
|
||||
stdio: Default::default(),
|
||||
enable_stack_trace_arg_in_ops: false,
|
||||
unconfigured_runtime: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,112 +389,13 @@ impl MainWorker {
|
|||
let enable_testing_features = options.bootstrap.enable_testing_features;
|
||||
let exit_code = ExitCode::default();
|
||||
|
||||
// NOTE(bartlomieju): ordering is important here, keep it in sync with
|
||||
// `runtime/worker.rs`, `runtime/web_worker.rs`, `runtime/snapshot_info.rs`
|
||||
// and `runtime/snapshot.rs`!
|
||||
let mut extensions = vec![
|
||||
deno_telemetry::deno_telemetry::init(),
|
||||
// Web APIs
|
||||
deno_webidl::deno_webidl::init(),
|
||||
deno_console::deno_console::init(),
|
||||
deno_url::deno_url::init(),
|
||||
deno_web::deno_web::init::<PermissionsContainer>(
|
||||
services.blob_store.clone(),
|
||||
options.bootstrap.location.clone(),
|
||||
),
|
||||
deno_webgpu::deno_webgpu::init(),
|
||||
deno_canvas::deno_canvas::init(),
|
||||
deno_fetch::deno_fetch::init::<PermissionsContainer>(
|
||||
deno_fetch::Options {
|
||||
user_agent: options.bootstrap.user_agent.clone(),
|
||||
root_cert_store_provider: services.root_cert_store_provider.clone(),
|
||||
unsafely_ignore_certificate_errors: options
|
||||
.unsafely_ignore_certificate_errors
|
||||
.clone(),
|
||||
file_fetch_handler: Rc::new(deno_fetch::FsFetchHandler),
|
||||
resolver: services.fetch_dns_resolver,
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
deno_cache::deno_cache::init(create_cache),
|
||||
deno_websocket::deno_websocket::init::<PermissionsContainer>(
|
||||
options.bootstrap.user_agent.clone(),
|
||||
services.root_cert_store_provider.clone(),
|
||||
options.unsafely_ignore_certificate_errors.clone(),
|
||||
),
|
||||
deno_webstorage::deno_webstorage::init(
|
||||
options.origin_storage_dir.clone(),
|
||||
),
|
||||
deno_crypto::deno_crypto::init(options.seed),
|
||||
deno_broadcast_channel::deno_broadcast_channel::init(
|
||||
services.broadcast_channel.clone(),
|
||||
),
|
||||
deno_ffi::deno_ffi::init::<PermissionsContainer>(
|
||||
services.deno_rt_native_addon_loader.clone(),
|
||||
),
|
||||
deno_net::deno_net::init::<PermissionsContainer>(
|
||||
services.root_cert_store_provider.clone(),
|
||||
options.unsafely_ignore_certificate_errors.clone(),
|
||||
),
|
||||
deno_tls::deno_tls::init(),
|
||||
deno_kv::deno_kv::init(
|
||||
MultiBackendDbHandler::remote_or_sqlite::<PermissionsContainer>(
|
||||
options.origin_storage_dir.clone(),
|
||||
options.seed,
|
||||
deno_kv::remote::HttpOptions {
|
||||
user_agent: options.bootstrap.user_agent.clone(),
|
||||
root_cert_store_provider: services.root_cert_store_provider.clone(),
|
||||
unsafely_ignore_certificate_errors: options
|
||||
.unsafely_ignore_certificate_errors
|
||||
.clone(),
|
||||
client_cert_chain_and_key: TlsKeys::Null,
|
||||
proxy: None,
|
||||
},
|
||||
),
|
||||
deno_kv::KvConfig::builder().build(),
|
||||
),
|
||||
deno_cron::deno_cron::init(LocalCronHandler::new()),
|
||||
deno_napi::deno_napi::init::<PermissionsContainer>(
|
||||
services.deno_rt_native_addon_loader.clone(),
|
||||
),
|
||||
deno_http::deno_http::init(deno_http::Options {
|
||||
no_legacy_abort: options.bootstrap.no_legacy_abort,
|
||||
..Default::default()
|
||||
}),
|
||||
deno_io::deno_io::init(Some(options.stdio)),
|
||||
deno_fs::deno_fs::init::<PermissionsContainer>(services.fs.clone()),
|
||||
deno_os::deno_os::init(Some(exit_code.clone())),
|
||||
deno_process::deno_process::init(services.npm_process_state_provider),
|
||||
deno_node::deno_node::init::<
|
||||
PermissionsContainer,
|
||||
TInNpmPackageChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TExtNodeSys,
|
||||
>(services.node_services, services.fs),
|
||||
// Ops from this crate
|
||||
ops::runtime::deno_runtime::init(main_module.clone()),
|
||||
ops::worker_host::deno_worker_host::init(
|
||||
options.create_web_worker_cb.clone(),
|
||||
options.format_js_error_fn.clone(),
|
||||
),
|
||||
ops::fs_events::deno_fs_events::init(),
|
||||
ops::permissions::deno_permissions::init(),
|
||||
ops::tty::deno_tty::init(),
|
||||
ops::http::deno_http_runtime::init(),
|
||||
ops::bootstrap::deno_bootstrap::init(
|
||||
if options.startup_snapshot.is_some() {
|
||||
None
|
||||
} else {
|
||||
Some(Default::default())
|
||||
},
|
||||
),
|
||||
runtime::init(),
|
||||
// NOTE(bartlomieju): this is done, just so that ops from this extension
|
||||
// are available and importing them in `99_main.js` doesn't cause an
|
||||
// error because they're not defined. Trying to use these ops in non-worker
|
||||
// context will cause a panic.
|
||||
ops::web_worker::deno_web_worker::init().disable(),
|
||||
];
|
||||
// check options that require configuring a new jsruntime
|
||||
if options.unconfigured_runtime.is_some()
|
||||
&& (options.enable_stack_trace_arg_in_ops
|
||||
|| op_metrics_factory_fn.is_some())
|
||||
{
|
||||
options.unconfigured_runtime = None;
|
||||
}
|
||||
|
||||
#[cfg(feature = "hmr")]
|
||||
assert!(
|
||||
|
@ -488,56 +403,35 @@ impl MainWorker {
|
|||
"'hmr' is incompatible with 'only_snapshotted_js_sources'."
|
||||
);
|
||||
|
||||
for extension in &mut extensions {
|
||||
if options.startup_snapshot.is_some() {
|
||||
extension.js_files = std::borrow::Cow::Borrowed(&[]);
|
||||
extension.esm_files = std::borrow::Cow::Borrowed(&[]);
|
||||
extension.esm_entry_point = None;
|
||||
}
|
||||
}
|
||||
|
||||
extensions.extend(std::mem::take(&mut options.extensions));
|
||||
|
||||
#[cfg(feature = "only_snapshotted_js_sources")]
|
||||
options.startup_snapshot.as_ref().expect("A user snapshot was not provided, even though 'only_snapshotted_js_sources' is used.");
|
||||
|
||||
let has_notified_of_inspector_disconnect = AtomicBool::new(false);
|
||||
let wait_for_inspector_disconnect_callback = Box::new(move || {
|
||||
if !has_notified_of_inspector_disconnect
|
||||
.swap(true, std::sync::atomic::Ordering::SeqCst)
|
||||
{
|
||||
log::info!("Program finished. Waiting for inspector to disconnect to exit the process...");
|
||||
}
|
||||
});
|
||||
let mut js_runtime = if let Some(u) = options.unconfigured_runtime {
|
||||
u.hydrate(services.module_loader)
|
||||
} else {
|
||||
let mut extensions = common_extensions::<
|
||||
TInNpmPackageChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TExtNodeSys,
|
||||
>(options.startup_snapshot.is_some(), false);
|
||||
|
||||
let mut js_runtime = JsRuntime::new(RuntimeOptions {
|
||||
module_loader: Some(services.module_loader.clone()),
|
||||
startup_snapshot: options.startup_snapshot,
|
||||
create_params: options.create_params,
|
||||
skip_op_registration: options.skip_op_registration,
|
||||
shared_array_buffer_store: services.shared_array_buffer_store.clone(),
|
||||
compiled_wasm_module_store: services.compiled_wasm_module_store.clone(),
|
||||
extensions,
|
||||
#[cfg(feature = "transpile")]
|
||||
extension_transpiler: Some(Rc::new(|specifier, source| {
|
||||
crate::transpile::maybe_transpile_source(specifier, source)
|
||||
})),
|
||||
#[cfg(not(feature = "transpile"))]
|
||||
extension_transpiler: None,
|
||||
inspector: true,
|
||||
is_main: true,
|
||||
op_metrics_factory_fn,
|
||||
wait_for_inspector_disconnect_callback: Some(
|
||||
wait_for_inspector_disconnect_callback,
|
||||
),
|
||||
import_meta_resolve_callback: Some(Box::new(
|
||||
import_meta_resolve_callback,
|
||||
)),
|
||||
validate_import_attributes_cb: Some(Box::new(
|
||||
validate_import_attributes_callback,
|
||||
)),
|
||||
import_assertions_support: deno_core::ImportAssertionsSupport::Error,
|
||||
eval_context_code_cache_cbs: services.v8_code_cache.map(|cache| {
|
||||
extensions.extend(std::mem::take(&mut options.extensions));
|
||||
|
||||
common_runtime(
|
||||
services.module_loader.clone(),
|
||||
options.startup_snapshot,
|
||||
options.create_params,
|
||||
options.skip_op_registration,
|
||||
services.shared_array_buffer_store,
|
||||
services.compiled_wasm_module_store,
|
||||
extensions,
|
||||
op_metrics_factory_fn,
|
||||
options.enable_stack_trace_arg_in_ops,
|
||||
)
|
||||
};
|
||||
|
||||
js_runtime.set_eval_context_code_cache_cbs(services.v8_code_cache.map(
|
||||
|cache| {
|
||||
let cache_clone = cache.clone();
|
||||
(
|
||||
Box::new(move |specifier: &ModuleSpecifier, code: &v8::String| {
|
||||
|
@ -549,12 +443,14 @@ impl MainWorker {
|
|||
hasher.finish()
|
||||
};
|
||||
let data = cache
|
||||
.get_sync(specifier, CodeCacheType::Script, source_hash)
|
||||
.inspect(|_| {
|
||||
// This log line is also used by tests.
|
||||
log::debug!("V8 code cache hit for script: {specifier}, [{source_hash}]");
|
||||
})
|
||||
.map(Cow::Owned);
|
||||
.get_sync(specifier, CodeCacheType::Script, source_hash)
|
||||
.inspect(|_| {
|
||||
// This log line is also used by tests.
|
||||
log::debug!(
|
||||
"V8 code cache hit for script: {specifier}, [{source_hash}]"
|
||||
);
|
||||
})
|
||||
.map(Cow::Owned);
|
||||
Ok(SourceCodeCacheInfo {
|
||||
data,
|
||||
hash: source_hash,
|
||||
|
@ -563,7 +459,9 @@ impl MainWorker {
|
|||
Box::new(
|
||||
move |specifier: ModuleSpecifier, source_hash: u64, data: &[u8]| {
|
||||
// This log line is also used by tests.
|
||||
log::debug!("Updating V8 code cache for script: {specifier}, [{source_hash}]");
|
||||
log::debug!(
|
||||
"Updating V8 code cache for script: {specifier}, [{source_hash}]"
|
||||
);
|
||||
cache_clone.set_sync(
|
||||
specifier,
|
||||
CodeCacheType::Script,
|
||||
|
@ -573,14 +471,89 @@ impl MainWorker {
|
|||
},
|
||||
) as Box<dyn Fn(_, _, &_)>,
|
||||
)
|
||||
}),
|
||||
maybe_op_stack_trace_callback: if options.enable_stack_trace_arg_in_ops {
|
||||
Some(Box::new(|stack| {
|
||||
deno_permissions::prompter::set_current_stacktrace(stack)
|
||||
}))
|
||||
} else { None },
|
||||
..Default::default()
|
||||
});
|
||||
},
|
||||
));
|
||||
|
||||
js_runtime
|
||||
.lazy_init_extensions(vec![
|
||||
deno_web::deno_web::args::<PermissionsContainer>(
|
||||
services.blob_store.clone(),
|
||||
options.bootstrap.location.clone(),
|
||||
),
|
||||
deno_fetch::deno_fetch::args::<PermissionsContainer>(
|
||||
deno_fetch::Options {
|
||||
user_agent: options.bootstrap.user_agent.clone(),
|
||||
root_cert_store_provider: services.root_cert_store_provider.clone(),
|
||||
unsafely_ignore_certificate_errors: options
|
||||
.unsafely_ignore_certificate_errors
|
||||
.clone(),
|
||||
file_fetch_handler: Rc::new(deno_fetch::FsFetchHandler),
|
||||
resolver: services.fetch_dns_resolver,
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
deno_cache::deno_cache::args(create_cache),
|
||||
deno_websocket::deno_websocket::args::<PermissionsContainer>(
|
||||
options.bootstrap.user_agent.clone(),
|
||||
services.root_cert_store_provider.clone(),
|
||||
options.unsafely_ignore_certificate_errors.clone(),
|
||||
),
|
||||
deno_webstorage::deno_webstorage::args(
|
||||
options.origin_storage_dir.clone(),
|
||||
),
|
||||
deno_crypto::deno_crypto::args(options.seed),
|
||||
deno_broadcast_channel::deno_broadcast_channel::args(
|
||||
services.broadcast_channel.clone(),
|
||||
),
|
||||
deno_ffi::deno_ffi::args::<PermissionsContainer>(
|
||||
services.deno_rt_native_addon_loader.clone(),
|
||||
),
|
||||
deno_net::deno_net::args::<PermissionsContainer>(
|
||||
services.root_cert_store_provider.clone(),
|
||||
options.unsafely_ignore_certificate_errors.clone(),
|
||||
),
|
||||
deno_kv::deno_kv::args(
|
||||
MultiBackendDbHandler::remote_or_sqlite::<PermissionsContainer>(
|
||||
options.origin_storage_dir.clone(),
|
||||
options.seed,
|
||||
deno_kv::remote::HttpOptions {
|
||||
user_agent: options.bootstrap.user_agent.clone(),
|
||||
root_cert_store_provider: services
|
||||
.root_cert_store_provider
|
||||
.clone(),
|
||||
unsafely_ignore_certificate_errors: options
|
||||
.unsafely_ignore_certificate_errors
|
||||
.clone(),
|
||||
client_cert_chain_and_key: TlsKeys::Null,
|
||||
proxy: None,
|
||||
},
|
||||
),
|
||||
deno_kv::KvConfig::builder().build(),
|
||||
),
|
||||
deno_napi::deno_napi::args::<PermissionsContainer>(
|
||||
services.deno_rt_native_addon_loader.clone(),
|
||||
),
|
||||
deno_http::deno_http::args(deno_http::Options {
|
||||
no_legacy_abort: options.bootstrap.no_legacy_abort,
|
||||
..Default::default()
|
||||
}),
|
||||
deno_io::deno_io::args(Some(options.stdio)),
|
||||
deno_fs::deno_fs::args::<PermissionsContainer>(services.fs.clone()),
|
||||
deno_os::deno_os::args(Some(exit_code.clone())),
|
||||
deno_process::deno_process::args(services.npm_process_state_provider),
|
||||
deno_node::deno_node::args::<
|
||||
PermissionsContainer,
|
||||
TInNpmPackageChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TExtNodeSys,
|
||||
>(services.node_services, services.fs.clone()),
|
||||
ops::runtime::deno_runtime::args(main_module.clone()),
|
||||
ops::worker_host::deno_worker_host::args(
|
||||
options.create_web_worker_cb.clone(),
|
||||
options.format_js_error_fn.clone(),
|
||||
),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
if let Some(op_summary_metrics) = op_summary_metrics {
|
||||
js_runtime.op_state().borrow_mut().put(op_summary_metrics);
|
||||
|
@ -958,3 +931,265 @@ impl MainWorker {
|
|||
Ok(ret_val.is_true())
|
||||
}
|
||||
}
|
||||
|
||||
fn common_extensions<
|
||||
TInNpmPackageChecker: InNpmPackageChecker + 'static,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
|
||||
TExtNodeSys: ExtNodeSys + 'static,
|
||||
>(
|
||||
has_snapshot: bool,
|
||||
unconfigured_runtime: bool,
|
||||
) -> Vec<Extension> {
|
||||
// NOTE(bartlomieju): ordering is important here, keep it in sync with
|
||||
// `runtime/worker.rs`, `runtime/web_worker.rs`, `runtime/snapshot_info.rs`
|
||||
// and `runtime/snapshot.rs`!
|
||||
vec![
|
||||
deno_telemetry::deno_telemetry::init(),
|
||||
// Web APIs
|
||||
deno_webidl::deno_webidl::init(),
|
||||
deno_console::deno_console::init(),
|
||||
deno_url::deno_url::init(),
|
||||
deno_web::deno_web::lazy_init::<PermissionsContainer>(),
|
||||
deno_webgpu::deno_webgpu::init(),
|
||||
deno_canvas::deno_canvas::init(),
|
||||
deno_fetch::deno_fetch::lazy_init::<PermissionsContainer>(),
|
||||
deno_cache::deno_cache::lazy_init(),
|
||||
deno_websocket::deno_websocket::lazy_init::<PermissionsContainer>(),
|
||||
deno_webstorage::deno_webstorage::lazy_init(),
|
||||
deno_crypto::deno_crypto::lazy_init(),
|
||||
deno_broadcast_channel::deno_broadcast_channel::lazy_init::<
|
||||
InMemoryBroadcastChannel,
|
||||
>(),
|
||||
deno_ffi::deno_ffi::lazy_init::<PermissionsContainer>(),
|
||||
deno_net::deno_net::lazy_init::<PermissionsContainer>(),
|
||||
deno_tls::deno_tls::init(),
|
||||
deno_kv::deno_kv::lazy_init::<MultiBackendDbHandler>(),
|
||||
deno_cron::deno_cron::init(LocalCronHandler::new()),
|
||||
deno_napi::deno_napi::lazy_init::<PermissionsContainer>(),
|
||||
deno_http::deno_http::lazy_init(),
|
||||
deno_io::deno_io::lazy_init(),
|
||||
deno_fs::deno_fs::lazy_init::<PermissionsContainer>(),
|
||||
deno_os::deno_os::lazy_init(),
|
||||
deno_process::deno_process::lazy_init(),
|
||||
deno_node::deno_node::lazy_init::<
|
||||
PermissionsContainer,
|
||||
TInNpmPackageChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TExtNodeSys,
|
||||
>(),
|
||||
// Ops from this crate
|
||||
ops::runtime::deno_runtime::lazy_init(),
|
||||
ops::worker_host::deno_worker_host::lazy_init(),
|
||||
ops::fs_events::deno_fs_events::init(),
|
||||
ops::permissions::deno_permissions::init(),
|
||||
ops::tty::deno_tty::init(),
|
||||
ops::http::deno_http_runtime::init(),
|
||||
ops::bootstrap::deno_bootstrap::init(
|
||||
has_snapshot.then(Default::default),
|
||||
unconfigured_runtime,
|
||||
),
|
||||
runtime::init(),
|
||||
// NOTE(bartlomieju): this is done, just so that ops from this extension
|
||||
// are available and importing them in `99_main.js` doesn't cause an
|
||||
// error because they're not defined. Trying to use these ops in non-worker
|
||||
// context will cause a panic.
|
||||
ops::web_worker::deno_web_worker::init().disable(),
|
||||
]
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn common_runtime(
|
||||
module_loader: Rc<dyn ModuleLoader>,
|
||||
startup_snapshot: Option<&'static [u8]>,
|
||||
create_params: Option<v8::CreateParams>,
|
||||
skip_op_registration: bool,
|
||||
shared_array_buffer_store: Option<SharedArrayBufferStore>,
|
||||
compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
|
||||
extensions: Vec<Extension>,
|
||||
op_metrics_factory_fn: Option<OpMetricsFactoryFn>,
|
||||
enable_stack_trace_arg_in_ops: bool,
|
||||
) -> JsRuntime {
|
||||
JsRuntime::new(RuntimeOptions {
|
||||
module_loader: Some(module_loader),
|
||||
startup_snapshot,
|
||||
create_params,
|
||||
skip_op_registration,
|
||||
shared_array_buffer_store,
|
||||
compiled_wasm_module_store,
|
||||
extensions,
|
||||
#[cfg(feature = "transpile")]
|
||||
extension_transpiler: Some(Rc::new(|specifier, source| {
|
||||
crate::transpile::maybe_transpile_source(specifier, source)
|
||||
})),
|
||||
#[cfg(not(feature = "transpile"))]
|
||||
extension_transpiler: None,
|
||||
inspector: true,
|
||||
is_main: true,
|
||||
op_metrics_factory_fn,
|
||||
wait_for_inspector_disconnect_callback: Some(
|
||||
make_wait_for_inspector_disconnect_callback(),
|
||||
),
|
||||
import_meta_resolve_callback: Some(Box::new(import_meta_resolve_callback)),
|
||||
validate_import_attributes_cb: Some(Box::new(
|
||||
validate_import_attributes_callback,
|
||||
)),
|
||||
import_assertions_support: deno_core::ImportAssertionsSupport::Error,
|
||||
maybe_op_stack_trace_callback: enable_stack_trace_arg_in_ops.then(|| {
|
||||
Box::new(|stack| {
|
||||
deno_permissions::prompter::set_current_stacktrace(stack)
|
||||
}) as _
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub struct UnconfiguredRuntime {
|
||||
module_loader: Rc<PlaceholderModuleLoader>,
|
||||
js_runtime: JsRuntime,
|
||||
}
|
||||
|
||||
impl UnconfiguredRuntime {
|
||||
pub fn new<
|
||||
TInNpmPackageChecker: InNpmPackageChecker + 'static,
|
||||
TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static,
|
||||
TExtNodeSys: ExtNodeSys + 'static,
|
||||
>(
|
||||
startup_snapshot: &'static [u8],
|
||||
create_params: Option<v8::CreateParams>,
|
||||
shared_array_buffer_store: Option<SharedArrayBufferStore>,
|
||||
compiled_wasm_module_store: Option<CompiledWasmModuleStore>,
|
||||
additional_extensions: Vec<Extension>,
|
||||
) -> Self {
|
||||
let mut extensions = common_extensions::<
|
||||
TInNpmPackageChecker,
|
||||
TNpmPackageFolderResolver,
|
||||
TExtNodeSys,
|
||||
>(true, true);
|
||||
|
||||
extensions.extend(additional_extensions);
|
||||
|
||||
let module_loader =
|
||||
Rc::new(PlaceholderModuleLoader(std::cell::RefCell::new(None)));
|
||||
|
||||
let js_runtime = common_runtime(
|
||||
module_loader.clone(),
|
||||
Some(startup_snapshot),
|
||||
create_params,
|
||||
true,
|
||||
shared_array_buffer_store,
|
||||
compiled_wasm_module_store,
|
||||
extensions,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
|
||||
UnconfiguredRuntime {
|
||||
module_loader,
|
||||
js_runtime,
|
||||
}
|
||||
}
|
||||
|
||||
fn hydrate(self, module_loader: Rc<dyn ModuleLoader>) -> JsRuntime {
|
||||
let _ = self.module_loader.0.borrow_mut().insert(module_loader);
|
||||
self.js_runtime
|
||||
}
|
||||
}
|
||||
|
||||
struct PlaceholderModuleLoader(
|
||||
std::cell::RefCell<Option<Rc<dyn ModuleLoader>>>,
|
||||
);
|
||||
|
||||
impl ModuleLoader for PlaceholderModuleLoader {
|
||||
fn resolve(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &str,
|
||||
kind: deno_core::ResolutionKind,
|
||||
) -> Result<ModuleSpecifier, deno_core::error::ModuleLoaderError> {
|
||||
self
|
||||
.0
|
||||
.borrow_mut()
|
||||
.clone()
|
||||
.unwrap()
|
||||
.resolve(specifier, referrer, kind)
|
||||
}
|
||||
|
||||
fn load(
|
||||
&self,
|
||||
module_specifier: &ModuleSpecifier,
|
||||
maybe_referrer: Option<&ModuleSpecifier>,
|
||||
is_dyn_import: bool,
|
||||
requested_module_type: deno_core::RequestedModuleType,
|
||||
) -> deno_core::ModuleLoadResponse {
|
||||
self.0.borrow_mut().clone().unwrap().load(
|
||||
module_specifier,
|
||||
maybe_referrer,
|
||||
is_dyn_import,
|
||||
requested_module_type,
|
||||
)
|
||||
}
|
||||
|
||||
fn prepare_load(
|
||||
&self,
|
||||
module_specifier: &ModuleSpecifier,
|
||||
maybe_referrer: Option<String>,
|
||||
is_dyn_import: bool,
|
||||
) -> std::pin::Pin<
|
||||
Box<
|
||||
dyn std::prelude::rust_2024::Future<
|
||||
Output = Result<(), deno_core::error::ModuleLoaderError>,
|
||||
>,
|
||||
>,
|
||||
> {
|
||||
self.0.borrow_mut().clone().unwrap().prepare_load(
|
||||
module_specifier,
|
||||
maybe_referrer,
|
||||
is_dyn_import,
|
||||
)
|
||||
}
|
||||
|
||||
fn finish_load(&self) {
|
||||
self.0.borrow_mut().clone().unwrap().finish_load()
|
||||
}
|
||||
|
||||
fn purge_and_prevent_code_cache(&self, module_specifier: &str) {
|
||||
self
|
||||
.0
|
||||
.borrow_mut()
|
||||
.clone()
|
||||
.unwrap()
|
||||
.purge_and_prevent_code_cache(module_specifier)
|
||||
}
|
||||
|
||||
fn get_source_map(&self, file_name: &str) -> Option<Cow<[u8]>> {
|
||||
let v = self.0.borrow_mut().clone().unwrap();
|
||||
let v = v.get_source_map(file_name);
|
||||
v.map(|c| Cow::from(c.into_owned()))
|
||||
}
|
||||
|
||||
fn get_source_mapped_source_line(
|
||||
&self,
|
||||
file_name: &str,
|
||||
line_number: usize,
|
||||
) -> Option<String> {
|
||||
self
|
||||
.0
|
||||
.borrow_mut()
|
||||
.clone()
|
||||
.unwrap()
|
||||
.get_source_mapped_source_line(file_name, line_number)
|
||||
}
|
||||
|
||||
fn get_host_defined_options<'s>(
|
||||
&self,
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
name: &str,
|
||||
) -> Option<v8::Local<'s, v8::Data>> {
|
||||
self
|
||||
.0
|
||||
.borrow_mut()
|
||||
.clone()
|
||||
.unwrap()
|
||||
.get_host_defined_options(scope, name)
|
||||
}
|
||||
}
|
||||
|
|
9
tests/specs/run/unconfigured/__test__.jsonc
Normal file
9
tests/specs/run/unconfigured/__test__.jsonc
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"tests": {
|
||||
"unconfigured": {
|
||||
"args": "run -A main.ts",
|
||||
"output": "main.out",
|
||||
"if": "unix"
|
||||
}
|
||||
}
|
||||
}
|
3
tests/specs/run/unconfigured/main.out
Normal file
3
tests/specs/run/unconfigured/main.out
Normal file
|
@ -0,0 +1,3 @@
|
|||
true
|
||||
hello world
|
||||
[Object: null prototype] { success: true, code: 0, signal: null }
|
50
tests/specs/run/unconfigured/main.ts
Normal file
50
tests/specs/run/unconfigured/main.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
const tempDirPath = await Deno.makeTempDir();
|
||||
|
||||
const sockPath = `${tempDirPath}/control.sock`;
|
||||
const testPath = `${tempDirPath}/test.ts`;
|
||||
|
||||
const command = new Deno.Command(Deno.execPath(), {
|
||||
env: {
|
||||
DENO_UNSTABLE_CONTROL_SOCK: `unix:${sockPath}`,
|
||||
},
|
||||
});
|
||||
|
||||
const child = command.spawn();
|
||||
|
||||
let i = 0;
|
||||
while (true) {
|
||||
try {
|
||||
await Deno.lstat(sockPath);
|
||||
break;
|
||||
} catch {}
|
||||
|
||||
i += 1;
|
||||
if (i > 100) {
|
||||
throw new Error(`${sockPath} did not exist`);
|
||||
}
|
||||
|
||||
await new Promise((r) => setTimeout(r, 10));
|
||||
}
|
||||
|
||||
const sock = await Deno.connect({
|
||||
transport: "unix",
|
||||
path: sockPath,
|
||||
});
|
||||
|
||||
Deno.writeTextFile(
|
||||
testPath,
|
||||
`
|
||||
console.log(Deno[Deno.internal].isFromUnconfiguredRuntime());
|
||||
console.log(Deno.env.get('A'));
|
||||
`,
|
||||
);
|
||||
|
||||
const data = JSON.stringify({
|
||||
cwd: tempDirPath,
|
||||
args: ["run", "-A", "test.ts"],
|
||||
env: [["A", "hello world"]],
|
||||
});
|
||||
|
||||
await sock.write(new TextEncoder().encode(data + "\n"));
|
||||
|
||||
console.log(await child.status);
|
Loading…
Add table
Add a link
Reference in a new issue