Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esm - convert window related helpers to TS #229961

Merged
merged 1 commit into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@
"restrictions": []
},
{
"target": "src/{bootstrap-cli.ts,bootstrap-esm.ts,bootstrap-fork.ts,bootstrap-node.ts,bootstrap-import.ts,bootstrap-meta.ts,bootstrap-window.js,cli.ts,main.ts,server-cli.ts,server-main.ts,bootstrap-server.ts}",
"target": "src/{bootstrap-cli.ts,bootstrap-esm.ts,bootstrap-fork.ts,bootstrap-node.ts,bootstrap-import.ts,bootstrap-meta.ts,bootstrap-window.ts,cli.ts,main.ts,server-cli.ts,server-main.ts,bootstrap-server.ts}",
"restrictions": []
}
]
Expand Down
263 changes: 120 additions & 143 deletions src/bootstrap-window.js → src/bootstrap-window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,133 +3,44 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

//@ts-check
'use strict';
/* eslint-disable no-restricted-globals */

/**
* @import { ISandboxConfiguration } from './vs/base/parts/sandbox/common/sandboxTypes'
* @typedef {any} LoaderConfig
*/
(function () {

/* eslint-disable no-restricted-globals */
type ISandboxConfiguration = import('vs/base/parts/sandbox/common/sandboxTypes.js').ISandboxConfiguration;
type ILoadOptions<T extends ISandboxConfiguration> = import('vs/platform/window/electron-sandbox/window.js').ILoadOptions<T>;
type PreloadGlobals = typeof import('./vs/base/parts/sandbox/electron-sandbox/globals.js');

(function (factory) {
// @ts-ignore
globalThis.MonacoBootstrapWindow = factory();
}(function () {
const preloadGlobals = sandboxGlobals();
// @ts-ignore (defined in preload.ts)
const preloadGlobals: PreloadGlobals = window.vscode;
const safeProcess = preloadGlobals.process;

// increase number of stack frames(from 10, https://github.com/v8/v8/wiki/Stack-Trace-API)
Error.stackTraceLimit = 100;

/**
* @param {string} esModule
* @param {(result: unknown, configuration: ISandboxConfiguration) => Promise<unknown> | undefined} resultCallback
* @param {{
* configureDeveloperSettings?: (config: ISandboxConfiguration) => {
* forceDisableShowDevtoolsOnError?: boolean,
* forceEnableDeveloperKeybindings?: boolean,
* disallowReloadKeybinding?: boolean,
* removeDeveloperKeybindingsAfterLoad?: boolean
* },
* canModifyDOM?: (config: ISandboxConfiguration) => void,
* beforeImport?: (config: ISandboxConfiguration) => void
* }} [options]
*/
async function load(esModule, resultCallback, options) {

// Await window configuration from preload
const timeout = setTimeout(() => { console.error(`[resolve window config] Could not resolve window configuration within 10 seconds, but will continue to wait...`); }, 10000);
performance.mark('code/willWaitForWindowConfig');
/** @type {ISandboxConfiguration} */
const configuration = await preloadGlobals.context.resolveConfiguration();
performance.mark('code/didWaitForWindowConfig');
clearTimeout(timeout);

// Signal DOM modifications are now OK
if (typeof options?.canModifyDOM === 'function') {
options.canModifyDOM(configuration);
}
async function load<T extends ISandboxConfiguration>(esModule: string, resultCallback: (result: any, configuration: T) => Promise<unknown> | undefined, options: ILoadOptions<T>): Promise<void> {

// Developer settings
const {
forceEnableDeveloperKeybindings,
disallowReloadKeybinding,
removeDeveloperKeybindingsAfterLoad
} = typeof options?.configureDeveloperSettings === 'function' ? options.configureDeveloperSettings(configuration) : {
forceEnableDeveloperKeybindings: false,
disallowReloadKeybinding: false,
removeDeveloperKeybindingsAfterLoad: false
};
const isDev = !!safeProcess.env['VSCODE_DEV'];
const enableDeveloperKeybindings = isDev || forceEnableDeveloperKeybindings;
let developerDeveloperKeybindingsDisposable = undefined;
if (enableDeveloperKeybindings) {
developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding);
}
// Window Configuration from Preload Script
const configuration = await resolveWindowConfiguration<T>();

globalThis._VSCODE_NLS_MESSAGES = configuration.nls.messages;
globalThis._VSCODE_NLS_LANGUAGE = configuration.nls.language;
let language = configuration.nls.language || 'en';
if (language === 'zh-tw') {
language = 'zh-Hant';
} else if (language === 'zh-cn') {
language = 'zh-Hans';
}
// Signal can modify DOM
options?.canModifyDOM?.(configuration);

window.document.documentElement.setAttribute('lang', language);
// Developer settings
const { enableDeveloperKeybindings, removeDeveloperKeybindingsAfterLoad, developerDeveloperKeybindingsDisposable } = setupDeveloperKeybindings(configuration, options);

window['MonacoEnvironment'] = {};
// NLS
setupNLS<T>(configuration);

// Signal before import()
if (typeof options?.beforeImport === 'function') {
options.beforeImport(configuration);
}
options?.beforeImport?.(configuration);

// Compute base URL and set as global
const baseUrl = new URL(`${fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out/`);
globalThis._VSCODE_FILE_ROOT = baseUrl.toString();

// DEV ---------------------------------------------------------------------------------------
// DEV: This is for development and enables loading CSS via import-statements via import-maps.
// DEV: For each CSS modules that we have we defined an entry in the import map that maps to
// DEV: a blob URL that loads the CSS via a dynamic @import-rule.
// DEV ---------------------------------------------------------------------------------------
if (Array.isArray(configuration.cssModules) && configuration.cssModules.length > 0) {
performance.mark('code/willAddCssLoader');

const style = document.createElement('style');
style.type = 'text/css';
style.media = 'screen';
style.id = 'vscode-css-loading';
document.head.appendChild(style);

globalThis._VSCODE_CSS_LOAD = function (url) {
style.textContent += `@import url(${url});\n`;
};

/**
* @type { { imports: Record<string, string> }}
*/
const importMap = { imports: {} };
for (const cssModule of configuration.cssModules) {
const cssUrl = new URL(cssModule, baseUrl).href;
const jsSrc = `globalThis._VSCODE_CSS_LOAD('${cssUrl}');\n`;
const blob = new Blob([jsSrc], { type: 'application/javascript' });
importMap.imports[cssUrl] = URL.createObjectURL(blob);
}

const ttp = window.trustedTypes?.createPolicy('vscode-bootstrapImportMap', { createScript(value) { return value; }, });
const importMapSrc = JSON.stringify(importMap, undefined, 2);
const importMapScript = document.createElement('script');
importMapScript.type = 'importmap';
importMapScript.setAttribute('nonce', '0c6a828f1297');
// @ts-ignore
importMapScript.textContent = ttp?.createScript(importMapSrc) ?? importMapSrc;
document.head.appendChild(importMapScript);

performance.mark('code/didAddCssLoader');
}
// Dev only: CSS import map tricks
setupCSSImportMaps<T>(configuration, baseUrl);

// ESM Import
try {
Expand All @@ -148,18 +59,48 @@
}
}

/**
* @param {boolean | undefined} disallowReloadKeybinding
* @returns {() => void}
*/
function registerDeveloperKeybindings(disallowReloadKeybinding) {
async function resolveWindowConfiguration<T extends ISandboxConfiguration>() {
const timeout = setTimeout(() => { console.error(`[resolve window config] Could not resolve window configuration within 10 seconds, but will continue to wait...`); }, 10000);
performance.mark('code/willWaitForWindowConfig');

const configuration = await preloadGlobals.context.resolveConfiguration() as T;
performance.mark('code/didWaitForWindowConfig');

clearTimeout(timeout);

return configuration;
}

function setupDeveloperKeybindings<T extends ISandboxConfiguration>(configuration: T, options: ILoadOptions<T>) {
const {
forceEnableDeveloperKeybindings,
disallowReloadKeybinding,
removeDeveloperKeybindingsAfterLoad
} = typeof options?.configureDeveloperSettings === 'function' ? options.configureDeveloperSettings(configuration) : {
forceEnableDeveloperKeybindings: false,
disallowReloadKeybinding: false,
removeDeveloperKeybindingsAfterLoad: false
};

const isDev = !!safeProcess.env['VSCODE_DEV'];
const enableDeveloperKeybindings = Boolean(isDev || forceEnableDeveloperKeybindings);
let developerDeveloperKeybindingsDisposable: Function | undefined = undefined;
if (enableDeveloperKeybindings) {
developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding);
}

return {
enableDeveloperKeybindings,
removeDeveloperKeybindingsAfterLoad,
developerDeveloperKeybindingsDisposable
};
}

function registerDeveloperKeybindings(disallowReloadKeybinding: boolean | undefined): Function {
const ipcRenderer = preloadGlobals.ipcRenderer;

const extractKey =
/**
* @param {KeyboardEvent} e
*/
function (e) {
function (e: KeyboardEvent) {
return [
e.ctrlKey ? 'ctrl-' : '',
e.metaKey ? 'meta-' : '',
Expand All @@ -174,8 +115,7 @@
const TOGGLE_DEV_TOOLS_KB_ALT = '123'; // F12
const RELOAD_KB = (safeProcess.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R

/** @type {((e: KeyboardEvent) => void) | undefined} */
let listener = function (e) {
let listener: ((e: KeyboardEvent) => void) | undefined = function (e) {
const key = extractKey(e);
if (key === TOGGLE_DEV_TOOLS_KB || key === TOGGLE_DEV_TOOLS_KB_ALT) {
ipcRenderer.send('vscode:toggleDevTools');
Expand All @@ -194,11 +134,21 @@
};
}

/**
* @param {string | Error} error
* @param {boolean} [showDevtoolsOnError]
*/
function onUnexpectedError(error, showDevtoolsOnError) {
function setupNLS<T extends ISandboxConfiguration>(configuration: T): void {
globalThis._VSCODE_NLS_MESSAGES = configuration.nls.messages;
globalThis._VSCODE_NLS_LANGUAGE = configuration.nls.language;

let language = configuration.nls.language || 'en';
if (language === 'zh-tw') {
language = 'zh-Hant';
} else if (language === 'zh-cn') {
language = 'zh-Hans';
}

window.document.documentElement.setAttribute('lang', language);
}

function onUnexpectedError(error: string | Error, showDevtoolsOnError: boolean): void {
if (showDevtoolsOnError) {
const ipcRenderer = preloadGlobals.ipcRenderer;
ipcRenderer.send('vscode:openDevTools');
Expand All @@ -211,12 +161,7 @@
}
}

/**
* @param {string} path
* @param {{ isWindows?: boolean, scheme?: string, fallbackAuthority?: string }} config
* @returns {string}
*/
function fileUriFromPath(path, config) {
function fileUriFromPath(path: string, config: { isWindows?: boolean; scheme?: string; fallbackAuthority?: string }): string {

// Since we are building a URI, we normalize any backslash
// to slashes and we ensure that the path begins with a '/'.
Expand All @@ -225,8 +170,7 @@
pathName = `/${pathName}`;
}

/** @type {string} */
let uri;
let uri: string;

// Windows: in order to support UNC paths (which start with '//')
// that have their own authority, we do not use the provided authority
Expand All @@ -243,15 +187,48 @@
return uri.replace(/#/g, '%23');
}

/**
* @return {typeof import('./vs/base/parts/sandbox/electron-sandbox/globals')}
*/
function sandboxGlobals() {
// @ts-ignore (defined in globals.js)
return window.vscode;
function setupCSSImportMaps<T extends ISandboxConfiguration>(configuration: T, baseUrl: URL) {

// DEV ---------------------------------------------------------------------------------------
// DEV: This is for development and enables loading CSS via import-statements via import-maps.
// DEV: For each CSS modules that we have we defined an entry in the import map that maps to
// DEV: a blob URL that loads the CSS via a dynamic @import-rule.
// DEV ---------------------------------------------------------------------------------------

if (Array.isArray(configuration.cssModules) && configuration.cssModules.length > 0) {
performance.mark('code/willAddCssLoader');

const style = document.createElement('style');
style.type = 'text/css';
style.media = 'screen';
style.id = 'vscode-css-loading';
document.head.appendChild(style);

globalThis._VSCODE_CSS_LOAD = function (url) {
style.textContent += `@import url(${url});\n`;
};

const importMap: { imports: Record<string, string> } = { imports: {} };
for (const cssModule of configuration.cssModules) {
const cssUrl = new URL(cssModule, baseUrl).href;
const jsSrc = `globalThis._VSCODE_CSS_LOAD('${cssUrl}');\n`;
const blob = new Blob([jsSrc], { type: 'application/javascript' });
importMap.imports[cssUrl] = URL.createObjectURL(blob);
}

const ttp = window.trustedTypes?.createPolicy('vscode-bootstrapImportMap', { createScript(value) { return value; }, });
const importMapSrc = JSON.stringify(importMap, undefined, 2);
const importMapScript = document.createElement('script');
importMapScript.type = 'importmap';
importMapScript.setAttribute('nonce', '0c6a828f1297');
// @ts-ignore
importMapScript.textContent = ttp?.createScript(importMapSrc) ?? importMapSrc;
document.head.appendChild(importMapScript);

performance.mark('code/didAddCssLoader');
}
}

return {
load
};
}));
// @ts-ignore
globalThis.MonacoBootstrapWindow = { load };
}());
2 changes: 1 addition & 1 deletion src/server-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ async function findFreePort(host: string | undefined, start: number, end: number
return undefined;
}

function loadCode(nlsConfiguration: INLSConfiguration): Promise<typeof import('./vs/server/node/server.main')> {
function loadCode(nlsConfiguration: INLSConfiguration): Promise<typeof import('./vs/server/node/server.main.js')> {
return new Promise((resolve, reject) => {

// required for `bootstrap-esm` to pick up NLS messages
Expand Down
8 changes: 4 additions & 4 deletions src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"./bootstrap-meta.ts",
"./bootstrap-node.ts",
"./bootstrap-server.ts",
"./bootstrap-window.js",
"./bootstrap-window.ts",
"./cli.ts",
"./main.ts",
"./server-main.ts",
Expand All @@ -45,9 +45,9 @@
"./vs/platform/environment/node/userDataPath.ts",
"./vs/base/parts/sandbox/electron-sandbox/preload-aux.ts",
"./vs/base/parts/sandbox/electron-sandbox/preload.ts",
"./vs/code/electron-sandbox/processExplorer/processExplorer.js",
"./vs/code/electron-sandbox/workbench/workbench.js",
"./vs/workbench/contrib/issue/electron-sandbox/issueReporter.js",
"./vs/code/electron-sandbox/processExplorer/processExplorer.ts",
"./vs/code/electron-sandbox/workbench/workbench.ts",
"./vs/workbench/contrib/issue/electron-sandbox/issueReporter.ts",
"./typings",
"./vs/**/*.ts",
"vscode-dts/vscode.proposed.*.d.ts",
Expand Down
4 changes: 2 additions & 2 deletions src/tsec.exemptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"vs/workbench/services/keybinding/test/node/keyboardMapperTestUtils.ts"
],
"ban-trustedtypes-createpolicy": [
"bootstrap-window.js",
"bootstrap-window.ts",
"vs/amdX.ts",
"vs/base/browser/trustedTypes.ts",
"vs/base/worker/workerMain.ts",
Expand All @@ -41,6 +41,6 @@
"**/*.ts"
],
"ban-script-content-assignments": [
"bootstrap-window.js"
"bootstrap-window.ts"
]
}
Loading
Loading