init.ts 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import * as path from 'path';
  2. import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
  3. import type * as ipcRendererInternalModule from '@electron/internal/renderer/ipc-renderer-internal';
  4. import type * as webFrameInitModule from '@electron/internal/renderer/web-frame-init';
  5. import type * as webViewInitModule from '@electron/internal/renderer/web-view/web-view-init';
  6. import type * as windowSetupModule from '@electron/internal/renderer/window-setup';
  7. import type * as securityWarningsModule from '@electron/internal/renderer/security-warnings';
  8. const Module = require('module');
  9. // Make sure globals like "process" and "global" are always available in preload
  10. // scripts even after they are deleted in "loaded" script.
  11. //
  12. // Note 1: We rely on a Node patch to actually pass "process" and "global" and
  13. // other arguments to the wrapper.
  14. //
  15. // Note 2: Node introduced a new code path to use native code to wrap module
  16. // code, which does not work with this hack. However by modifying the
  17. // "Module.wrapper" we can force Node to use the old code path to wrap module
  18. // code with JavaScript.
  19. //
  20. // Note 3: We provide the equivalent extra variables internally through the
  21. // webpack ProvidePlugin in webpack.config.base.js. If you add any extra
  22. // variables to this wrapper please ensure to update that plugin as well.
  23. Module.wrapper = [
  24. '(function (exports, require, module, __filename, __dirname, process, global, Buffer) { ' +
  25. // By running the code in a new closure, it would be possible for the module
  26. // code to override "process" and "Buffer" with local variables.
  27. 'return function (exports, require, module, __filename, __dirname) { ',
  28. '\n}.call(this, exports, require, module, __filename, __dirname); });'
  29. ];
  30. // We modified the original process.argv to let node.js load the
  31. // init.js, we need to restore it here.
  32. process.argv.splice(1, 1);
  33. // Clear search paths.
  34. require('../common/reset-search-paths');
  35. // Import common settings.
  36. require('@electron/internal/common/init');
  37. // The global variable will be used by ipc for event dispatching
  38. const v8Util = process._linkedBinding('electron_common_v8_util');
  39. const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal') as typeof ipcRendererInternalModule;
  40. const ipcRenderer = require('@electron/internal/renderer/api/ipc-renderer').default;
  41. v8Util.setHiddenValue(global, 'ipcNative', {
  42. onMessage (internal: boolean, channel: string, ports: any[], args: any[], senderId: number) {
  43. if (internal && senderId !== 0) {
  44. console.error(`Message ${channel} sent by unexpected WebContents (${senderId})`);
  45. return;
  46. }
  47. const sender = internal ? ipcRendererInternal : ipcRenderer;
  48. sender.emit(channel, { sender, senderId, ports }, ...args);
  49. }
  50. });
  51. // Use electron module after everything is ready.
  52. const { webFrameInit } = require('@electron/internal/renderer/web-frame-init') as typeof webFrameInitModule;
  53. webFrameInit();
  54. // Process command line arguments.
  55. const { hasSwitch, getSwitchValue } = process._linkedBinding('electron_common_command_line');
  56. const { mainFrame } = process._linkedBinding('electron_renderer_web_frame');
  57. const contextIsolation = mainFrame.getWebPreference('contextIsolation');
  58. const nodeIntegration = mainFrame.getWebPreference('nodeIntegration');
  59. const webviewTag = mainFrame.getWebPreference('webviewTag');
  60. const isHiddenPage = mainFrame.getWebPreference('hiddenPage');
  61. const usesNativeWindowOpen = mainFrame.getWebPreference('nativeWindowOpen');
  62. const preloadScript = mainFrame.getWebPreference('preload');
  63. const preloadScripts = mainFrame.getWebPreference('preloadScripts');
  64. const guestInstanceId = mainFrame.getWebPreference('guestInstanceId');
  65. const openerId = mainFrame.getWebPreference('openerId');
  66. const appPath = hasSwitch('app-path') ? getSwitchValue('app-path') : null;
  67. // The webContents preload script is loaded after the session preload scripts.
  68. if (preloadScript) {
  69. preloadScripts.push(preloadScript);
  70. }
  71. switch (window.location.protocol) {
  72. case 'devtools:': {
  73. // Override some inspector APIs.
  74. require('@electron/internal/renderer/inspector');
  75. break;
  76. }
  77. case 'chrome-extension:': {
  78. break;
  79. }
  80. case 'chrome:': {
  81. break;
  82. }
  83. default: {
  84. // Override default web functions.
  85. const { windowSetup } = require('@electron/internal/renderer/window-setup') as typeof windowSetupModule;
  86. windowSetup(guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen);
  87. }
  88. }
  89. // Load webview tag implementation.
  90. if (process.isMainFrame) {
  91. const { webViewInit } = require('@electron/internal/renderer/web-view/web-view-init') as typeof webViewInitModule;
  92. webViewInit(contextIsolation, webviewTag, guestInstanceId);
  93. }
  94. if (nodeIntegration) {
  95. // Export node bindings to global.
  96. const { makeRequireFunction } = __non_webpack_require__('internal/modules/cjs/helpers') // eslint-disable-line
  97. global.module = new Module('electron/js2c/renderer_init');
  98. global.require = makeRequireFunction(global.module);
  99. // Set the __filename to the path of html file if it is file: protocol.
  100. if (window.location.protocol === 'file:') {
  101. const location = window.location;
  102. let pathname = location.pathname;
  103. if (process.platform === 'win32') {
  104. if (pathname[0] === '/') pathname = pathname.substr(1);
  105. const isWindowsNetworkSharePath = location.hostname.length > 0 && process.resourcesPath.startsWith('\\');
  106. if (isWindowsNetworkSharePath) {
  107. pathname = `//${location.host}/${pathname}`;
  108. }
  109. }
  110. global.__filename = path.normalize(decodeURIComponent(pathname));
  111. global.__dirname = path.dirname(global.__filename);
  112. // Set module's filename so relative require can work as expected.
  113. global.module.filename = global.__filename;
  114. // Also search for module under the html file.
  115. global.module.paths = Module._nodeModulePaths(global.__dirname);
  116. } else {
  117. // For backwards compatibility we fake these two paths here
  118. global.__filename = path.join(process.resourcesPath, 'electron.asar', 'renderer', 'init.js');
  119. global.__dirname = path.join(process.resourcesPath, 'electron.asar', 'renderer');
  120. if (appPath) {
  121. // Search for module under the app directory
  122. global.module.paths = Module._nodeModulePaths(appPath);
  123. }
  124. }
  125. // Redirect window.onerror to uncaughtException.
  126. window.onerror = function (_message, _filename, _lineno, _colno, error) {
  127. if (global.process.listenerCount('uncaughtException') > 0) {
  128. // We do not want to add `uncaughtException` to our definitions
  129. // because we don't want anyone else (anywhere) to throw that kind
  130. // of error.
  131. global.process.emit('uncaughtException', error as any);
  132. return true;
  133. } else {
  134. return false;
  135. }
  136. };
  137. } else {
  138. // Delete Node's symbols after the Environment has been loaded in a
  139. // non context-isolated environment
  140. if (!contextIsolation) {
  141. process.once('loaded', function () {
  142. delete (global as any).process;
  143. delete (global as any).Buffer;
  144. delete (global as any).setImmediate;
  145. delete (global as any).clearImmediate;
  146. delete (global as any).global;
  147. delete (global as any).root;
  148. delete (global as any).GLOBAL;
  149. });
  150. }
  151. }
  152. // Load the preload scripts.
  153. for (const preloadScript of preloadScripts) {
  154. try {
  155. Module._load(preloadScript);
  156. } catch (error) {
  157. console.error(`Unable to load preload script: ${preloadScript}`);
  158. console.error(error);
  159. ipcRendererInternal.send(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, preloadScript, error);
  160. }
  161. }
  162. // Warn about security issues
  163. if (process.isMainFrame) {
  164. const { securityWarnings } = require('@electron/internal/renderer/security-warnings') as typeof securityWarningsModule;
  165. securityWarnings(nodeIntegration);
  166. }