Have you ever got a task in which you build a service to listen or watch another project (folder). If there is an error, a notification will be thrown. In this tutorial, we’re gonna look at a way to solve this problem: watch a folder for changes in Node.js.
Related post: How to watch file for changes in Node.js
Overview
Watch folder for changes in Node.js
The problem is determined. So how to deal with it?
At first, getting the error is to read log file that is generated when running a project, to watch it for appearance or changes. Next, we should create a service working independently of the main project (that generates the log file).
Assume that the main project Performance will generate error.log file in logs
folder everytime it throws an error.
So what we will do is watching the logs
folder. If error.log appears, read the file, get the content, and delete that file.
This is the structure for our example:
Way to watch folder for changes
How do we build a service to work for this process?
We can use fs.watch
, fs.watchFile
from Node.js fs
module. But it has disadvantages:
- trigger change event twice while modify & save only once
- get notification when changing the file name, while only listen to file content update
- not support subfolders
- some errors on macOS
We’d like to introduce chokidar module to solve this problem. At the time of writting this tutorial, it has over 13 milion downloaded per week.
This is the overview of chokidar API:
const chokidar = require('chokidar');
// Initialize watcher.
const watcher = chokidar.watch('path/to/folder', { persistent: true });
// Add event listeners.
watcher
.on('add', path => log(`File ${path} has been added`))
.on('change', path => log(`File ${path} has been changed`))
.on('unlink', path => log(`File ${path} has been removed`));
// More possible events.
watcher
.on('addDir', path => log(`Directory ${path} has been added`))
.on('unlinkDir', path => log(`Directory ${path} has been removed`))
.on('error', error => log(`Watcher error: ${error}`))
.on('ready', () => log('Initial scan complete. Ready for changes'))
Practice
Setup Node.js modules
We need to install 2 packages: chokidar and fs-extra (promise support to the fs methods).
So run the command:
npm install chokidar fs-extra
Create Service for watching folder
Under services folder, create obserser.js file:
const chokidar = require('chokidar');
const EventEmitter = require('events').EventEmitter;
const fsExtra = require('fs-extra');
class Observer extends EventEmitter {
constructor() {
super();
}
watchFolder(folder) {
try {
console.log(
`[${new Date().toLocaleString()}] Watching for folder changes on: ${folder}`
);
var watcher = chokidar.watch(folder, { persistent: true });
watcher.on('add', async filePath => {
if (filePath.includes('error.log')) {
console.log(
`[${new Date().toLocaleString()}] ${filePath} has been added.`
);
// Read content of new file
var fileContent = await fsExtra.readFile(filePath);
// emit an event when new file has been added
this.emit('file-added', {
message: fileContent.toString()
});
// remove file error.log
await fsExtra.unlink(filePath);
console.log(
`[${new Date().toLocaleString()}] ${filePath} has been removed.`
);
}
});
} catch (error) {
console.log(error);
}
}
}
module.exports = Observer;
These are things we do in the code above:
– import necessary module: chokidar
, events
, fs-extra
.
– define Observer
class that extends EventEmitter
which can emit event (emit()
method) and listen to event (on()
method).
– create watcher
variable using chokidar.watch()
function. {persistent: true}
indicates whether the process should continue to run as long as files are being watched.
– watcher.on('add')
is the event listener for a file added event. In the handler, we check if the added file is error.log
, read content using fsExtra.readFile()
, emit 'file-added'
event with the content as message
, delete the file using fsExtra.unlink()
.
– export Observer
module.
Use Observer object
server.js
const Obserser = require('./services/observer');
var obserser = new Obserser();
const folder = 'Performance/logs';
obserser.on('file-added', log => {
// print error message to console
console.log(log.message);
});
obserser.watchFolder(folder);
What we do:
– import Observer
class and initialize observer
object.
– use on()
method to listen 'file-added'
event. In the handler, you can do anything such as: push alert message to chatwork, slack…
– call watchFolder()
function.
Check result
On the project root folder, run this command:
node src/server.js
The console shows (in case there was an error.log file before):
[8/28/2019, 1:51:51 PM] Watching for folder changes on: Performance/logs
[8/28/2019, 1:51:52 PM] Performance\logs\error.log has been added.
just an error!
[8/28/2019, 1:51:52 PM] Performance\logs\error.log has been removed.
Look inside the folder, we don’t see error.log any longer.
If we create new error.log with content new error here!
inside the folder. Console will immediately show:
[8/28/2019, 1:58:25 PM] Performance\logs\error.log has been added.
new error here!
[8/28/2019, 1:58:25 PM] Performance\logs\error.log has been removed.
Conclusion
Today we’ve learned way to listen/watch a folder for changes by solving the real world problem: check log file appearance, read the content, then delete it.
In the next tutorial, we show you way to listen/watch a file for new changes:
How to watch file for changes in Node.js
Happy learning! See you again.
Further Reading
- https://www.npmjs.com/package/chokidar
- https://github.com/paulmillr/chokidar
- https://www.npmjs.com/package/fs-extra
Source Code
You can find the complete source code for this example on Github.
Very simple and informative. Thanks!
This tutorial is well suited for many applications like an editor or IDE, that potentially has many open files and needs to ensure that the files are synchronized with the file system. It is also well suited for an application server that watches a directory. Thank you!