Thursday, June 16, 2016

Browserify Winston

1. The problem.

Winston 1.0 and still 2.0 uses fs.readdirSync() which is not supported by brfs and the other goto fs transform modules.

2. The solution.

Browserify lets us write our own transforms. Thus if we take the MVP path, we can write two files one, that substitutes require("mockLogger") in for require("winston") out of every src file, and the second file to define the "mockLogger".

Assume we have file called browserTest.js as follows:

// browserTest.js
var winston = require('winston')
console.log('I am browserified!')
winston.info('I am info!')
winston.debug('I am info!')
winston.silly('I am info!')
winston.error('I am info!')

If we have a mockLogger.js file as follows:

// mockLogger.js
module.exports = {
  error: function(e) {
    console.log(e)
  },
  warn: function(d) {console.log(d)},
  verbose: function(d) {console.log(d)},
  info: function(d) {console.log(d)},
  debug: function(d) {console.log(d)},
  silly: function(d) {console.log(d)},
};

Then we can define a transform file called wtc.js like this:

// wtc.js
var through = require('through2')

module.exports = function(file) {
  return through(function(buf, enc, next) {
    this.push(buf.toString('utf8').replace(/require\(.winston.\).*(;)?/g,'require("./mockLogger");'))
    next()
  })
}


And the final browserify cli command:

browserify browserTest.js -t ./wtc.js > bundle.js

If you like you can run the above command without specifying the "-t ./wtc.js" part and if you simply try to run "node bundle.js" you will see a "TypeError: fs.readdirSync is not a function" Error.

Of course you don't really want to rely on the cli for production software. In that case you can forgo the transformer and just map the module substitution in your package.json like so:

//package.json
{
  "browser": {
    "winston": "./mockLogger"
  },
  "scripts" {
    "browersify": "browserify -e browserTest.js -o bundle.js"
  }
}

Your command then becomes:

npm run browserify