Ramit Mittal

Back-end Engineer @ Attosol | Speaks Node, Python, HTTP

Learning Node.js by dissecting an open-source library.

Learning to stand on the shoulders of giants
Popular open-source libraries are a treasure trove of robust, standards-compliant code. Writing libraries is a little different from writing applications. Open-source libraries often target multiple platforms and language versions and a lot of that needs to be managed in the source code. This increases the barrier to entry for newcomers who might approach it with the intent of contributing. However, I have found that just reading the source code without the intent of making a pull request is also a great habit.

node-fetch

This library is like requests for NodeJs. Despite having only a tenth of the stars on Github, it's well-written and is an absolute pleasure to use. You can clone the Github repository to your local machine or browse the code on Github itself. Start by examining the directory structure.
$ tree .
.
├── browser.js
├── build
│   ├── babel-plugin.js
│   └── rollup-plugin.js
├── CHANGELOG.md
├── codecov.yml
├── ERROR-HANDLING.md
├── LICENSE.md
├── LIMITS.md
├── package.json
├── README.md
├── rollup.config.js
├── src
│   ├── abort-error.js
│   ├── blob.js
│   ├── body.js
│   ├── fetch-error.js
│   ├── headers.js
│   ├── index.js
│   ├── request.js
│   └── response.js
├── test
│   ├── dummy.txt
│   ├── server.js
│   └── test.js
└── UPGRADE-GUIDE.md

3 directories, 23 files
We will attack this code-base in a top-down manner, reading the most important file first.
README.md
The README file is always a good place to start. Here, we get a gist of what the library is supposed to do and the API it provides, along with usage examples.
package.json
In the order of precedence, this file comes right after the README. This is a standard package definition file. It specifies the dependencies, build scripts and other package metadata. Don't look at the scripts section just now. Our primary goal here is the
main
field which specifies the package entry file. This is what gets loaded when you import/require the package.
lib/index.js
We are getting closer to the source code now.
index.js
looks like a source code file.
😱 😱 😱 but there is no lib folder in my cloned repository!
The
lib
folder would probably be created during the build or bundling process. This is a common practice. It can easily be verified by looking the
scripts
section of
package.json
A build script is specified
cross-env BABEL_ENV=rollup rollup -c
I had zero idea what rollup does before reading this line. A quick web search proves that it is indeed a JS bundler. We will have to look at rollup's configuration file to figure what exactly it is doing.
rollup.config.js
It reads
src/index.js
and outputs
lib/index.js
So whatever goes inside
lib/index.js
should come from
src/index.js
Our aim is to save the build-related stuff for later and focus on the code first. We have our next task.
src/index.js
Top-down! Remember? Look at what this module exports. You will also find that the major chunk of code in this file is just this single function.
export default function fetch(url, opts) {

	// allow custom promise
	if (!fetch.Promise) {
		throw new Error('native promise missing, set fetch.Promise to your favorite alternative');
	}

	Body.Promise = fetch.Promise;

	// wrap http.request into fetch
	return new fetch.Promise((resolve, reject) => {
fetch.Promise? What sorcery is this?
The explanation lies at the very end of the file. The rationale being that if promises aren't supported natively, a third party library can come and fill in.
fetch.Promise = global.Promise;
Assigning key-value to a function object, neat!
When you find an unexplained variable, either you figure out where it came from or acknowledge it and continue reading the code block. Remember that it is very hard to figure out what every single line does in a single go. Be a little compiler-ish. Make multiple passes over the source code, learning more and more every time.
This function returns a promise that either resolves into a response received from the remote server or gets rejected with an error. Pretty basic, huh!

Your turn to choose the next file

That's it from my side. We saw one neat trick and there are a lot more in that source code. Reading other people's source code is an excellent method to figure out new tricks to tackle common problems. Descend the source tree yourself and find 'em.

Tags

Comments

More by Ramit Mittal