How can I remove cookies, local storage and other crap from the "AppData\roaming\MyApp" folder, when the electron application quits?
I tried deleting the whole directory on app quit, but it throws me EBUSY errors. Apparently the files are locked or something, almost like someone doesn't want us to be able to remove the bloat?
const fs = require('fs-extra');
const clearBloat = async () => fs.remove(path.join(app.getPath('appData'), app.name));
app.on('window-all-closed', async () => {
await clearBloat();
});
After doing some testing, I've found that you have to delete the files after your electron process has ended (trying to delete the files while in the quit or will-quit app events doesn't delete the files/folders; they get re-created right away. Something in electron (likely, Chromium) wants these files/folders to exist while the app is running, and it's too much work to figure out how to hook into it).
What works for me is spawning a detached cmd off a shell that waits 3 seconds, and then deletes all files/folders in a given application folder. What will be an exercise up to the reader will be to hide the output of the ping command (or hide the window, but there's been mixed success on that front), or choose a different command. I've found timeout works, but sleep and choice (ie. something like this) do not work.
Here's what you will need to add:
const { app } = require("electron");
const { spawn } = require("child_process");
const path = require("path");
...
app.on("will-quit", async (event) => {
const folder = path.join(app.getPath("appData"), app.name);
// Wait 3 seconds, navigate into your app folder and delete all files/folders
const cmd = `ping localhost -n 3 > nul 2>&1 && pushd "${folder}" && (rd /s /q "${folder}" 2>nul & popd)`;
// shell = true prevents EONENT errors
// stdio = ignore allows the pipes to continue processing w/o handling command output
// detached = true allows the command to run once your app is [completely] shut down
const process = spawn(cmd, { shell: true, stdio: "ignore", detached: true });
// Prevents the parent process from waiting for the child (this) process to finish
process.unref();
});
As another user mentioned, there's a method available on your electron session that is a native API that clears all of these files/folders. However, it returns a promise, and I could not figure out how to execute this synchronously within one of these app-events.
Reference #1
Related
Inside my main file, I have
const loadWorker = async () => {
const SyncWorker = await import("$lib/canvas.worker?worker");
syncWorker = new SyncWorker.default();
syncWorker?.postMessage({});
};
Then in my unmount I have
onMount(() => {
console.log("Canvas: mounted");
loadWorker();
});
Then in my canvas.worker.ts file, I have a simple
onmessage = () => {
console.log("Hello from the worker!");
};
export {};
This message prints successfully in Chrome, but in firefox all I get is
SyntaxError: import declarations may only appear at top level of a module
Is this because the worker is stored on my local system, and maybe there's a special flag to allow loading of system files as workers (as that seems it may be a security concern)? Firefox docs say that my browser should support workers.
Well, I should've read the documentation better.
service workers only work in the production build, not in development.
To test it locally, use vite preview
https://kit.svelte.dev/docs/service-workers
Or in my case, "npm run build && npm run preview" worked.
I'm using detox with cucumber and the setup works great until the last moment of calling AfterAll hooks.
In the hook I do the following:
AfterAll(async () => {
console.log('CLEANING DETOX');
await detox.cleanup();
});
To run cucumber I use the following script from package.json:
"bdd": "cucumber-js --require-module #babel/register",
The problem happens when I interrupt cucumber run for any reason. AfterAll hook won't run in this case and detox won't clear its stale files.
Which wouldn't be a problem but detox is using ~/Library/Detox/device.registry.state.lock file to track which simulators are being used by runner. Essentially, this leads to detox constantly launching new simulator devices as this file never gets cleared.
I thought, I could just create a simple wrapper script:
const { execSync } = require('child_process');
const detox = require('detox');
const stdout = execSync('cucumber-js --require-module #babel/register');
process.on('SIGINT', async function () {
console.log('Cleanig up detox');
await detox.cleanup();
});
console.log(stdout);
However, that didn't work either as detox.cleanup() only removes the file when it has detox.device setup. Which happens in BeforeAll hook:
BeforeAll({ timeout: 120 * 1000 }, async () => {
const detoxConfig = { selectedConfiguration: 'ios.debug2' };
// console.log('CONFIG::', detoxConfig);
await detox.init(detoxConfig);
await detox.device.launchApp();
});
My only idea left is to manually clear the file - I should be able to grab lock file path from detox internal somehow - my worry about this approach is tight dependency on detox implementation. Which is why I would rather call detox.cleanup.
EDIT:
Ended up doing this workaround for now:
BeforeAll({ timeout: 120 * 1000 }, async () => {
await startDetox();
});
async function startDetox() {
const detoxConfig = { selectedConfiguration: 'ios.debug' };
const lockFile = getDeviceLockFilePathIOS();
unlink(lockFile, (err) => {
if (err) {
console.debug('Lock file was not deleted:::', err);
}
});
await detox.init(detoxConfig);
await detox.device.launchApp();
}
Wonder if anyone has a better idea ?
Have you tried adding
detox clean-framework-cache && detox build-framework-cache into your command like so:
detox clean-framework-cache && detox build-framework-cache && cucumber-js --require-module #babel/register
This is a detox command that clears the cache and resets it so detox starts from fresh every time, it barely adds any time to the execution time so can be run on every test and means the first thing the build does before starting the simulator is clear the cache and start from fresh. I had the exact same issue with our cucumber detox builds and this fixed it for us.
After fiddling with workaround for way too long I ended up migrating to jest-cucumber.
It manages to work way better with detox and doesn't require all this workarounds.
I am using ElectronJS in order to build a Desktop Application.
However, I would like to auto-update the changes in the code and see the result immediately.
For example, if I am creating a WebServer with express on localhost, alyways when i update the browser, i get the changes.
On the Go Live extension on VSCode, this happens automatically after CRTL + Save
Does there exist any similar functionality for electron?
My current alternative is to close the whole electron application and start it with npm start again...
Thanks.
use electron-hot-reload package get hotreload
import { mainReloader, rendererReloader } from 'electron-hot-reload';
import { app } from 'electron';
import path from 'path';
const mainFile = path.join(app.getAppPath(), 'dist', 'main.js');
const rendererFile = path.join(app.getAppPath(), 'dist', 'renderer.js');
mainReloader(mainFile, undefined, (error, path) => {
console.log("It is a main's process hook!");
});
rendererReloader(rendererFile, undefined, (error, path) => {
console.log("It is a renderer's process hook!");
});
Example project with configuration
https://github.com/valentineus/electron-hot-reload/tree/6feca4b65b78c674aea096906ecd7b46abebc36a/example/application/src
Found it on my own.
As #ShioT mentioned, this is called hot reload / live reload.
electron-reload | npm package
https://www.npmjs.com/package/electron-reload
Frontend
require('electron-reload')(__dirname);
Backend (hard reset)
const path = require('path')
require('electron-reload')(__dirname, {
// note that this path can vary
electron: path.join(__dirname, 'node_modules', '.bin', 'electron')
});
The simplest way I've found is using electron-reloader, after installation, just paste the following code at the top of the app entry file, and you're all set:
const { app } = require('electron')
app.isPackaged || require('electron-reloader')(module)
I googled
EPERM: operation not permitted
and I got many hits on issues with npm and this error.
This is not my case ( not a duplicate ) as I am not running npm, I am running my own Node code.
I am getting this error:
Error
{
Error: 'EPERM: operation not permitted',
errno: -1,
code: 'EPERM',
syscall: 'scandir',
path: '../../../Library/Application Support/CallHistoryDB/'
};
when running the code below on my home directory.
I ran it using both
node getInfo
and
sudo node getInfo
but I get the same error.
This code works fine if I run it on my local repository but when I try to traverse my entire home directory I get the error.
Executed code:
// Libraries
const fs = require('fs');
const h = require('./helper');
// Start recursing here
const start = '../../../';
// API
getThings(start).then(() => {
console.log(data);
}).catch(h.error)
// Accesses the file system and returns an array of files / folders
async function getThings (folder) {
const things = await fs.promises.readdir(folder);
for(let i = 0; i < things.length; i++) {
await getStats(things[i], folder);
}
}
// Gets statistics for each file/folder
async function getStats (thing, folder) {
const path = folder + thing;
const stats = await fs.promises.stat(path);
await checkForFolder(stats, thing, path);
}
// if the file/folder is a folder, recurse and do it again
async function checkForFolder(stats, thing, path){
// logThing(stats, thing, path);
if (stats.isDirectory() ) {
await getThings(path + '/');
}
}
Research
SO - EPERM vs EACCES
'../../../Library/Application Support/CallHistoryDB/'
This path is protected by macOS security settings, as it may contain sensitive telephone history data.
If you specifically need to access it in your Node application, you will need to enable full disk access for the application you're using to run this script (e.g, Terminal.app, iTerm, or an IDE) in System Preferences, as shown below. Note that this will give all applications you run in the terminal access to your sensitive personal files; tread carefully.
However, if you don't need to specifically access this path (and you probably shouldn't), a better solution may be to catch errors individually on each call to fs.promises.stat(path). The simplest way of doing this will be to wrap the call to await fs.promises.stat(path) in a try … catch block and either print or ignore errors.
I need to run the set of node js files which contains the configuration information where It has to run typically port number and IP address then using the forever in node.js I need to run the script in the terminal with the configuration without having any manual input.
For Programmatic approach , you can use Forever-Moniter
var forever = require('forever-monitor');
var child = new (forever.Monitor)('your-filename.js', {
max: 3,
silent: true,
options: []
});
child.on('exit', function () {
console.log('your-filename.js has exited after 3 restarts');
});
child.start();
You could make use of the child_process module. Check the doc, there're some useful information there: http://nodejs.org/api/child_process.html
To give a brief example
var exec = require('child_process').exec;
exec('forever', function callback(error, stdout, stderr){
// cb
});
If you don't need a callback / don't want to wait for the execution:
var exec = require('child_process').exec('forever').unref();
Was that helpful?
Best
Marc
Edit: Ok, not sure if I really got the point of your question, but my answer combined with https://stackoverflow.com/a/23871739/823851 might offer a good solution.
Usage:
forever start hello.js to start a process.
forever list to see list of all processes started by forever
forever stop hello.js to stop the process, or forever stop 0 to stop the process with index 0 (as shown by forever list).
node-config is a good module for managing different configurations of a Node.js app.
For example, to make a "production" config, /config/production.json would contain:
{
"port" : "3000",
"ip" : "192.168.1.1"
}
In one of your node application JS files:
config = require('config')
....
var port = config.port;
var ip = config.ip;
And to launch the app in this configuration, just first set your NODE_ENV to production from the shell before running your app.
export NODE_ENV=production
forever start app.js
Make additional config JSON files as needed for each of your environments. default.json is used when no environment is specified.