This project:

1. is a case-study for [browserifying anything](https://gist.github.com/kumavis/5703360)
2. part of a dream to create virtual Node.js development environment
3. likely a major time-sink!

starting out:
```
mkdir browser-npm && cd browser-npm
npm install npm
npm init
```

make an index.js
```javascript
var npm = require('npm')
debugger
```

and an index.html
```html
<body> b r o w s e r - n p m <script src="bundle.js"></script></body>
```

ok simple enough lets see what happens next
```
browserify index.js >| bundle.js
```

didn't think it would be that easy did you? I get:
```
Error: module "os" not found from "/Users/kumavis/Dropbox/Development/Node/browser-npm/node_modules/npm/lib/utils/error-handler.js"
```

ok, what is this `os` module? in Node I can see that it is provided out of the box, I would consider it a core-module:
```javascript
> require('os')
{ hostname: [Function],
  loadavg: [Function],
  uptime: [Function],
  freemem: [Function],
  totalmem: [Function],
  cpus: [Function],
  type: [Function],
  release: [Function],
  networkInterfaces: [Function],
  arch: [Function],
  platform: [Function],
  tmpDir: [Function],
  getNetworkInterfaces: [Function: deprecated],
  EOL: '\n' }
```

if its a core module, why didn't browser-resolve supply it?
```
ls /usr/local/share/npm/lib/node_modules/browserify/node_modules/browser-resolve/builtin
assert.js         events.js         net.js            querystring.js    sys.js            tty.js
child_process.js  fs.js             path.js           stream.js         timers.js         url.js
dgram.js          https.js          process.js        string_decoder.js tls.js            util.js
```

Oh well we can make our own as needed. skimming the results of `npm search browser os` I found [os-browserify](https://github.com/CoderPuppy/os-browserify/blob/master/index.js). It will do! I am going to add it browserify's browser-resolve's deps,

```javascript
  "dependencies": {
    "resolve": "0.3.1",
    "console-browserify": "0.1.6",
    "vm-browserify": "0.0.1",
    "crypto-browserify": "0.2.1",
    "http-browserify": "0.1.11",
    "buffer-browserify": "0.0.5",
    "zlib-browserify": "0.0.1",
    "os-browserify": "0.1.0"
  },
```
navigate to `browserify/node_modules/browser-resolve/` and `npm install`.

Next add `core['os'] = require.resolve('os-browserify');` to [browserify/node_modules/browser-resolve/index.js](https://github.com/shtylman/node-browser-resolve/blob/1eebfe102be94cfcb8e85e352aa1abe5e7b0f407/index.js#L16-L22)

oh! I almost forgot. We need to tell `browser-resolve` to use its own list of core modules, instead of asking regular `resolve`. Replace [this line](https://github.com/shtylman/node-browser-resolve/blob/1eebfe102be94cfcb8e85e352aa1abe5e7b0f407/index.js#L113) with this
```javascript
if (core.hasOwnProperty(id)) {
```

returning to our `browser-npm` directory, lets try bundling again...
```
/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:3859
            throw e;
                  ^
Error: Line 9: Illegal return statement
    at throwError (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:1161:21)
    at throwErrorTolerant (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:1172:24)
    at parseReturnStatement (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:2476:13)
    at parseStatement (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:2752:24)
    at parseIfStatement (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:2191:22)
    at parseStatement (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:2750:24)
    at parseSourceElement (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:3044:24)
    at parseSourceElements (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:3082:29)
    at parseProgram (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:3096:19)
    at parse (/usr/local/share/npm/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/lexical-scope/node_modules/astw/node_modules/esprima/esprima.js:3843:23)
```

ouch! right in the esprima! ok lets see whats going on here. Well apparently [esprima](https://github.com/ariya/esprima) is an "ECMAScript parsing infrastructure". Clearly browserify is using this to seek `require` calls and bundle dependencies. But something has gone awry - search reveals [that others are getting this unhelpful error message](https://github.com/substack/node-browserify/issues/308), the posted issue unresolved at the time of this writing.

In order to find out what code is being parsed when the error thrown, I add `process.stderr.write(source);` right above the `throwErrorTolerant({}, Messages.IllegalReturn);` line, `browserify index.js >| bundle.js` again, take the console output and use it to do a project-wide search in `browser-npm/`. Don't forget to undo changes to esprima.js!

It is from `browser-npm/node_modules/npm/node_modules/child-process-close/index.js`. The above github issue says that you can avoid this `Illegal return statement` error by wrapping your code in a closure, like so:
```javascript
(function(){
  < original index.js content >
})();
```

This is a good time to stretch, get a glass of water. Ready?

```
browserify index.js >| bundle.js
Error: ENOENT, open 'constants'
```

Not a lot of details, but browserify is trying to open a file 'constants' and failing. In node, `require('constants')` resolves to a Hash of integers. [This looks relevant](https://github.com/joyent/node/blob/6ecb0cd65d2f818a35adb80d23261555b63528ca/src/node_constants.cc), but I'm just going to figure this one is a core module and save [this output}(https://gist.github.com/kumavis/5704326) from the` require('constants')` to `browserify/node_modules/browser-resolve/builtin/constants.js`. Since we changed `browser-resolve/index.js` to rely on its own understanding of `core`, we should be good.
Note: these numbers may be machine specific. You may want to use what is output by your machine instead. I don't really know. We'll figure it out later if we need to.

Continuing onward!

```
browserify index.js >| bundle.js

/Users/kumavis/Dropbox/Development/Node/browser-npm/node_modules/npm/bin/npm-cli.js:1
(function(process){#!/usr/bin/env node
                   ^
ParseError: Unexpected token ILLEGAL
```

Hmmm, there's a bit of preprocessor directive or something at the head of `npm-cli.js`. I'm not exactly sure what that is or what its for, but I'll just comment it out for now.
```
browserify index.js >| bundle.js
Error: ENOENT, open 'dns'
```

Can't find the file 'dns'. I'm going to guess its another core module. Node? [Node agrees](http://nodejs.org/api/dns.html), Lets `npm search browser dns`. Hmmm nothing. We'll need to roll our own. I'm just going to do a copy-paste-hack job here. It will likely break if you try to actualy use it. Save [this](https://gist.github.com/kumavis/5704306) as `browserify/node_modules/browser-resolve/builtin/dns.js`

What's next?
```
[kumavis:...evelopment/Node/browser-npm]$ browserify index.js >| bundle.js
[kumavis:...evelopment/Node/browser-npm]$
```

woah. cool. But I wouldn't get too excited, this journey has just begun. Opening up `index.html` I can use the debugger to see what the first problem is.

```javascript
Uncaught TypeError: Cannot read property '_ansicursor' of undefined     bundle.js:12175
```
this error originates from the middle line
```javascript
var ansi = require('ansi')
log.cursor = ansi(process.stderr)
log.stream = process.stderr
```
which in turn comes from a half-hearted implementation of `process`
```javascript
> process.stderr
undefined
```

[The docs say](http://nodejs.org/api/process.html#process_process_stderr) `process.stderr` should be a stream

I assumed that this was coming from `browserify/node_modules/browser-resolve/builtin/process.js` but apparently it actually comes from `browserify/node_modules/insert-module-globals/node_modules/process/browser.js`. Add the following:

```javascript
Stream = require('stream');
```
and
```javascript
process.stderr = new Stream();
//  copy pasta from `process.stderr.write.toString()`
process.stderr.write = function (data, arg1, arg2) {
  var encoding, cb;

  // parse arguments
  if (arg1) {
    if (typeof arg1 === 'string') {
      encoding = arg1;
      cb = arg2;
    } else if (typeof arg1 === 'function') {
      cb = arg1;
    } else {
      throw new Error('bad arg');
    }
  }

  if (typeof data === 'string') {
    encoding = (encoding || 'utf8').toLowerCase();
    switch (encoding) {
      case 'utf8':
      case 'utf-8':
      case 'ascii':
      case 'ucs2':
      case 'ucs-2':
      case 'utf16le':
      case 'utf-16le':
        // This encoding can be handled in the binding layer.
        break;

      default:
        data = new Buffer(data, encoding);
    }
  } else if (!Buffer.isBuffer(data)) {
    throw new TypeError('First argument must be a buffer or a string.');
  }

  // If we are still connecting, then buffer this for later.
  if (this._connecting) {
    this._connectQueueSize += data.length;
    if (this._connectQueue) {
      this._connectQueue.push([data, encoding, cb]);
    } else {
      this._connectQueue = [[data, encoding, cb]];
    }
    return false;
  }

  return this._write(data, encoding, cb);
}
```

 If you `browserify` and run you'll find that it isn't able to get the Stream package for you. `browserify/node_modules/insert-module-globals/index.js` needs you to manually set deps. Adjust line 59 as below:
 
```javascript
    deps: {"stream": path.join(__dirname+"../../browser-resolve", 'builtin/stream.js')}
```

Running again, we hit our debugger statement in our own `index.js`! Home sweet home. We're clearly making progress. Of course node is very async, so now we have to catch up with all the work various modules have set aside to be done, and for us that means more debugging and patching holes. Let's remove the debugger statement before we carry on.

next we're on `browser-npm/node_modules/npm/node_modules/graceful-fs/graceful-fs.js` 
```javascript
// lchmod, broken prior to 0.6.2
// back-port the fix here.
if (constants.hasOwnProperty('O_SYMLINK') &&
    process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
```
Its trying to compensate for old node versions and `process.version` is undefined. We'll just use Node's output. Add this to `browserify/node_modules/insert-module-globals/node_modules/process/browser.js`.

```javascript
process.version = 'v0.8.21';
```

Next we have something trying to readFileSync `/node_modules/npm/node_modules/request/node_modules/mime/types/mime.types` using my virtual file system! (1) My file system isn't quite ready for use (2) Its empty! There aren't any files stored on it.  Sounds like we'll need to seed our file system with some basic node environment. 

See you next time!