// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use std::env; use std::path::PathBuf; #[cfg(all( not(feature = "docsrs"), not(feature = "dont_create_runtime_snapshot") ))] mod startup_snapshot { use super::*; use deno_ast::MediaType; use deno_ast::ParseParams; use deno_ast::SourceTextInfo; use deno_cache::SqliteBackedCache; use deno_core::error::AnyError; use deno_core::snapshot_util::*; use deno_core::Extension; use deno_core::ExtensionFileSource; use deno_core::ModuleCode; use deno_http::DefaultHttpPropertyExtractor; use std::path::Path; fn transpile_ts_for_snapshotting( file_source: &ExtensionFileSource, ) -> Result { // Always transpile `node:` built-in modules, since they might be TypeScript. let media_type = if file_source.specifier.starts_with("node:") { MediaType::TypeScript } else { MediaType::from_path(Path::new(&file_source.specifier)) }; let should_transpile = match media_type { MediaType::JavaScript => false, MediaType::Mjs => false, MediaType::TypeScript => true, _ => { panic!( "Unsupported media type for snapshotting {media_type:?} for file {}", file_source.specifier ) } }; let code = file_source.load()?; if !should_transpile { return Ok(code); } let parsed = deno_ast::parse_module(ParseParams { specifier: file_source.specifier.to_string(), text_info: SourceTextInfo::from_string(code.as_str().to_owned()), media_type, capture_tokens: false, scope_analysis: false, maybe_syntax: None, })?; let transpiled_source = parsed.transpile(&deno_ast::EmitOptions { imports_not_used_as_values: deno_ast::ImportsNotUsedAsValues::Remove, inline_source_map: false, ..Default::default() })?; Ok(transpiled_source.text.into()) } #[derive(Clone)] struct Permissions; impl deno_fetch::FetchPermissions for Permissions { fn check_net_url( &mut self, _url: &deno_core::url::Url, _api_name: &str, ) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } fn check_read( &mut self, _p: &Path, _api_name: &str, ) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } } impl deno_websocket::WebSocketPermissions for Permissions { fn check_net_url( &mut self, _url: &deno_core::url::Url, _api_name: &str, ) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } } impl deno_web::TimersPermission for Permissions { fn allow_hrtime(&mut self) -> bool { unreachable!("snapshotting!") } fn check_unstable( &self, _state: &deno_core::OpState, _api_name: &'static str, ) { unreachable!("snapshotting!") } } impl deno_ffi::FfiPermissions for Permissions { fn check( &mut self, _path: Option<&Path>, ) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } } impl deno_napi::NapiPermissions for Permissions { fn check( &mut self, _path: Option<&Path>, ) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } } impl deno_node::NodePermissions for Permissions { fn check_net_url( &mut self, _url: &deno_core::url::Url, _api_name: &str, ) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } fn check_read(&self, _p: &Path) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } } impl deno_net::NetPermissions for Permissions { fn check_net>( &mut self, _host: &(T, Option), _api_name: &str, ) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } fn check_read( &mut self, _p: &Path, _api_name: &str, ) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } fn check_write( &mut self, _p: &Path, _api_name: &str, ) -> Result<(), deno_core::error::AnyError> { unreachable!("snapshotting!") } } impl deno_fs::FsPermissions for Permissions { fn check_read( &mut self, _path: &Path, _api_name: &str, ) -> Result<(), AnyError> { unreachable!("snapshotting!") } fn check_read_all(&mut self, _api_name: &str) -> Result<(), AnyError> { unreachable!("snapshotting!") } fn check_read_blind( &mut self, _path: &Path, _display: &str, _api_name: &str, ) -> Result<(), AnyError> { unreachable!("snapshotting!") } fn check_write( &mut self, _path: &Path, _api_name: &str, ) -> Result<(), AnyError> { unreachable!("snapshotting!") } fn check_write_all(&mut self, _api_name: &str) -> Result<(), AnyError> { unreachable!("snapshotting!") } fn check_write_blind( &mut self, _path: &Path, _display: &str, _api_name: &str, ) -> Result<(), AnyError> { unreachable!("snapshotting!") } } impl deno_kv::sqlite::SqliteDbHandlerPermissions for Permissions { fn check_read( &mut self, _path: &Path, _api_name: &str, ) -> Result<(), AnyError> { unreachable!("snapshotting!") } fn check_write( &mut self, _path: &Path, _api_name: &str, ) -> Result<(), AnyError> { unreachable!("snapshotting!") } } deno_core::extension!(runtime, deps = [ deno_webidl, deno_console, deno_url, deno_tls, deno_web, deno_fetch, deno_cache, deno_websocket, deno_webstorage, deno_crypto, deno_broadcast_channel, // FIXME(bartlomieju): this should be reenabled // "deno_node", deno_ffi, deno_net, deno_napi, deno_http, deno_io, deno_fs ], esm = [ dir "js", "01_errors.js", "01_version.ts", "06_util.js", "10_permissions.js", "11_workers.js", "13_buffer.js", "30_os.js", "40_fs_events.js", "40_http.js", "40_process.js", "40_signals.js", "40_tty.js", "41_prompt.js", "90_deno_ns.js", "98_global_scope.js" ], ); #[cfg(not(feature = "snapshot_from_snapshot"))] deno_core::extension!( runtime_main, deps = [runtime], customizer = |ext: &mut deno_core::ExtensionBuilder| { ext.esm(vec![ExtensionFileSource { specifier: "ext:runtime_main/js/99_main.js", code: deno_core::ExtensionFileSourceCode::IncludedInBinary( include_str!("js/99_main.js"), ), }]); ext.esm_entry_point("ext:runtime_main/js/99_main.js"); } ); #[cfg(feature = "snapshot_from_snapshot")] deno_core::extension!( runtime_main, deps = [runtime], customizer = |ext: &mut deno_core::ExtensionBuilder| { ext.esm_entry_point("ext:runtime/90_deno_ns.js"); } ); pub fn create_runtime_snapshot(snapshot_path: PathBuf) { // NOTE(bartlomieju): ordering is important here, keep it in sync with // `runtime/worker.rs`, `runtime/web_worker.rs` and `cli/build.rs`! let fs = std::sync::Arc::new(deno_fs::RealFs); let extensions: Vec = vec![ deno_webidl::deno_webidl::init_ops_and_esm(), deno_console::deno_console::init_ops_and_esm(), deno_url::deno_url::init_ops_and_esm(), deno_web::deno_web::init_ops_and_esm::( Default::default(), Default::default(), ), deno_fetch::deno_fetch::init_ops_and_esm::( Default::default(), ), deno_cache::deno_cache::init_ops_and_esm::(None), deno_websocket::deno_websocket::init_ops_and_esm::( "".to_owned(), None, None, ), deno_webstorage::deno_webstorage::init_ops_and_esm(None), deno_crypto::deno_crypto::init_ops_and_esm(None), deno_broadcast_channel::deno_broadcast_channel::init_ops_and_esm( deno_broadcast_channel::InMemoryBroadcastChannel::default(), false, // No --unstable. ), deno_ffi::deno_ffi::init_ops_and_esm::(false), deno_net::deno_net::init_ops_and_esm::( None, false, // No --unstable. None, ), deno_tls::deno_tls::init_ops_and_esm(), deno_kv::deno_kv::init_ops_and_esm( deno_kv::sqlite::SqliteDbHandler::::new(None), false, // No --unstable ), deno_napi::deno_napi::init_ops_and_esm::(), deno_http::deno_http::init_ops_and_esm::(), deno_io::deno_io::init_ops_and_esm(Default::default()), deno_fs::deno_fs::init_ops_and_esm::(false, fs.clone()), runtime::init_ops_and_esm(), // FIXME(bartlomieju): these extensions are specified last, because they // depend on `runtime`, even though it should be other way around deno_node::deno_node::init_ops_and_esm::(None, fs), runtime_main::init_ops_and_esm(), ]; let output = create_snapshot(CreateSnapshotOptions { cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"), snapshot_path, startup_snapshot: None, extensions, compression_cb: None, snapshot_module_load_cb: Some(Box::new(transpile_ts_for_snapshotting)), }); for path in output.files_loaded_during_snapshot { println!("cargo:rerun-if-changed={}", path.display()); } } } fn main() { // To debug snapshot issues uncomment: // op_fetch_asset::trace_serializer(); println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap()); println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); let o = PathBuf::from(env::var_os("OUT_DIR").unwrap()); // Main snapshot let runtime_snapshot_path = o.join("RUNTIME_SNAPSHOT.bin"); // If we're building on docs.rs we just create // and empty snapshot file and return, because `rusty_v8` // doesn't actually compile on docs.rs if env::var_os("DOCS_RS").is_some() { let snapshot_slice = &[]; #[allow(clippy::needless_borrow)] #[allow(clippy::disallowed_methods)] std::fs::write(&runtime_snapshot_path, snapshot_slice).unwrap(); } #[cfg(all( not(feature = "docsrs"), not(feature = "dont_create_runtime_snapshot") ))] startup_snapshot::create_runtime_snapshot(runtime_snapshot_path) }