diff options
Diffstat (limited to 'cli/tsc')
-rw-r--r-- | cli/tsc/99_main_compiler.js | 43 | ||||
-rw-r--r-- | cli/tsc/mod.rs | 200 |
2 files changed, 139 insertions, 104 deletions
diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index a3cdad742..a0219fe13 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -385,7 +385,7 @@ delete Object.prototype.__proto__; // paths must be either relative or absolute. Since // analysis in Rust operates on fully resolved URLs, // it makes sense to use the same scheme here. - const ASSETS = "asset:///"; + const ASSETS_URL_PREFIX = "asset:///"; /** Diagnostics that are intentionally ignored when compiling TypeScript in * Deno, as they provide misleading or incorrect information. */ @@ -431,6 +431,7 @@ delete Object.prototype.__proto__; noEmit: true, strict: true, target: ts.ScriptTarget.ESNext, + lib: ["lib.deno.window.d.ts"], }; // todo(dsherret): can we remove this and just use ts.OperationCanceledException? @@ -546,10 +547,10 @@ delete Object.prototype.__proto__; return sourceFile; }, getDefaultLibFileName() { - return `${ASSETS}/lib.esnext.d.ts`; + return `${ASSETS_URL_PREFIX}lib.esnext.d.ts`; }, getDefaultLibLocation() { - return ASSETS; + return ASSETS_URL_PREFIX; }, writeFile(fileName, data, _writeByteOrderMark, _onError, _sourceFiles) { if (logDebug) { @@ -887,6 +888,20 @@ delete Object.prototype.__proto__; debug("<<< exec stop"); } + function getAssets() { + /** @type {{ specifier: string; text: string; }[]} */ + const assets = []; + for (const sourceFile of sourceFileCache.values()) { + if (sourceFile.fileName.startsWith(ASSETS_URL_PREFIX)) { + assets.push({ + specifier: sourceFile.fileName, + text: sourceFile.text, + }); + } + } + return assets; + } + /** * @param {number} id * @param {any} data @@ -935,16 +950,7 @@ delete Object.prototype.__proto__; ); } case "getAssets": { - const assets = []; - for (const sourceFile of sourceFileCache.values()) { - if (sourceFile.fileName.startsWith(ASSETS)) { - assets.push({ - specifier: sourceFile.fileName, - text: sourceFile.text, - }); - } - } - return respond(id, assets); + return respond(id, getAssets()); } case "getApplicableRefactors": { return respond( @@ -1281,7 +1287,10 @@ delete Object.prototype.__proto__; // we are caching in memory common type libraries that will be re-used by // tsc on when the snapshot is restored assert( - host.getSourceFile(`${ASSETS}${specifier}`, ts.ScriptTarget.ESNext), + host.getSourceFile( + `${ASSETS_URL_PREFIX}${specifier}`, + ts.ScriptTarget.ESNext, + ), ); } // this helps ensure as much as possible is in memory that is re-usable @@ -1292,12 +1301,16 @@ delete Object.prototype.__proto__; options: SNAPSHOT_COMPILE_OPTIONS, host, }); - ts.getPreEmitDiagnostics(TS_SNAPSHOT_PROGRAM); + assert(ts.getPreEmitDiagnostics(TS_SNAPSHOT_PROGRAM).length === 0); + + // remove this now that we don't need it anymore for warming up tsc + sourceFileCache.delete(buildSpecifier); // exposes the two functions that are called by `tsc::exec()` when type // checking TypeScript. globalThis.startup = startup; globalThis.exec = exec; + globalThis.getAssets = getAssets; // exposes the functions that are called when the compiler is used as a // language service. diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index 6ea037522..d540e5b33 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -25,6 +25,7 @@ use deno_core::serde::Serializer; use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::serde_json::Value; +use deno_core::serde_v8; use deno_core::Extension; use deno_core::JsRuntime; use deno_core::ModuleSpecifier; @@ -49,28 +50,6 @@ pub use self::diagnostics::DiagnosticMessageChain; pub use self::diagnostics::Diagnostics; pub use self::diagnostics::Position; -// Declaration files - -pub static DENO_NS_LIB: &str = include_str!("dts/lib.deno.ns.d.ts"); -pub static DENO_CONSOLE_LIB: &str = include_str!(env!("DENO_CONSOLE_LIB_PATH")); -pub static DENO_URL_LIB: &str = include_str!(env!("DENO_URL_LIB_PATH")); -pub static DENO_WEB_LIB: &str = include_str!(env!("DENO_WEB_LIB_PATH")); -pub static DENO_FETCH_LIB: &str = include_str!(env!("DENO_FETCH_LIB_PATH")); -pub static DENO_WEBGPU_LIB: &str = include_str!(env!("DENO_WEBGPU_LIB_PATH")); -pub static DENO_WEBSOCKET_LIB: &str = - include_str!(env!("DENO_WEBSOCKET_LIB_PATH")); -pub static DENO_WEBSTORAGE_LIB: &str = - include_str!(env!("DENO_WEBSTORAGE_LIB_PATH")); -pub static DENO_CACHE_LIB: &str = include_str!(env!("DENO_CACHE_LIB_PATH")); -pub static DENO_CRYPTO_LIB: &str = include_str!(env!("DENO_CRYPTO_LIB_PATH")); -pub static DENO_BROADCAST_CHANNEL_LIB: &str = - include_str!(env!("DENO_BROADCAST_CHANNEL_LIB_PATH")); -pub static DENO_NET_LIB: &str = include_str!(env!("DENO_NET_LIB_PATH")); -pub static SHARED_GLOBALS_LIB: &str = - include_str!("dts/lib.deno.shared_globals.d.ts"); -pub static WINDOW_LIB: &str = include_str!("dts/lib.deno.window.d.ts"); -pub static UNSTABLE_NS_LIB: &str = include_str!("dts/lib.deno.unstable.d.ts"); - pub static COMPILER_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new( #[cold] #[inline(never)] @@ -89,28 +68,57 @@ pub static COMPILER_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new( ); pub fn get_types_declaration_file_text(unstable: bool) -> String { - let mut types = vec![ - DENO_NS_LIB, - DENO_CONSOLE_LIB, - DENO_URL_LIB, - DENO_WEB_LIB, - DENO_FETCH_LIB, - DENO_WEBGPU_LIB, - DENO_WEBSOCKET_LIB, - DENO_WEBSTORAGE_LIB, - DENO_CRYPTO_LIB, - DENO_BROADCAST_CHANNEL_LIB, - DENO_NET_LIB, - SHARED_GLOBALS_LIB, - DENO_CACHE_LIB, - WINDOW_LIB, + let mut assets = get_asset_texts_from_new_runtime() + .unwrap() + .into_iter() + .map(|a| (a.specifier, a.text)) + .collect::<HashMap<_, _>>(); + + let mut lib_names = vec![ + "deno.ns", + "deno.console", + "deno.url", + "deno.web", + "deno.fetch", + "deno.webgpu", + "deno.websocket", + "deno.webstorage", + "deno.crypto", + "deno.broadcast_channel", + "deno.net", + "deno.shared_globals", + "deno.cache", + "deno.window", ]; if unstable { - types.push(UNSTABLE_NS_LIB); + lib_names.push("deno.unstable"); } - types.join("\n") + lib_names + .into_iter() + .map(|name| { + let asset_url = format!("asset:///lib.{}.d.ts", name); + assets.remove(&asset_url).unwrap() + }) + .collect::<Vec<_>>() + .join("\n") +} + +fn get_asset_texts_from_new_runtime() -> Result<Vec<AssetText>, AnyError> { + // the assets are stored within the typescript isolate, so take them out of there + let mut runtime = JsRuntime::new(RuntimeOptions { + startup_snapshot: Some(compiler_snapshot()), + extensions: vec![Extension::builder("deno_cli_tsc") + .ops(get_tsc_ops()) + .build()], + ..Default::default() + }); + let global = + runtime.execute_script("get_assets.js", "globalThis.getAssets()")?; + let scope = &mut runtime.handle_scope(); + let local = deno_core::v8::Local::new(scope, global); + Ok(serde_v8::from_v8::<Vec<AssetText>>(scope, local)?) } pub fn compiler_snapshot() -> Snapshot { @@ -124,40 +132,44 @@ macro_rules! inc { } /// Contains static assets that are not preloaded in the compiler snapshot. -pub static STATIC_ASSETS: Lazy<HashMap<&'static str, &'static str>> = - Lazy::new(|| { - ([ - ( - "lib.dom.asynciterable.d.ts", - inc!("lib.dom.asynciterable.d.ts"), - ), - ("lib.dom.d.ts", inc!("lib.dom.d.ts")), - ("lib.dom.extras.d.ts", inc!("lib.dom.extras.d.ts")), - ("lib.dom.iterable.d.ts", inc!("lib.dom.iterable.d.ts")), - ("lib.es6.d.ts", inc!("lib.es6.d.ts")), - ("lib.es2016.full.d.ts", inc!("lib.es2016.full.d.ts")), - ("lib.es2017.full.d.ts", inc!("lib.es2017.full.d.ts")), - ("lib.es2018.full.d.ts", inc!("lib.es2018.full.d.ts")), - ("lib.es2019.full.d.ts", inc!("lib.es2019.full.d.ts")), - ("lib.es2020.full.d.ts", inc!("lib.es2020.full.d.ts")), - ("lib.es2021.full.d.ts", inc!("lib.es2021.full.d.ts")), - ("lib.es2022.full.d.ts", inc!("lib.es2022.full.d.ts")), - ("lib.esnext.full.d.ts", inc!("lib.esnext.full.d.ts")), - ("lib.scripthost.d.ts", inc!("lib.scripthost.d.ts")), - ("lib.webworker.d.ts", inc!("lib.webworker.d.ts")), - ( - "lib.webworker.importscripts.d.ts", - inc!("lib.webworker.importscripts.d.ts"), - ), - ( - "lib.webworker.iterable.d.ts", - inc!("lib.webworker.iterable.d.ts"), - ), - ]) - .iter() - .cloned() - .collect() - }); +/// +/// We lazily load these because putting them in the compiler snapshot will +/// increase memory usage when not used (last time checked by about 0.5MB). +pub static LAZILY_LOADED_STATIC_ASSETS: Lazy< + HashMap<&'static str, &'static str>, +> = Lazy::new(|| { + ([ + ( + "lib.dom.asynciterable.d.ts", + inc!("lib.dom.asynciterable.d.ts"), + ), + ("lib.dom.d.ts", inc!("lib.dom.d.ts")), + ("lib.dom.extras.d.ts", inc!("lib.dom.extras.d.ts")), + ("lib.dom.iterable.d.ts", inc!("lib.dom.iterable.d.ts")), + ("lib.es6.d.ts", inc!("lib.es6.d.ts")), + ("lib.es2016.full.d.ts", inc!("lib.es2016.full.d.ts")), + ("lib.es2017.full.d.ts", inc!("lib.es2017.full.d.ts")), + ("lib.es2018.full.d.ts", inc!("lib.es2018.full.d.ts")), + ("lib.es2019.full.d.ts", inc!("lib.es2019.full.d.ts")), + ("lib.es2020.full.d.ts", inc!("lib.es2020.full.d.ts")), + ("lib.es2021.full.d.ts", inc!("lib.es2021.full.d.ts")), + ("lib.es2022.full.d.ts", inc!("lib.es2022.full.d.ts")), + ("lib.esnext.full.d.ts", inc!("lib.esnext.full.d.ts")), + ("lib.scripthost.d.ts", inc!("lib.scripthost.d.ts")), + ("lib.webworker.d.ts", inc!("lib.webworker.d.ts")), + ( + "lib.webworker.importscripts.d.ts", + inc!("lib.webworker.importscripts.d.ts"), + ), + ( + "lib.webworker.iterable.d.ts", + inc!("lib.webworker.iterable.d.ts"), + ), + ]) + .iter() + .cloned() + .collect() +}); /// A structure representing stats from a type check operation for a graph. #[derive(Clone, Debug, Default, Eq, PartialEq)] @@ -193,9 +205,16 @@ impl fmt::Display for Stats { } } +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AssetText { + pub specifier: String, + pub text: String, +} + /// Retrieve a static asset that are included in the binary. -pub fn get_asset(asset: &str) -> Option<&'static str> { - STATIC_ASSETS.get(asset).map(|s| s.to_owned()) +fn get_lazily_loaded_asset(asset: &str) -> Option<&'static str> { + LAZILY_LOADED_STATIC_ASSETS.get(asset).map(|s| s.to_owned()) } fn get_maybe_hash( @@ -501,9 +520,8 @@ fn op_load(state: &mut OpState, args: Value) -> Result<Value, AnyError> { hash = Some("1".to_string()); media_type = MediaType::Dts; Some(Cow::Borrowed("declare const __: any;\nexport = __;\n")) - } else if v.specifier.starts_with("asset:///") { - let name = v.specifier.replace("asset:///", ""); - let maybe_source = get_asset(&name); + } else if let Some(name) = v.specifier.strip_prefix("asset:///") { + let maybe_source = get_lazily_loaded_asset(name); hash = get_maybe_hash(maybe_source, &state.hash_data); media_type = MediaType::from(&v.specifier); maybe_source.map(Cow::Borrowed) @@ -774,16 +792,7 @@ pub fn exec(request: Request) -> Result<Response, AnyError> { let mut runtime = JsRuntime::new(RuntimeOptions { startup_snapshot: Some(compiler_snapshot()), extensions: vec![Extension::builder("deno_cli_tsc") - .ops(vec![ - op_cwd::decl(), - op_create_hash::decl(), - op_emit::decl(), - op_exists::decl(), - op_is_node_file::decl(), - op_load::decl(), - op_resolve::decl(), - op_respond::decl(), - ]) + .ops(get_tsc_ops()) .state(move |state| { state.put(State::new( request.graph_data.clone(), @@ -833,6 +842,19 @@ pub fn exec(request: Request) -> Result<Response, AnyError> { } } +fn get_tsc_ops() -> Vec<deno_core::OpDecl> { + vec![ + op_cwd::decl(), + op_create_hash::decl(), + op_emit::decl(), + op_exists::decl(), + op_is_node_file::decl(), + op_load::decl(), + op_resolve::decl(), + op_respond::decl(), + ] +} + #[cfg(test)] mod tests { use super::Diagnostic; @@ -1089,7 +1111,7 @@ mod tests { .expect("should have invoked op"); let actual: LoadResponse = serde_json::from_value(value).expect("failed to deserialize"); - let expected = get_asset("lib.dom.d.ts").unwrap(); + let expected = get_lazily_loaded_asset("lib.dom.d.ts").unwrap(); assert_eq!(actual.data, expected); assert!(actual.version.is_some()); assert_eq!(actual.script_kind, 3); |