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
The following is part of a script that is run using npm run test.
async setup() {
process.env.DATABASE_URL = this.databaseUrl;
this.global.process.env.DATABASE_URL = this.databaseUrl;
await exec(`./node_modules/.bin/prisma migrate up --create-db --experimental`);
return super.setup();}
This throws the following error
Command failed: ./node_modules/.bin/prisma migrate up --create-db --experimental
'.' is not recognized as an internal or external command,
operable program or batch file.
When run from the cmd the command works as expected. What is the correct way to reference the binary file within exec()? I am using windows incase that is relevant.
Solution with help from #derpirscher.
const path = require("path");
const prismaBinary = "./node_modules/.bin/prisma";
await exec(
`${path.resolve(prismaBinary)} migrate up --create-db --experimental`
);
I'm trying to move a file from one partition to another in a Node.js script. When I used fs.renameSync I received Error: EXDEV, Cross-device link. I'd copy it over and delete the original, but I don't see a command to copy files either. How can this be done?
You need to copy and unlink when moving files across different partitions. Try this,
var fs = require('fs');
//var util = require('util');
var is = fs.createReadStream('source_file');
var os = fs.createWriteStream('destination_file');
is.pipe(os);
is.on('end',function() {
fs.unlinkSync('source_file');
});
/* node.js 0.6 and earlier you can use util.pump:
util.pump(is, os, function() {
fs.unlinkSync('source_file');
});
*/
I know this is already answered, but I ran across a similar problem and ended up with something along the lines of:
require('child_process').spawn('cp', ['-r', source, destination])
What this does is call the command cp ("copy"). Since we're stepping outside of Node.js, this command needs to be supported by your system.
I know it's not the most elegant, but it did what I needed :)
One more solution to the problem.
There's a package called fs.extra written by "coolaj86" on npm.
You use it like so:
npm install fs.extra
fs = require ('fs.extra');
fs.move ('foo.txt', 'bar.txt', function (err) {
if (err) { throw err; }
console.log ("Moved 'foo.txt' to 'bar.txt'");
});
I've read the source code for this thing. It attempts to do a standard fs.rename() then, if it fails, it does a copy and deletes the original using the same util.pump() that #chandru uses.
to import the module and save it to your package.json file
npm install mv --save
then use it like so:
var mv = require('mv');
mv('source_file', 'destination_file', function (err) {
if (err) {
throw err;
}
console.log('file moved successfully');
});
I made a Node.js module that just handles it for you. You don't have to think about whether it's going to be moved within the same partition or not. It's the fastest solution available, as it uses the recent fs.copyFile() Node.js API to copy the file when moving to a different partition/disk.
Just install move-file:
$ npm install move-file
Then use it like this:
const moveFile = require('move-file');
(async () => {
await moveFile(fromPath, toPath);
console.log('File moved');
})();
I already have read the documentation of Node.js and, unless if I missed something, it does not tell what the parameters contain in certain operations, in particular fs.mkdir(). As you can see in the documentation, it's not very much.
Currently, I have this code, which tries to create a folder or use an existing one instead:
fs.mkdir(path,function(e){
if(!e || (e && e.code === 'EEXIST')){
//do something with contents
} else {
//debug
console.log(e);
}
});
But I wonder is this the right way to do it? Is checking for the code EEXIST the right way to know that the folder already exists? I know I can do fs.stat() before making the directory, but that would already be two hits to the filesystem.
Secondly, is there a complete or at least a more detailed documentation of Node.js that contains details as to what error objects contain, what parameters signify etc.
Edit: Because this answer is very popular, I have updated it to reflect up-to-date practices.
Node >=10
The new { recursive: true } option of Node's fs now allows this natively. This option mimics the behaviour of UNIX's mkdir -p. It will recursively make sure every part of the path exist, and will not throw an error if any of them do.
(Note: it might still throw errors such as EPERM or EACCESS, so better still wrap it in a try {} catch (e) {} if your implementation is susceptible to it.)
Synchronous version.
fs.mkdirSync(dirpath, { recursive: true })
Async version
await fs.promises.mkdir(dirpath, { recursive: true })
Older Node versions
Using a try {} catch (err) {}, you can achieve this very gracefully without encountering a race condition.
In order to prevent dead time between checking for existence and creating the directory, we simply try to create it straight up, and disregard the error if it is EEXIST (directory already exists).
If the error is not EEXIST, however, we ought to throw an error, because we could be dealing with something like an EPERM or EACCES
function ensureDirSync (dirpath) {
try {
return fs.mkdirSync(dirpath)
} catch (err) {
if (err.code !== 'EEXIST') throw err
}
}
For mkdir -p-like recursive behaviour, e.g. ./a/b/c, you'd have to call it on every part of the dirpath, e.g. ./a, ./a/b, .a/b/c
Good way to do this is to use mkdirp module.
$ npm install mkdirp
Use it to run function that requires the directory. Callback is called after path is created or if path did already exists. Error err is set if mkdirp failed to create directory path.
var mkdirp = require('mkdirp');
mkdirp('/tmp/some/path/foo', function(err) {
// path exists unless there was an error
});
If you want a quick-and-dirty one liner, use this:
fs.existsSync("directory") || fs.mkdirSync("directory");
The node.js docs for fs.mkdir basically defer to the Linux man page for mkdir(2). That indicates that EEXIST will also be indicated if the path exists but isn't a directory which creates an awkward corner case if you go this route.
You may be better off calling fs.stat which will tell you whether the path exists and if it's a directory in a single call. For (what I'm assuming is) the normal case where the directory already exists, it's only a single filesystem hit.
These fs module methods are thin wrappers around the native C APIs so you've got to check the man pages referenced in the node.js docs for the details.
You can use this:
if(!fs.existsSync("directory")){
fs.mkdirSync("directory", 0766, function(err){
if(err){
console.log(err);
// echo the result back
response.send("ERROR! Can't make the directory! \n");
}
});
}
I propose a solution without modules (accumulate modules is never recommended for maintainability especially for small functions that can be written in a few lines...) :
LAST UPDATE :
In v10.12.0, NodeJS impletement recursive options :
// Create recursive folder
fs.mkdir('my/new/folder/create', { recursive: true }, (err) => { if (err) throw err; });
UPDATE :
// Get modules node
const fs = require('fs');
const path = require('path');
// Create
function mkdirpath(dirPath)
{
if(!fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK))
{
try
{
fs.mkdirSync(dirPath);
}
catch(e)
{
mkdirpath(path.dirname(dirPath));
mkdirpath(dirPath);
}
}
}
// Create folder path
mkdirpath('my/new/folder/create');
You can also use fs-extra, which provide a lot frequently used file operations.
Sample Code:
var fs = require('fs-extra')
fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function (err) {
if (err) return console.error(err)
console.log("success!")
})
fs.mkdirsSync('/tmp/another/path')
docs here: https://github.com/jprichardson/node-fs-extra#mkdirsdir-callback
Here is the ES6 code which I use to create a directory (when it doesn't exist):
const fs = require('fs');
const path = require('path');
function createDirectory(directoryPath) {
const directory = path.normalize(directoryPath);
return new Promise((resolve, reject) => {
fs.stat(directory, (error) => {
if (error) {
if (error.code === 'ENOENT') {
fs.mkdir(directory, (error) => {
if (error) {
reject(error);
} else {
resolve(directory);
}
});
} else {
reject(error);
}
} else {
resolve(directory);
}
});
});
}
const directoryPath = `${__dirname}/test`;
createDirectory(directoryPath).then((path) => {
console.log(`Successfully created directory: '${path}'`);
}).catch((error) => {
console.log(`Problem creating directory: ${error.message}`)
});
Note:
In the beginning of the createDirectory function, I normalize the path to guarantee that the path seperator type of the operating system will be used consistently (e.g. this will turn C:\directory/test into C:\directory\test (when being on Windows)
fs.exists is deprecated, that's why I use fs.stat to check if the directory already exists
If a directory doesn't exist, the error code will be ENOENT (Error NO ENTry)
The directory itself will be created using fs.mkdir
I prefer the asynchronous function fs.mkdir over it's blocking counterpart fs.mkdirSync and because of the wrapping Promise it will be guaranteed that the path of the directory will only be returned after the directory has been successfully created
You'd better not to count the filesystem hits while you code in Javascript, in my opinion.
However, (1) stat & mkdir and (2) mkdir and check(or discard) the error code, both ways are right ways to do what you want.
create dynamic name directory for each user... use this code
***suppose email contain user mail address***
var filessystem = require('fs');
var dir = './public/uploads/'+email;
if (!filessystem.existsSync(dir)){
filessystem.mkdirSync(dir);
}else
{
console.log("Directory already exist");
}
Just as a newer alternative to Teemu Ikonen's answer, which is very simple and easily readable, is to use the ensureDir method of the fs-extra package.
It can not only be used as a blatant replacement for the built in fs module, but also has a lot of other functionalities in addition to the functionalities of the fs package.
The ensureDir method, as the name suggests, ensures that the directory exists. If the directory structure does not exist, it is created. Like mkdir -p. Not just the end folder, instead the entire path is created if not existing already.
the one provided above is the async version of it. It also has a synchronous method to perform this in the form of the ensureDirSync method.
You can do all of this with the File System module.
const
fs = require('fs'),
dirPath = `path/to/dir`
// Check if directory exists.
fs.access(dirPath, fs.constants.F_OK, (err)=>{
if (err){
// Create directory if directory does not exist.
fs.mkdir(dirPath, {recursive:true}, (err)=>{
if (err) console.log(`Error creating directory: ${err}`)
else console.log('Directory created successfully.')
})
}
// Directory now exists.
})
You really don't even need to check if the directory exists. The following code also guarantees that the directory either already exists or is created.
const
fs = require('fs'),
dirPath = `path/to/dir`
// Create directory if directory does not exist.
fs.mkdir(dirPath, {recursive:true}, (err)=>{
if (err) console.log(`Error creating directory: ${err}`)
// Directory now exists.
})
#Liberateur's answer above did not work for me (Node v8.10.0).
Little modification did the trick but I am not sure if this is a right way. Please suggest.
// Get modules node
const fs = require('fs');
const path = require('path');
// Create
function mkdirpath(dirPath)
{
try {
fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
}
catch(err) {
try
{
fs.mkdirSync(dirPath);
}
catch(e)
{
mkdirpath(path.dirname(dirPath));
mkdirpath(dirPath);
}
}
}
// Create folder path
mkdirpath('my/new/folder/create');
const fs = require('fs');
const folderName = '/Users/joe/test';
try {
if (!fs.existsSync(folderName)) {
fs.mkdirSync(folderName);
}
} catch (err) {
console.error(err);
}
For documentation and more examples, please see here https://nodejs.dev/learn/working-with-folders-in-nodejs
Raugaral's answer but with -p functionality. Ugly, but it works:
function mkdirp(dir) {
let dirs = dir.split(/\\/).filter(asdf => !asdf.match(/^\s*$/))
let fullpath = ''
// Production directory will begin \\, test is on my local drive.
if (dirs[0].match(/C:/i)) {
fullpath = dirs[0] + '\\'
}
else {
fullpath = '\\\\' + dirs[0] + '\\'
}
// Start from root directory + 1, build out one level at a time.
dirs.slice(1).map(asdf => {
fullpath += asdf + '\\'
if (!fs.existsSync(fullpath)) {
fs.mkdirSync(fullpath)
}
})
}//mkdirp
I'm trying to move a file from one partition to another in a Node.js script. When I used fs.renameSync I received Error: EXDEV, Cross-device link. I'd copy it over and delete the original, but I don't see a command to copy files either. How can this be done?
You need to copy and unlink when moving files across different partitions. Try this,
var fs = require('fs');
//var util = require('util');
var is = fs.createReadStream('source_file');
var os = fs.createWriteStream('destination_file');
is.pipe(os);
is.on('end',function() {
fs.unlinkSync('source_file');
});
/* node.js 0.6 and earlier you can use util.pump:
util.pump(is, os, function() {
fs.unlinkSync('source_file');
});
*/
I know this is already answered, but I ran across a similar problem and ended up with something along the lines of:
require('child_process').spawn('cp', ['-r', source, destination])
What this does is call the command cp ("copy"). Since we're stepping outside of Node.js, this command needs to be supported by your system.
I know it's not the most elegant, but it did what I needed :)
One more solution to the problem.
There's a package called fs.extra written by "coolaj86" on npm.
You use it like so:
npm install fs.extra
fs = require ('fs.extra');
fs.move ('foo.txt', 'bar.txt', function (err) {
if (err) { throw err; }
console.log ("Moved 'foo.txt' to 'bar.txt'");
});
I've read the source code for this thing. It attempts to do a standard fs.rename() then, if it fails, it does a copy and deletes the original using the same util.pump() that #chandru uses.
to import the module and save it to your package.json file
npm install mv --save
then use it like so:
var mv = require('mv');
mv('source_file', 'destination_file', function (err) {
if (err) {
throw err;
}
console.log('file moved successfully');
});
I made a Node.js module that just handles it for you. You don't have to think about whether it's going to be moved within the same partition or not. It's the fastest solution available, as it uses the recent fs.copyFile() Node.js API to copy the file when moving to a different partition/disk.
Just install move-file:
$ npm install move-file
Then use it like this:
const moveFile = require('move-file');
(async () => {
await moveFile(fromPath, toPath);
console.log('File moved');
})();