How does the Levenshtein module interact with NodeJS module system?

377
January 12, 2017, at 05:08 AM

I am looking here:

https://github.com/gf3/Levenshtein/blob/master/lib/levenshtein.js

I see that the code begins like this:

(function(root, factory){
  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
    define(function(){
      return factory(root);
    });
  } else if (typeof module == 'object' && module && module.exports) {
    module.exports = factory(root);
  } else {
    root.Levenshtein = factory(root);
  }
}(this, function(root){

I've never seen this before. What does it mean? What does "root" mean?

If I add this to the package.json file of my NodeJS app, then how do I use this inner function:

 // Levenshtein distance
 function Levenshtein( str_m, str_n )

All the examples use this inner function, but I don't know how to reach it.

Answer 1
TL;DR

What does "root" mean?

root is the first argument passed to this IIFE, which (as you see on line 11) is this. At the "top level" of a JavaScript file in Node.js, this points to the global namespace object. In the browser it points to window.

All the examples use this inner function, but I don't know how to reach it.

That's not a question, but this is how you use it in Node.js:

const Levenshtein = require('levenshtein');
const lev = new Levenshtein('bar', 'baz');
console.log(lev.distance); // => 1

What does it mean?

The purpose of all of this is to make this code work whether you use require in Node.js, an AMD module loader, or a <script> tag in the browser.

If you break it down, the code isn't too hard to understand. Let's start with the anonymous function on line 11, which is a "factory" function that just returns the Levenshtein constructor, like so:

function factory(root) {
  // ...
  function Levenshtein( str_m, str_n ) {
    // ...
  }
  // ...
  return Levenshtein
}

(In the case of the Levenshtein module, the root argument is never actually used in the "factory" function. Go figure.)

Now let's back up to the first line. Here an anonymous function is declared, which basically works like this:

function iife(root, factory) {
  const Levenshtein = factory(root);
  if (anAMDLoaderIsLoadingMe()) {
    // AMD loaders supply a `define` function
    define(function() { return Levenshtein; });
  } else if (nodeJsIsLoadingMe()) {
    // Node.js supplies the `module.exports` object
    module.exports = Levenshtein;
  } else {
    // In a browser, so `root` is `window`
    root.Levenshtein = Levenshtein;
  }
}

Finally, these two functions are used like this:

iife(this, factory);

That's it! The reason these functions are used anonymously instead of giving them sensible names like iife and factory is so that they don't clash with other functions that you might define (or that other, less well-behaved modules define). This isn't a possibility in Node.js, but it is in the browser.

READ ALSO
Is there a npm command to know where a particular node module is located

Is there a npm command to know where a particular node module is located

I have been searching in every node_modules in my project but I cannot find where http module is located

305
Vagrant filesystem issues with npm

Vagrant filesystem issues with npm

I've been encountering a frequent error with Vagrant machines and npm, where the filesystem suddenly becomes read-onlyIn all cases, a synced directory containing a git repo was involved

384
Hot Module Replace for Node Web Server

Hot Module Replace for Node Web Server

So, I've got Webpack and React running with HMRWorks real good, bar some of the gotchas

355
Including ffmpeg library in project?

Including ffmpeg library in project?

Say I have written a software which utilises the ffmpeg libraryHow would I include this in my project, and install it automatically with my software? That is, I do not want to require the user to do any additional tasks (like downloading the ffmpeg library...

372