Node.js | Reading The File that Exports an npm Package.

Andrew Miller
3 min readJan 16, 2021
Photo by Federico Di Dio photography on Unsplash

This article aims to walk the reader through the steps of programmatically reading the file that exports any npm package that exists in their node_modules folder.

First let’s install an arbitrary npm package and generate a node_modules folder.

Enter the following command:

npm install -D eslint

Now lets require eslint into a file and take a look at which objects it exports to us.

‘use strict’;
const eslint = require(‘eslint’);
console.log(eslint);

The code above logs eslint to the console, and at the time of this writing reveals the following objects.

{Linter: [class Linter],CLIEngine: [class CLIEngine] {version: '7.18.0',getFormatter: [Function: getFormatter]},ESLint: [class ESLint],RuleTester: [class RuleTester] { [Symbol(it)]: null, [Symbol(describe)]: nul    l },SourceCode: [class SourceCode extends TokenStore]}

Now let’s get the path to the file that exports these objects.

'use strict';const pathToEslint = require.resolve('eslint');console.log(pathToEslint);

‘The console.log call on pathToEslint reveals the path. Which will resemble something similar to the absolute path shown below.

/Users/AndrewMiller/medium_npm_dir/node_modules/eslint/lib/api.js

Now that we have the path to the file eslint exports from let’s read the file, and log it to the console.

There are at least four different ways to read a file: synchronously, asynchronously with callbacks or with promises, and with a readable stream. We will use the easiest and perhaps the most inefficient. We will read the file synchronously.

1'use strict';2 const { readFileSync } = require('fs');3 let eslintPath = require.resolve('eslint')45 console.log(eslintPath);67 let requirePathContent = readFileSync(eslintPath, { encoding:'utf-8' });8 console.log(requirePathContent);

On line 2 we initalize our readFileSync method using object destructuring assignment. On line 3 we retrive our path and initalize the eslintPath variable with it.

We call the readFileSync method on line 7 and pass it two arguments. The first argument is the path to the eslint file, the file that exports objects to the file that calls require(‘eslint’). The next argument describes the encoding of the file that is being read, so the files content does not arrive in a Buffer representation of binary data.

On line 8 we log the contents of the file that we identified earlier. The one which has the following file path.

Absolute path:

/Users/AndrewMiller/medium_npm_dir/node_modules/eslint/lib/api.js

Our program logs the above files content to the console.

Files Content:

"use strict";const { CLIEngine } = require("./cli-engine");const { ESLint } = require("./eslint");const { Linter } = require("./linter");const { RuleTester } = require("./rule-tester");const { SourceCode } = require("./source-code");module.exports = {Linter,CLIEngine,ESLint,RuleTester,SourceCode};// DOTO: remove deprecated API.let deprecatedLinterInstance = null;Object.defineProperty(module.exports, "linter", {enumerable: false,get() {if (!deprecatedLinterInstance) {deprecatedLinterInstance = new Linter();}return deprecatedLinterInstance;}});

Now we can see that the objects that were exported. Match the objects we retrieve when using require(‘eslint’).

Below there is a copy of the objects that are retrieved using require(‘eslint’). You can see the module.exports function call above that exports the objects shown below.

{Linter: [class Linter],CLIEngine: [class CLIEngine] {version: '7.18.0',getFormatter: [Function: getFormatter]},ESLint: [class ESLint],RuleTester: [class RuleTester] { [Symbol(it)]: null, [Symbol(describe)]: null },SourceCode: [class SourceCode extends TokenStore]}

To elaborate on this you could try reading the directory that the file is in and writing the content of that directory out to a file.

Thanks for reading my article! Enjoy your day!

--

--

Andrew Miller

Hello I am Andrew Miller. I am a Software Engineer that loves Node.js