Code Monkey home page Code Monkey logo

electronmon's Introduction

electronmon

electronmon logo

Watch and reload your electron app the easy way!

GitHub Actions CI npm-downloads npm-version

This is the simplest way to watch and restart/reload electron applications. It requires no quessing, no configuration, and no changing your application or conditionally requiring dependencies. And best of all, it keeps everything in-process, and will not exit on the first application relaunch.

It was inspired by nodemon and largely works the same way (by magic ๐Ÿง™).

To use it, you don't have to change your application at all. Just use electronmon instead of electron to launch your application, using all the same arguments you would pass to the electron cli:

npx electronmon .

That's it! Now, all your files are watched. Changes to main process files will cause the application to restart entirely, while changes to any of the renderer process files will simply reload the application browser windows.

All you have to do now is write your application code.

Configuration

Okay, okay... so it's not exactly magic. While electronmon will usually work exactly the way you want it to, you might find a need to contigure it. You can do so by providing extra values in your package.json in the an electronmon object. The following options are available:

  • patterns {Array<String>} - Additional patterns to watch, in glob form. The default patterns are ['**/*', '!node_modules', '!node_modules/**/*', '!.*', '!**/*.map'], and this property will add to that. If you want to ignore some files, start the glob with !.

Example:

{
  "electronmon": {
    "patterns": ["!test/**"]
  }
}

Supported environments

This module is tested and supported on Windows, MacOS, and Linux, using node versions 10 - 18 and electron versions 8 - 23. Considering it still works after all these versions, there's a good chance it works with newer versions as well.

API Usage

You will likely never need to use this, but in case you do, this module can be required and exposes and API for interacting with the monitor process.

const electronmon = require('electronmon');

(async () => {
  const options = {...};
  const app = await electronmon(options);
})();

All options are optional with reasonable defaults (again, magic ๐Ÿง™), but the following options are available:

  • cwd {String} - The root directory of your application.
  • args {Array<String>} - The arguments that you want to pass to electron.
  • env {Object} - Any additional environment variables you would like to specically provide to your electron process.
  • patterns {Array<String>} - Additional patterns to watch, in glob form. The default patterns are ['**/*', '!node_modules', '!node_modules/**/*', '!.*', '!**/*.map'], and this property will add to that. If you want to ignore some files, start the glob with !.
  • logLevel {String} - The level of logging you would like. Possible values are verbose, info, error, and quiet.
  • electronPath {String} - The path to the electron binary.

When the monitor is started, it will start your application and the monitoring process. It exposes the following methods for interacting with the monitoring process (all methods are asynchronous and return a Promise):

  • app.reload() โ†’ Promise - reloads all open web views of your application
  • app.restart() โ†’ Promise - restarts the entire electron process of your application
  • app.close() โ†’ Promise - closes the entire electron process of your application and waits for file changes in order to restart it
  • app.destroy() โ†’ Promise - closes the entire electron process and stops monitoring

electronmon's People

Contributors

catdad avatar dependabot[bot] avatar erickzhao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

electronmon's Issues

monitoring crashes if the app has an error while starting app and user clicks "OK" on error prompt

if i get error like this:

main.js :

console.log(qqq) // qqq is not defined

and press Ctrl + S, my electronmon restart with error,

and if i after this qqq replase to 232332
main.js :

console.log(232332) // qqq is not defined

my electronmon app not restarting
it my console output:

 App threw an error during load
ReferenceError: qq is not defined
    at Object.<anonymous> (C:\localhost\electron\index.js:1:22)
    at Module._compile (internal/modules/cjs/loader.js:880:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:892:10)
    at Module.load (internal/modules/cjs/loader.js:735:32)
    at Module._load (internal/modules/cjs/loader.js:648:12)
    at Module._load (electron/js2c/asar.js:717:26)
    at Function.Module._load (electron/js2c/asar.js:717:26)
    at Function.Module._load (C:\localhost\electron\node_modules\runtime-required\runtime-required.js:38:23)
    at loadApplicationPackage (C:\localhost\electron\node_modules\electron\dist\resources\default_app.asar\main.js:109:16)
    at Object.<anonymous> (C:\localhost\electron\node_modules\electron\dist\resources\default_app.asar\main.js:155:9)
(electron) 'getName function' is deprecated and will be removed. Please use 'name property' instead.
C:\localhost\electron\node_modules\electronmon\src\electronmon.js:86
  globalApp.once('exit', () => {
            ^

TypeError: Cannot read property 'once' of null
    at restartApp (C:\localhost\electron\node_modules\electronmon\src\electronmon.js:86:13)
    at FSWatcher.<anonymous> (C:\localhost\electron\node_modules\electronmon\src\electronmon.js:102:14)
    at FSWatcher.emit (events.js:210:5)
    at FSWatcher.<anonymous> (C:\localhost\electron\node_modules\chokidar\index.js:199:15)
    at FSWatcher._emit (C:\localhost\electron\node_modules\chokidar\index.js:241:5)
    at FSWatcher.<anonymous> (C:\localhost\electron\node_modules\chokidar\lib\nodefs-handler.js:274:18)
    at FSReqCallback.oncomplete (fs.js:159:5)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! test@1.0.0 electronmon: `electronmon .`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the test@1.0.0 electronmon script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\me\AppData\Roaming\npm-cache\_logs\2019-12-17T01_27_21_582Z-debug.log

Support for custom electron fork

Hi,

i'm developing an app using a forked Electron version, specifically the ow-electron package, https://www.npmjs.com/package/@overwolf/ow-electron

Also setting the electronPath in electronmon packages.json section, doesn't seem nodemon is starting using ow-electron

 "electronmon": {
    "patterns": [
      "!**/**",
      "src/main/**"
    ],
    "logLevel": "verbose",
    "electronPath": "./node_modules/bin/ow-electron"
  }

tried with simple ow-electron also.

I'm using it with the electron-react-boilerplate https://github.com/electron-react-boilerplate/electron-react-boilerplate

Replacing electromon with ow-electron here, launch the application with ow-electron

"start:main": "cross-env NODE_ENV=development electronmon -r ts-node/register/transpile-only .",

I'm not an Electron expert so probably i'm missing something :)

Debugging main and renderer documentation

The current documentation does not indicate how to use electromon to be integrated with a debug tool like vscode for the main process or chrome for the renderer process.

AC: Documentation should include the needed instructions to use it with debug tools.

determine actual renderer files

Needs to detect:

  • files loaded as a URL with a file:// scheme
  • required files if the renderer allows node module requires
  • files loaded through the network that match local files ?

Cannot find module '@/src/xxx'

how to parse url like "@/src/xxx" in main process?

here is package script:
"start:main": "cross-env NODE_ENV=development electronmon -r ts-node/register/transpile-only ."

and here is part of tsconfig:

"baseUrl": "./",
"paths": { "@/*": ["./*"] }

but i got error "Cannot find module '@/src/xxx'"

remove yargs-parser

It's really not being used for anything, and probably causes a bug but I am too lazy to check right now.

Stop app flashing on Windows taskbar for soft reloads

Whenever electronmon does a soft reload (renderer) of the app, the taskbar icon of the app starts flashing, which gets rather annoying very quickly, is there any way to stop it from doing this? For hard reloads (main) its fine since it restarts the entire app so it makes sense, but soft reload not really, if you consider manually pressing Ctrl + R on the app doesn't do this.

If there's no way to fix it in electronmon, are there any workarounds?

Watchboy error after change of file

I've just added electronmon to a new react+webpack+typescript+electron app. Unfortunatly if I run it with electronmon the process crashes with the following output:

!> yarn mon
yarn run v1.22.5
$ electronmon ./dist/main.bundle.js

[electronmon] waiting for a change to restart it
(node:6564) ExtensionLoadWarning: Warnings loading extension at C:\Users\jdrum\AppData\Roaming\Electron\extensions\fmkadmapgofadopljbjfkapdkoienihi: Unrecognized manifest key 'browser_action'. Unrecognized manifest key 'minimum_chrome_version'. Unrecognized manifest key 'update_url'. Cannot load extension with file or directory name _metadata. Filenames starting with "_" are reserved for use by the system.
Added Extension:  React Developer Tools
(node:6564) ExtensionLoadWarning: Warnings loading extension at C:\Users\jdrum\AppData\Roaming\Electron\extensions\lmhkpmbekcpmknklioeibfkpmmfibljd: Unrecognized manifest key 'commands'. Unrecognized manifest key 'homepage_url'. Unrecognized manifest key 'page_action'. Unrecognized manifest key 'short_name'. Unrecognized manifest key 'update_url'. Permission 'notifications' is unknown or URL pattern is malformed. Permission 'contextMenus' is unknown or URL pattern is malformed. Permission 'tabs' is unknown or URL pattern is malformed. Cannot load extension with file or directory name _metadata. Filenames starting with "_" are reserved for use by the system.
Added Extension:  Redux DevTools
[electronmon] renderer file change: dist\renderer.bundle.js
[electronmon] renderer file change: dist\renderer.bundle.js.map
C:\Users\jdrum\Documents\Projects\birder\node_modules\watchboy\index.js:182
      pending[abspath].timer = -1;
                             ^

TypeError: Cannot set property 'timer' of undefined
    at Timeout._onTimeout (C:\Users\jdrum\Documents\Projects\birder\node_modules\watchboy\index.js:182:30)
    at listOnTimeout (node:internal/timers:557:17)
    at processTimers (node:internal/timers:500:7)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

OS: Windows 10
Node: > v15.11.0

  "dependencies": {
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-router": "^5.2.0",
    "react-router-dom": "^5.2.0"
  },
  "devDependencies": {
    "@types/mocha": "^8.2.0",
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "@types/react-router": "^5.1.8",
    "@types/react-router-dom": "^5.1.6",
    "@typescript-eslint/eslint-plugin": "^4.11.0",
    "@typescript-eslint/parser": "^4.11.0",
    "copy-webpack-plugin": "^7.0.0",
    "cross-env": "^7.0.3",
    "css-loader": "^5.0.1",
    "electron": "^11.1.1",
    "electron-builder": "^22.9.1",
    "electron-devtools-installer": "^3.1.1",
    "electronmon": "^2.0.0",
    "eslint": "^7.16.0",
    "eslint-config-airbnb": "^18.2.1",
    "eslint-import-resolver-webpack": "^0.13.0",
    "eslint-plugin-import": "^2.22.1",
    "eslint-plugin-jsx-a11y": "^6.4.1",
    "eslint-plugin-react": "^7.21.5",
    "eslint-plugin-react-hooks": "^4.2.0",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^4.5.0",
    "lodash": "^4.17.20",
    "mocha": "^8.2.1",
    "npm-run-all": "^4.1.5",
    "react-devtools": "^4.10.1",
    "rimraf": "^3.0.2",
    "serve": "^11.3.2",
    "source-map-loader": "^2.0.0",
    "spectron": "^13.0.0",
    "style-loader": "^2.0.0",
    "ts-loader": "^8.0.12",
    "ts-node": "^9.1.1",
    "tsconfig-paths": "^3.9.0",
    "typescript": "^4.1.3",
    "webpack": "^5.11.0",
    "webpack-cli": "^4.3.0"
  },

First I thought that maybe the changed ts files cause trouble because of webpack, so I've excluded src folder with no luck:

  "electronmon": {
    "patterns": ["!src/**", "dist/**"]
  }

Could you please help me to fix this issue?

support symlinked projects

Steps:

  • create a project using electronmon
  • create a symlink to that project
  • run project from the symlink
  • modify main thread files

Expected behavior: file change is detected as a main file change
Actual behavior: file change is detected as a renderer file change

BrowserView doesn't get reloaded

When having a BrowserView nested inside BrowserWindow and a renderer file changes for the BrowserView, the change is detected in the console, but the BrowserView doesn't get refreshed, so one is currently forced to manually restart.

Doesn't seem to re-transpile app/main.ts, associated with renderer process (should be main)

I run:

ng serve -c web -o

and then:

wait-on tcp:4200 && tsc -p tsconfig.serve.json && npx electronmon . --serve

When I re-save ./app/main.ts, I see electronmon spit out:

[electronmon] renderer file change: app/main.ts

ok... but that's a main file, not a renderer file... and.... it didn't transpile. It didn't even re-run the main process, It reloaded the renderer only. So, I can't make an edit and hit save, and see it, unless I ctrl-C out of electronmon and totally restart, then it's fine.

-> It seems that electronmon is (incorrectly) associating main.ts with the renderer process, instead of the main process.

How do I fix this? The README.md gives patterns and some advice to ignore files, but doesn't tell me how to use that in the situation when electronmon is incorrectly associating the files with the wrong main vs renderer process.

saving package.json works:

[electronmon] main file change: package.json
will quit
[electronmon] restarting app due to file change

and trying to add a pattern to package.json doesn't make any changes (the main.ts does not rerun)

  "electronmon": {
    "patterns": ["app/**"]
  },

it just gives the same renderer line when saving main.ts

[electronmon] renderer file change: app/main.ts

Expose watchboy API as well

In order to correct do things (in my case track the recompile time of electronmon), it would be nice to be able to hook into watch boy and methods like watcher.on('change').... An example of a package that does this is webpack

JS api not working

If i try to use JS api, without providing any params i am getting this error:
TypeError [ERR_INVALID_ARG_TYPE]: The "file" argument must be of type string. Received an instance of Object

Not sure what to do here. Any help would be appreciated. Thanks

crashes when npm updated package.json when installing dependencies

Steps:

  • use an app that watched package.json (for the main thread)
  • npm install -S <any package>

See crash when npm updates package.json:

events.js:167
      throw er; // Unhandled 'error' event
      ^

Error [ERR_IPC_CHANNEL_CLOSED]: Channel closed
    at ChildProcess.target.send (internal/child_process.js:628:16)
    at EventEmitter.watcher.on (D:\Git\all-compare\node_modules\electronmon\src\electronmon.js:177:21)
    at EventEmitter.emit (events.js:182:13)
    at stat.then.stat (D:\Git\all-compare\node_modules\watchboy\index.js:196:28)
Emitted 'error' event at:
    at process.nextTick (internal/child_process.js:632:35)
    at process._tickCallback (internal/process/next_tick.js:61:11)

Electronmon not working in Node v18?

I am using Electronmon to create a new Electron project in VSCode. Everything was working just fine while I was using Node v16.17.0. This is the output I see in the console when firing up the project in VSCode:
image

Then I decided I wanted to upgrade to Node v18.13.0. Then the app would not start at all, no GUI pops up. And this is what I see in the console:
image

So it seems to stop right before the line [1] [electronmon] waiting for a change to restart it which tells me that the issue is with Electronmon. Anyone else seeing this?

expose reload events via API for retaining SPA state

most sophisticated Electron apps are built in a SPA kind of manner, hence they expose various views just using Client logic.

Often when working on a given view & electronmon reloads the window, that view is lost & one has to manually navigate back to it.

It would be good if the module would expose an API for handling such things, in a manner like:

electronmon.on("reload", ()=>{//custom reload logic})

so one can then insert ones own navigation / routing logic to the last view one worked on.

"path" argument must be of type string - `electronmon` fails to load app due to bug in `runtime-required` dependency

Using Electron React Boilerplate v2, electronmon fails to start with the following error:

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received null
	  at validateString (internal/validators.js:120:11)
	  at Object.dirname (path.js:1128:5)
	  at Function.Module._load (/Users/longt/Documents/projects/solta/liverton.desktop.terminal-agent/node_modules/runtime-required/runtime-required.js:31:40)
	  at Module.require (internal/modules/cjs/loader.js:1032:19)
	  at Function.Module._preloadModules (internal/modules/cjs/loader.js:1293:12)
	  at Object.<anonymous> (/Users/longt/Documents/projects/solta/liverton.desktop.terminal-agent/node_modules/electron/dist/Electron.app/Contents/Resources/default_app.asar/main.js:67:12)
	  at Module._compile (internal/modules/cjs/loader.js:1152:30)
	  at Object.Module._extensions..js (internal/modules/cjs/loader.js:1173:10)
	  at Module.load (internal/modules/cjs/loader.js:992:32)
	  at Module._load (internal/modules/cjs/

This is because in runtime-requried, it is incorrectly assumed that if parent is not nil, then parent.filename is also not nil. It turns out that this is not the case, and that parent.filename can be null. The fix here would be to simply check for parent.filename before passing it to path.dirname().

For anyone currently affected by this and needs a temporary workaround, I've written a script that patches node_modules/runtime-required/runtime-required.js and added it to as a package.json script under prestart:main:

// .erb/scripts/PatchElectronmon.js
const fs = require('fs')
const path = require('path')

const runtimeRequired = fs.readFileSync(path.join(__dirname, './runtime-required.js'))

fs.writeFileSync(
  path.join(process.cwd(),
  'node_modules/runtime-required/runtime-required.js'),
  runtimeRequired
)

// package.json
{
	"scripts": {
+     "prestart:main": "node ./.erb/scripts/PatchElectronmon.js",
    }
}

// .erb/scripts/runtime-required.js
const path = require('path');
const Module = require('module');
const EventEmitter = require('events');

const resolve = require('resolve-from');

const events = new EventEmitter();

const emit = (request, id) => {
  var type = 'file';

  if (id.indexOf('node_modules') > -1) {
    type = 'module';
  } else if (!path.parse(id).root) {
    type = 'builtin';
  }

  events.emit('file', {
    type: type,
    id: id
  });
};

// this is a hack and I don't like it
// if you know a better way to collect all required modules
// please file an issue, I'd appreciate it very much
// https://github.com/catdad/electronmon/issues/new
const originalLoad = Module._load;
Module._load = function (request, parent) {
  if (parent && parent.filename) {
    const idpath = resolve.silent(path.dirname(parent.filename), request);

    if (idpath) {
      emit(request, idpath);
    }
  }

  return originalLoad.apply(this, arguments);
};

module.exports = events;

Electron 7

(I know the readme says electron 4-6) but in electron 7, cpu usage spikes insanely.

Electron version Pure Electron Electronmon
7.0 ~5% ~90%
6.1.2 ~10% ~20%

I like electronmon during development because it helps so much to have auto re-launch but I would like to use the same version of electron during dev as in testing and production.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.