init.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import { Buffer } from 'buffer';
  2. import { EventEmitter } from 'events';
  3. import * as fs from 'fs';
  4. import { Socket } from 'net';
  5. import * as path from 'path';
  6. import * as util from 'util';
  7. const Module = require('module');
  8. // We modified the original process.argv to let node.js load the init.js,
  9. // we need to restore it here.
  10. process.argv.splice(1, 1);
  11. // Clear search paths.
  12. require('../common/reset-search-paths');
  13. // Import common settings.
  14. require('@electron/internal/common/init');
  15. process.electronBinding('event_emitter').setEventEmitterPrototype(EventEmitter.prototype);
  16. if (process.platform === 'win32') {
  17. // Redirect node's console to use our own implementations, since node can not
  18. // handle console output when running as GUI program.
  19. const consoleLog = (...args: any[]) => {
  20. // @ts-ignore this typing is incorrect; 'format' is an optional parameter
  21. // See https://nodejs.org/api/util.html#util_util_format_format_args
  22. return process.log(util.format(...args) + '\n');
  23. };
  24. const streamWrite: Socket['write'] = function (chunk: Buffer | string, encoding?: any, callback?: Function) {
  25. if (Buffer.isBuffer(chunk)) {
  26. chunk = chunk.toString(encoding);
  27. }
  28. process.log(chunk);
  29. if (callback) {
  30. callback();
  31. }
  32. return true;
  33. };
  34. console.log = console.error = console.warn = consoleLog;
  35. process.stdout.write = process.stderr.write = streamWrite;
  36. }
  37. // Don't quit on fatal error.
  38. process.on('uncaughtException', function (error) {
  39. // Do nothing if the user has a custom uncaught exception handler.
  40. if (process.listenerCount('uncaughtException') > 1) {
  41. return;
  42. }
  43. // Show error in GUI.
  44. // We can't import { dialog } at the top of this file as this file is
  45. // responsible for setting up the require hook for the "electron" module
  46. // so we import it inside the handler down here
  47. import('electron')
  48. .then(({ dialog }) => {
  49. const stack = error.stack ? error.stack : `${error.name}: ${error.message}`;
  50. const message = 'Uncaught Exception:\n' + stack;
  51. dialog.showErrorBox('A JavaScript error occurred in the main process', message);
  52. });
  53. });
  54. // Emit 'exit' event on quit.
  55. const { app } = require('electron');
  56. app.on('quit', function (event, exitCode) {
  57. process.emit('exit', exitCode);
  58. });
  59. if (process.platform === 'win32') {
  60. // If we are a Squirrel.Windows-installed app, set app user model ID
  61. // so that users don't have to do this.
  62. //
  63. // Squirrel packages are always of the form:
  64. //
  65. // PACKAGE-NAME
  66. // - Update.exe
  67. // - app-VERSION
  68. // - OUREXE.exe
  69. //
  70. // Squirrel itself will always set the shortcut's App User Model ID to the
  71. // form `com.squirrel.PACKAGE-NAME.OUREXE`. We need to call
  72. // app.setAppUserModelId with a matching identifier so that renderer processes
  73. // will inherit this value.
  74. const updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe');
  75. if (fs.existsSync(updateDotExe)) {
  76. const packageDir = path.dirname(path.resolve(updateDotExe));
  77. const packageName = path.basename(packageDir).replace(/\s/g, '');
  78. const exeName = path.basename(process.execPath).replace(/\.exe$/i, '').replace(/\s/g, '');
  79. app.setAppUserModelId(`com.squirrel.${packageName}.${exeName}`);
  80. }
  81. }
  82. // Map process.exit to app.exit, which quits gracefully.
  83. process.exit = app.exit as () => never;
  84. // Load the RPC server.
  85. require('@electron/internal/browser/rpc-server');
  86. // Load the guest view manager.
  87. require('@electron/internal/browser/guest-view-manager');
  88. require('@electron/internal/browser/guest-window-manager');
  89. // Now we try to load app's package.json.
  90. let packagePath = null;
  91. let packageJson = null;
  92. const searchPaths = ['app', 'app.asar', 'default_app.asar'];
  93. if (process.resourcesPath) {
  94. for (packagePath of searchPaths) {
  95. try {
  96. packagePath = path.join(process.resourcesPath, packagePath);
  97. packageJson = Module._load(path.join(packagePath, 'package.json'));
  98. break;
  99. } catch {
  100. continue;
  101. }
  102. }
  103. }
  104. if (packageJson == null) {
  105. process.nextTick(function () {
  106. return process.exit(1);
  107. });
  108. throw new Error('Unable to find a valid app');
  109. }
  110. // Set application's version.
  111. if (packageJson.version != null) {
  112. app.setVersion(packageJson.version);
  113. }
  114. // Set application's name.
  115. if (packageJson.productName != null) {
  116. app.name = `${packageJson.productName}`.trim();
  117. } else if (packageJson.name != null) {
  118. app.name = `${packageJson.name}`.trim();
  119. }
  120. // Set application's desktop name.
  121. if (packageJson.desktopName != null) {
  122. app.setDesktopName(packageJson.desktopName);
  123. } else {
  124. app.setDesktopName(`${app.name}.desktop`);
  125. }
  126. // Set v8 flags, delibrately lazy load so that apps that do not use this
  127. // feature do not pay the price
  128. if (packageJson.v8Flags != null) {
  129. require('v8').setFlagsFromString(packageJson.v8Flags);
  130. }
  131. app._setDefaultAppPaths(packagePath);
  132. // Load the chrome devtools support.
  133. require('@electron/internal/browser/devtools');
  134. // Load the chrome extension support.
  135. require('@electron/internal/browser/chrome-extension-shim');
  136. if (BUILDFLAG(ENABLE_REMOTE_MODULE)) {
  137. require('@electron/internal/browser/remote/server');
  138. }
  139. // Load protocol module to ensure it is populated on app ready
  140. require('@electron/internal/browser/api/protocol');
  141. // Set main startup script of the app.
  142. const mainStartupScript = packageJson.main || 'index.js';
  143. const KNOWN_XDG_DESKTOP_VALUES = ['Pantheon', 'Unity:Unity7', 'pop:GNOME'];
  144. function currentPlatformSupportsAppIndicator () {
  145. if (process.platform !== 'linux') return false;
  146. const currentDesktop = process.env.XDG_CURRENT_DESKTOP;
  147. if (!currentDesktop) return false;
  148. if (KNOWN_XDG_DESKTOP_VALUES.includes(currentDesktop)) return true;
  149. // ubuntu based or derived session (default ubuntu one, communitheme…) supports
  150. // indicator too.
  151. if (/ubuntu/ig.test(currentDesktop)) return true;
  152. return false;
  153. }
  154. // Workaround for electron/electron#5050 and electron/electron#9046
  155. process.env.ORIGINAL_XDG_CURRENT_DESKTOP = process.env.XDG_CURRENT_DESKTOP;
  156. if (currentPlatformSupportsAppIndicator()) {
  157. process.env.XDG_CURRENT_DESKTOP = 'Unity';
  158. }
  159. // Quit when all windows are closed and no other one is listening to this.
  160. app.on('window-all-closed', () => {
  161. if (app.listenerCount('window-all-closed') === 1) {
  162. app.quit();
  163. }
  164. });
  165. const { setDefaultApplicationMenu } = require('@electron/internal/browser/default-menu');
  166. // Create default menu.
  167. //
  168. // The |will-finish-launching| event is emitted before |ready| event, so default
  169. // menu is set before any user window is created.
  170. app.once('will-finish-launching', setDefaultApplicationMenu);
  171. if (packagePath) {
  172. // Finally load app's main.js and transfer control to C++.
  173. process._firstFileName = Module._resolveFilename(path.join(packagePath, mainStartupScript), null, false);
  174. Module._load(path.join(packagePath, mainStartupScript), Module, true);
  175. } else {
  176. console.error('Failed to locate a valid package to load (app, app.asar or default_app.asar)');
  177. console.error('This normally means you\'ve damaged the Electron package somehow');
  178. }