bootstrap-window.ts 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. ;(function () {
  6. type ISandboxConfiguration =
  7. import("./deps/vscode/vs/base/parts/sandbox/common/sandboxTypes.js").ISandboxConfiguration
  8. type ILoadResult<
  9. M,
  10. T extends ISandboxConfiguration,
  11. > = import("./deps/vscode/vs/platform/window/electron-sandbox/window.js").ILoadResult<M, T>
  12. type ILoadOptions<T extends ISandboxConfiguration> =
  13. import("./deps/vscode/vs/platform/window/electron-sandbox/window.js").ILoadOptions<T>
  14. type IMainWindowSandboxGlobals =
  15. import("./deps/vscode/vs/base/parts/sandbox/electron-sandbox/globals.js").IMainWindowSandboxGlobals
  16. const preloadGlobals: IMainWindowSandboxGlobals = (window as any).vscode // defined by preload.ts
  17. const safeProcess = preloadGlobals.process
  18. async function load<M, T extends ISandboxConfiguration>(
  19. esModule: string,
  20. options: ILoadOptions<T>,
  21. ): Promise<ILoadResult<M, T>> {
  22. // Window Configuration from Preload Script
  23. const configuration = await resolveWindowConfiguration<T>()
  24. // Signal before import()
  25. options?.beforeImport?.(configuration)
  26. // Developer settings
  27. const {
  28. enableDeveloperKeybindings,
  29. removeDeveloperKeybindingsAfterLoad,
  30. developerDeveloperKeybindingsDisposable,
  31. forceDisableShowDevtoolsOnError,
  32. } = setupDeveloperKeybindings(configuration, options)
  33. // NLS
  34. setupNLS<T>(configuration)
  35. // Compute base URL and set as global
  36. const baseUrl = new URL(
  37. `${fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === "win32", scheme: "vscode-file", fallbackAuthority: "vscode-app" })}/out/`,
  38. )
  39. globalThis._VSCODE_FILE_ROOT = baseUrl.toString()
  40. // Dev only: CSS import map tricks
  41. setupCSSImportMaps<T>(configuration, baseUrl)
  42. // ESM Import
  43. try {
  44. const result = await import(new URL(`${esModule}.js`, baseUrl).href)
  45. if (developerDeveloperKeybindingsDisposable && removeDeveloperKeybindingsAfterLoad) {
  46. developerDeveloperKeybindingsDisposable()
  47. }
  48. return { result, configuration }
  49. } catch (error) {
  50. onUnexpectedError(error, enableDeveloperKeybindings && !forceDisableShowDevtoolsOnError)
  51. throw error
  52. }
  53. }
  54. async function resolveWindowConfiguration<T extends ISandboxConfiguration>() {
  55. const timeout = setTimeout(() => {
  56. console.error(
  57. `[resolve window config] Could not resolve window configuration within 10 seconds, but will continue to wait...`,
  58. )
  59. }, 10000)
  60. performance.mark("code/willWaitForWindowConfig")
  61. const configuration = (await preloadGlobals.context.resolveConfiguration()) as T
  62. performance.mark("code/didWaitForWindowConfig")
  63. clearTimeout(timeout)
  64. return configuration
  65. }
  66. function setupDeveloperKeybindings<T extends ISandboxConfiguration>(configuration: T, options: ILoadOptions<T>) {
  67. const {
  68. forceEnableDeveloperKeybindings,
  69. disallowReloadKeybinding,
  70. removeDeveloperKeybindingsAfterLoad,
  71. forceDisableShowDevtoolsOnError,
  72. } =
  73. typeof options?.configureDeveloperSettings === "function"
  74. ? options.configureDeveloperSettings(configuration)
  75. : {
  76. forceEnableDeveloperKeybindings: false,
  77. disallowReloadKeybinding: false,
  78. removeDeveloperKeybindingsAfterLoad: false,
  79. forceDisableShowDevtoolsOnError: false,
  80. }
  81. const isDev = !!safeProcess.env["VSCODE_DEV"]
  82. const enableDeveloperKeybindings = Boolean(isDev || forceEnableDeveloperKeybindings)
  83. let developerDeveloperKeybindingsDisposable: Function | undefined = undefined
  84. if (enableDeveloperKeybindings) {
  85. developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding)
  86. }
  87. return {
  88. enableDeveloperKeybindings,
  89. removeDeveloperKeybindingsAfterLoad,
  90. developerDeveloperKeybindingsDisposable,
  91. forceDisableShowDevtoolsOnError,
  92. }
  93. }
  94. function registerDeveloperKeybindings(disallowReloadKeybinding: boolean | undefined): Function {
  95. const ipcRenderer = preloadGlobals.ipcRenderer
  96. const extractKey = function (e: KeyboardEvent) {
  97. return [
  98. e.ctrlKey ? "ctrl-" : "",
  99. e.metaKey ? "meta-" : "",
  100. e.altKey ? "alt-" : "",
  101. e.shiftKey ? "shift-" : "",
  102. e.keyCode,
  103. ].join("")
  104. }
  105. // Devtools & reload support
  106. const TOGGLE_DEV_TOOLS_KB = safeProcess.platform === "darwin" ? "meta-alt-73" : "ctrl-shift-73" // mac: Cmd-Alt-I, rest: Ctrl-Shift-I
  107. const TOGGLE_DEV_TOOLS_KB_ALT = "123" // F12
  108. const RELOAD_KB = safeProcess.platform === "darwin" ? "meta-82" : "ctrl-82" // mac: Cmd-R, rest: Ctrl-R
  109. let listener: ((e: KeyboardEvent) => void) | undefined = function (e) {
  110. const key = extractKey(e)
  111. if (key === TOGGLE_DEV_TOOLS_KB || key === TOGGLE_DEV_TOOLS_KB_ALT) {
  112. ipcRenderer.send("vscode:toggleDevTools")
  113. } else if (key === RELOAD_KB && !disallowReloadKeybinding) {
  114. ipcRenderer.send("vscode:reloadWindow")
  115. }
  116. }
  117. window.addEventListener("keydown", listener)
  118. return function () {
  119. if (listener) {
  120. window.removeEventListener("keydown", listener)
  121. listener = undefined
  122. }
  123. }
  124. }
  125. function setupNLS<T extends ISandboxConfiguration>(configuration: T): void {
  126. globalThis._VSCODE_NLS_MESSAGES = configuration.nls.messages
  127. globalThis._VSCODE_NLS_LANGUAGE = configuration.nls.language
  128. let language = configuration.nls.language || "en"
  129. if (language === "zh-tw") {
  130. language = "zh-Hant"
  131. } else if (language === "zh-cn") {
  132. language = "zh-Hans"
  133. }
  134. window.document.documentElement.setAttribute("lang", language)
  135. }
  136. function onUnexpectedError(error: string | Error, showDevtoolsOnError: boolean): void {
  137. if (showDevtoolsOnError) {
  138. const ipcRenderer = preloadGlobals.ipcRenderer
  139. ipcRenderer.send("vscode:openDevTools")
  140. }
  141. console.error(`[uncaught exception]: ${error}`)
  142. if (error && typeof error !== "string" && error.stack) {
  143. console.error(error.stack)
  144. }
  145. }
  146. function fileUriFromPath(
  147. path: string,
  148. config: { isWindows?: boolean; scheme?: string; fallbackAuthority?: string },
  149. ): string {
  150. // Since we are building a URI, we normalize any backslash
  151. // to slashes and we ensure that the path begins with a '/'.
  152. let pathName = path.replace(/\\/g, "/")
  153. if (pathName.length > 0 && pathName.charAt(0) !== "/") {
  154. pathName = `/${pathName}`
  155. }
  156. let uri: string
  157. // Windows: in order to support UNC paths (which start with '//')
  158. // that have their own authority, we do not use the provided authority
  159. // but rather preserve it.
  160. if (config.isWindows && pathName.startsWith("//")) {
  161. uri = encodeURI(`${config.scheme || "file"}:${pathName}`)
  162. }
  163. // Otherwise we optionally add the provided authority if specified
  164. else {
  165. uri = encodeURI(`${config.scheme || "file"}://${config.fallbackAuthority || ""}${pathName}`)
  166. }
  167. return uri.replace(/#/g, "%23")
  168. }
  169. function setupCSSImportMaps<T extends ISandboxConfiguration>(configuration: T, baseUrl: URL) {
  170. // DEV ---------------------------------------------------------------------------------------
  171. // DEV: This is for development and enables loading CSS via import-statements via import-maps.
  172. // DEV: For each CSS modules that we have we defined an entry in the import map that maps to
  173. // DEV: a blob URL that loads the CSS via a dynamic @import-rule.
  174. // DEV ---------------------------------------------------------------------------------------
  175. if (Array.isArray(configuration.cssModules) && configuration.cssModules.length > 0) {
  176. performance.mark("code/willAddCssLoader")
  177. const style = document.createElement("style")
  178. style.type = "text/css"
  179. style.media = "screen"
  180. style.id = "vscode-css-loading"
  181. document.head.appendChild(style)
  182. globalThis._VSCODE_CSS_LOAD = function (url) {
  183. style.textContent += `@import url(${url});\n`
  184. }
  185. const importMap: { imports: Record<string, string> } = { imports: {} }
  186. for (const cssModule of configuration.cssModules) {
  187. const cssUrl = new URL(cssModule, baseUrl).href
  188. const jsSrc = `globalThis._VSCODE_CSS_LOAD('${cssUrl}');\n`
  189. const blob = new Blob([jsSrc], { type: "application/javascript" })
  190. importMap.imports[cssUrl] = URL.createObjectURL(blob)
  191. }
  192. const ttp = window.trustedTypes?.createPolicy("vscode-bootstrapImportMap", {
  193. createScript(value) {
  194. return value
  195. },
  196. })
  197. const importMapSrc = JSON.stringify(importMap, undefined, 2)
  198. const importMapScript = document.createElement("script")
  199. importMapScript.type = "importmap"
  200. importMapScript.setAttribute("nonce", "0c6a828f1297")
  201. // @ts-ignore
  202. importMapScript.textContent = ttp?.createScript(importMapSrc) ?? importMapSrc
  203. document.head.appendChild(importMapScript)
  204. performance.mark("code/didAddCssLoader")
  205. }
  206. }
  207. ;(globalThis as any).MonacoBootstrapWindow = { load }
  208. })()