Is It Always The Same Instance (Singleton)?
3 min read

Is It Always The Same Instance (Singleton)?

Is logger always the same instance? Is it a singleton? Do NodeJS and frontend behave in the same way?

Context

We are developing a web application in NodeJS and want to add error monitoring. We decide on a library that requires us to create an instance and export it. We can also add user data to that same instance once the user logs in to provide more context for the error.

After adding the library, we have something like the following:

// logger.js
import { Logger } from “error-monitoring”;
const logger = new Logger(<some-api-key>);
export default logger;

Then we import it and set the user in another file.

// login.js
import logger from “<path-to>/logger”;
// user logs in
logger.addUser(<user-data>);
// …

Then whenever we want to log an error:

// file1.js
import logger from “<path-to>/logger”;
// in a catch somewhere
logger.push({ err: “<some-error>” });

This means that our file structure is something like the following:

Is logger always the same instance? Is it a singleton?

What If It’s Not a Singleton?

If logger is not always the same instance, push will not have the information we added in addUser. That’s because logger.push and logger.addUser would not share the same data.

Therefore, it’s essential that our logger library always uses the same instance (or a singleton).

NodeJS Modules

To find out, we add a console.log(“in da logger.js”); in the file where we initialize the logger. If we get multiple logs, it means that the file is executed multiple times and logger is not a singleton.

We run the code with console.log and find out it’s printed only once. Perfect logger is a singleton.

Why is that?

The answer is in the NodeJS docs:

“Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.” NodeJS Docs on Modules

Disable Caching

To prove the module caching, we disable caching and check that the log is printed multiple times. For example, in one of the files where it’s imported, we need to add the following:

// some-file.js
import logger from “<path-to>/logger”;
// new line
delete require.cache[require.resolve('<path-to>/logger')];
// …

The new line removes the module from the cache and forces the file to be executed again. Consequently, the instance is not a singleton any more.

Frontend

That was in NodeJS, but is it also a singleton if the project is a front-end project?

Front-end projects are built with bundlers like Webpack or Rollup. Therefore, we need to understand what they do.

I created a simple project in Rollup to show what happens there.

Does It Import the Instance Twice?

The answer is no. The file that Rollup bundles contains the logger file only once. The final file is just a concatenation of all the project files.

// bundle.js
'use strict';

// code from logger.js
console.log('in da logger');
class Logger {}
const logger = new Logger();

// code from file1.js
console.log('in da file1', logger);

// code from login.js
console.log('in da login', logger);

// code from index.js
console.log('in da index.js');

Webpack does the same thing, yet in a much more complicated file.

Is It a Singleton?

The answer is YES. The logger is a singleton. We can rely on the push to have the data from addUser because both are the same instance.


If you like this post, consider sharing it with your friends on twitter or forwarding this email to them 🙈

Don't hesitate to reach out to me if you have any questions or see an error. I highly appreciate it.

And thanks to Michal, Miquel, and Sebastià for reviewing this article 🙏

Thanks for reading, don't be a stranger 👋

GIMTEC is the newsletter I wish I had earlier in my software engineering career.

Every other Wednesday, I share an article on a topic that you won't learn at work.

Join more than 3,000 subscribers below.

Thanks for subscribing! A confirmation email has been sent.

Check the SPAM folder if you don't receive it shortly.

Sorry, there was an error 🤫.

Try again and contact me at llorenc[at]gimtec.io if it doesn't work. Thanks!