main.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import { app, dialog } from 'electron'
  2. import * as fs from 'fs'
  3. import * as path from 'path'
  4. import * as url from 'url'
  5. type DefaultAppOptions = {
  6. file: null | string;
  7. noHelp: boolean;
  8. version: boolean;
  9. webdriver: boolean;
  10. interactive: boolean;
  11. abi: boolean;
  12. modules: string[];
  13. }
  14. const Module = require('module')
  15. // Parse command line options.
  16. const argv = process.argv.slice(1)
  17. const option: DefaultAppOptions = {
  18. file: null,
  19. noHelp: Boolean(process.env.ELECTRON_NO_HELP),
  20. version: false,
  21. webdriver: false,
  22. interactive: false,
  23. abi: false,
  24. modules: []
  25. }
  26. let nextArgIsRequire = false
  27. for (const arg of argv) {
  28. if (nextArgIsRequire) {
  29. option.modules.push(arg)
  30. nextArgIsRequire = false
  31. continue
  32. } else if (arg === '--version' || arg === '-v') {
  33. option.version = true
  34. break
  35. } else if (arg.match(/^--app=/)) {
  36. option.file = arg.split('=')[1]
  37. break
  38. } else if (arg === '--interactive' || arg === '-i' || arg === '-repl') {
  39. option.interactive = true
  40. } else if (arg === '--test-type=webdriver') {
  41. option.webdriver = true
  42. } else if (arg === '--require' || arg === '-r') {
  43. nextArgIsRequire = true
  44. continue
  45. } else if (arg === '--abi' || arg === '-a') {
  46. option.abi = true
  47. continue
  48. } else if (arg === '--no-help') {
  49. option.noHelp = true
  50. continue
  51. } else if (arg[0] === '-') {
  52. continue
  53. } else {
  54. option.file = arg
  55. break
  56. }
  57. }
  58. if (nextArgIsRequire) {
  59. console.error('Invalid Usage: --require [file]\n\n"file" is required')
  60. process.exit(1)
  61. }
  62. // Set up preload modules
  63. if (option.modules.length > 0) {
  64. Module._preloadModules(option.modules)
  65. }
  66. function loadApplicationPackage (packagePath: string) {
  67. // Add a flag indicating app is started from default app.
  68. Object.defineProperty(process, 'defaultApp', {
  69. configurable: false,
  70. enumerable: true,
  71. value: true
  72. })
  73. try {
  74. // Override app name and version.
  75. packagePath = path.resolve(packagePath)
  76. const packageJsonPath = path.join(packagePath, 'package.json')
  77. let appPath
  78. if (fs.existsSync(packageJsonPath)) {
  79. let packageJson
  80. try {
  81. packageJson = require(packageJsonPath)
  82. } catch (e) {
  83. showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${e.message}`)
  84. return
  85. }
  86. if (packageJson.version) {
  87. app.setVersion(packageJson.version)
  88. }
  89. if (packageJson.productName) {
  90. app.setName(packageJson.productName)
  91. } else if (packageJson.name) {
  92. app.setName(packageJson.name)
  93. }
  94. appPath = packagePath
  95. }
  96. try {
  97. const filePath = Module._resolveFilename(packagePath, module, true)
  98. app._setDefaultAppPaths(appPath || path.dirname(filePath))
  99. } catch (e) {
  100. showErrorMessage(`Unable to find Electron app at ${packagePath}\n\n${e.message}`)
  101. return
  102. }
  103. // Run the app.
  104. Module._load(packagePath, module, true)
  105. } catch (e) {
  106. console.error('App threw an error during load')
  107. console.error(e.stack || e)
  108. throw e
  109. }
  110. }
  111. function showErrorMessage (message: string) {
  112. app.focus()
  113. dialog.showErrorBox('Error launching app', message)
  114. process.exit(1)
  115. }
  116. async function loadApplicationByURL (appUrl: string) {
  117. const { loadURL } = await import('./default_app')
  118. loadURL(appUrl)
  119. }
  120. async function loadApplicationByFile (appPath: string) {
  121. const { loadFile } = await import('./default_app')
  122. loadFile(appPath)
  123. }
  124. function startRepl () {
  125. if (process.platform === 'win32') {
  126. console.error('Electron REPL not currently supported on Windows')
  127. process.exit(1)
  128. }
  129. // prevent quitting
  130. app.on('window-all-closed', () => {})
  131. const repl = require('repl')
  132. repl.start('> ').on('exit', () => {
  133. process.exit(0)
  134. })
  135. }
  136. // Start the specified app if there is one specified in command line, otherwise
  137. // start the default app.
  138. if (option.file && !option.webdriver) {
  139. const file = option.file
  140. const protocol = url.parse(file).protocol
  141. const extension = path.extname(file)
  142. if (protocol === 'http:' || protocol === 'https:' || protocol === 'file:' || protocol === 'chrome:') {
  143. loadApplicationByURL(file)
  144. } else if (extension === '.html' || extension === '.htm') {
  145. loadApplicationByFile(path.resolve(file))
  146. } else {
  147. loadApplicationPackage(file)
  148. }
  149. } else if (option.version) {
  150. console.log('v' + process.versions.electron)
  151. process.exit(0)
  152. } else if (option.abi) {
  153. console.log(process.versions.modules)
  154. process.exit(0)
  155. } else if (option.interactive) {
  156. startRepl()
  157. } else {
  158. if (!option.noHelp) {
  159. const welcomeMessage = `
  160. Electron ${process.versions.electron} - Build cross platform desktop apps with JavaScript, HTML, and CSS
  161. Usage: electron [options] [path]
  162. A path to an Electron app may be specified. It must be one of the following:
  163. - index.js file.
  164. - Folder containing a package.json file.
  165. - Folder containing an index.js file.
  166. - .html/.htm file.
  167. - http://, https://, or file:// URL.
  168. Options:
  169. -i, --interactive Open a REPL to the main process.
  170. -r, --require Module to preload (option can be repeated).
  171. -v, --version Print the version.
  172. -a, --abi Print the Node ABI version.`
  173. console.log(welcomeMessage)
  174. }
  175. loadApplicationByFile('index.html')
  176. }