Skip to content

Instantly share code, notes, and snippets.

@mklabs
Created February 13, 2012 19:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mklabs/1819130 to your computer and use it in GitHub Desktop.
Save mklabs/1819130 to your computer and use it in GitHub Desktop.
browserify windows

Got some issue running browserify on windows. Some notes and the corresponding files patched. Not ran the browserify tests (should do) but tested on a rather complex build, working on both win32, osx.


  • browserify: lib/wrap.js wrappers/prelude.js
  • resolve: index.js

might issue a pull request, this needs tests, I need time (and sleeeeeeeep)

var fs = require('fs');
var path = require('path');
var EventEmitter = require('events').EventEmitter;
var detective = require('detective');
var deputy = require('deputy');
var resolve = require('resolve');
var wrappers = require('./wrappers');
var commondir = require('commondir');
var nub = require('nub');
module.exports = function (opts) {
return new Wrap(opts);
};
function Wrap (opts) {
if (opts.cache === undefined && process.env.HOME !== undefined) {
opts.cache = true;
}
if (opts.cache) {
if (typeof opts.cache === 'boolean') {
var file = (process.env.HOME || process.env.USERPROFILE) + '/.config/browserify/cache.json';
this.detective = deputy(file);
}
else {
this.detective = deputy(opts.cache);
}
}
else {
this.detective = detective;
}
this.files = {};
this.filters = [];
this.postFilters = [];
this.preFilters = [];
this.aliases = {};
this._checkedPackages = {};
this.ignoring = {};
this.extensions = [ '.js' ];
this.prepends = [ wrappers.prelude, wrappers.process ];
this.appends = []
this.entries = {};
this.debug = opts.debug;
this.require([ 'path' ]);
}
Wrap.prototype = new EventEmitter;
Wrap.prototype.prepend = function (src) {
this.prepends.unshift(src);
return this;
};
Wrap.prototype.append = function (src) {
this.appends.push(src);
return this;
};
Wrap.prototype.ignore = function (files) {
if (!files) files = [];
if (!Array.isArray(files)) files = [ files ];
this.ignoring = files.reduce(function (acc,x) {
acc[x] = true;
return acc;
}, {});
return this;
};
Wrap.prototype.use = function (fn) {
fn(this, this);
return this;
};
Wrap.prototype.register = function (ext, fn) {
if (typeof ext === 'object') {
fn = ext.wrapper;
ext = ext.extension;
}
if (ext === 'post') {
this.postFilters.push(fn);
}
else if (ext === 'pre') {
this.preFilters.push(fn);
}
else if (fn) {
this.extensions.push(ext);
this.filters.push(function (body, file) {
if (file.slice(-ext.length) === ext) {
return fn.call(this, body, file);
}
else return body;
});
}
else {
this.filters.push(ext);
}
return this;
};
Wrap.prototype.readFile = function (file) {
var self = this;
var body = fs.readFileSync(file, 'utf8').replace(/^#![^\n]*\n/, '');
self.filters.forEach(function (fn) {
body = fn.call(self, body, file);
});
return body;
};
Wrap.prototype.alias = function (to, from) {
this.aliases[to] = from;
return this;
};
Wrap.prototype.addEntry = function (file, opts) {
var self = this;
if (!opts) opts = {};
var body = opts.body || self.readFile(file);
try {
var required = self.detective.find(body);
}
catch (err) {
process.nextTick(function () {
self.emit('syntaxError', err);
});
return self;
}
if (required.expressions.length) {
console.error('Expressions in require() statements:');
required.expressions.forEach(function (ex) {
console.error(' require(' + ex + ')');
});
}
var dir = path.dirname(path.resolve(process.cwd(), file));
if (!opts.root) {
opts.root = commondir(dir, required.strings.concat(file));
}
file = path.resolve(process.cwd(), file);
required.strings.forEach(function (r) {
var x = r.match(/^(\.\.?)?\//) ? path.resolve(opts.root, r) : r;
self.require(x, { root : opts.root });
});
this.entries[file] = this.appends.length;
var target = (opts.target || file.slice(dir.length)).replace(/\\/g, '');
this.append((self.debug ? wrappers.entry_debug : wrappers.entry)
.replace(/\$__filename/g, function () {
return JSON.stringify(target)
})
.replace(/\$body/, function () {
return self.debug
? JSON.stringify(body + '\n//@ sourceURL=' + target)
: body
;
})
);
return this;
};
Wrap.prototype.bundle = function () {
var self = this;
for (var i = 0; i < self.prepends.length; i++) {
var p = self.prepends[i];
if (p === wrappers.prelude) {
self.prepends[i] = p.replace(/\$extensions/, function () {
return JSON.stringify(self.extensions);
});
break;
}
}
this.preFilters.forEach((function (fn) {
fn.call(this, this);
}).bind(this));
var src = []
.concat(this.prepends)
.concat(Object.keys(self.files).map(function (name) {
return self.files[name].body;
}))
.concat(Object.keys(self.aliases).map(function (to) {
var from = self.aliases[to];
if (!to.match(/^(\.\.?)?\//)) {
to = '/node_modules/' + to;
}
return wrappers.alias
.replace(/\$from/, function () {
return JSON.stringify(from);
})
.replace(/\$to/, function () {
return JSON.stringify(to);
})
;
}))
.concat(this.appends)
.join('\n')
;
this.postFilters.forEach((function (fn) {
src = fn.call(this, src);
}).bind(this));
return src;
};
Wrap.prototype.wrap = function (target, body) {
var self = this;
return (self.debug ? wrappers.body_debug : wrappers.body)
.replace(/\$__filename/g, function () {
return JSON.stringify(target);
})
.replace(/\$body/, function () {
return self.debug
? JSON.stringify(body + '\n//@ sourceURL=' + target)
: body
;
})
;
};
Wrap.prototype.include = function (file, target, body, root) {
var synthetic = !file;
if (!file) file = Math.floor(Math.random() * Math.pow(2,32)).toString(16);
//console.log('tt1', file, target);
console.log('tt1', target);
this.files[file] = {
body : this.wrap(target, body),
target : target,
synthetic : synthetic,
root : root
};
return this;
};
Wrap.prototype.reload = function (name) {
if (this.files[name] !== undefined) {
var file = this.files[name];
delete this.files[name];
this.require(name, { target : file.target, root : file.root });
}
else if (this.entries[name] !== undefined) {
var items = this.appends.splice(this.entries[name], 1);
try {
this.addEntry(name);
}
catch (e) {
// Return item back to list
this.appends.splice(this.entries[name], 0, items[0]);
// Rethrow error
throw e;
}
}
return this;
};
function makeTarget (file, root) {
root = path.join(root);
var target = isPrefixOf(path.join(root + '/'), file) ? path.normalize('/' + file.slice(root.length + 1)) :
resolve.isCore(file) ? path.normalize(file) :
file.match(/[\/\\]node_modules[\/\\].+/) ? path.normalize(file.match(/([\/\\]node_modules[\/\\].+)/)[1]) :
'';
if(!target) throw new Error('Can only load non-root modules'
+ ' in a node_modules directory for file: ' + file
);
return target.replace(/\\/g, '/');
}
Wrap.prototype.requireMultiple = function (startFiles) {
var self = this;
if (!startFiles) startFiles = []
else if (!Array.isArray(startFiles)) {
startFiles = [ startFiles ];
}
startFiles.forEach(function include (file) {
var dir = process.cwd();
if (typeof file === 'object') {
Object.keys(file).forEach(function (key) {
self.alias(key, file[key]);
include(file[key]);
});
return;
}
if (resolve.isCore(file)) {
var res = file;
}
else if (file.match(/^(\.\.?)?\//)) {
var res = path.resolve(process.cwd(), file);
var dir = path.dirname(res);
}
else {
var res = file;
}
self.require(res, { basedir : dir, root : dir });
});
return self;
};
Wrap.prototype.require = function (mfile, opts) {
var self = this;
if (!opts) opts = {};
if (!opts.basedir) opts.basedir = process.cwd();
mfile = mfile.replace ? mfile.replace(opts.basedir, '').replace(process.platform === 'win32' ? /^\\+/ : /^\/+/, './') : mfile;
if (typeof mfile === 'object') {
return self.requireMultiple(mfile, opts);
}
if (self.ignoring[mfile]) return self;
if (self.aliases[mfile]) return self;
var pkg = {};
if (resolve.isCore(mfile)) {
var file = path.resolve(__dirname, '../builtins/' + mfile + '.js');
opts.target = opts.target || mfile;
if (!path.existsSync(file)) {
throw new Error('No wrapper for core module ' + mfile);
}
}
else if (self.has(mfile, path.join('/node_modules/', mfile, 'index.js'))
|| self.has(mfile, path.join('/node_modules/', mfile, 'package.json'))) {
// package has already been included in some fashion, no need to resolve
return self;
}
else if (opts.body) {
var file = mfile;
}
else {
try {
var file = self.resolver(mfile, opts.basedir);
}
catch (err) {
throw new Error('Cannot find module ' + JSON.stringify(mfile)
+ ' from directory ' + JSON.stringify(opts.basedir)
);
}
}
opts.basedir = path.dirname(file);
if (!opts.root && mfile.match(/^\//)) {
opts.root = opts.basedir;
}
if (!opts.target) {
opts.target = makeTarget(file, opts.root);
}
if (self.ignoring[opts.target]) return self;
if (self.has(file, opts.target)) return self;
var pkgfile = opts.basedir + '/package.json';
if (!mfile.match(/^(\.\.?)?\//)) {
try {
pkgfile = resolve.sync(mfile + '/package.json', {
basedir : opts.basedir
});
}
catch (err) {}
}
if (pkgfile && !self._checkedPackages[pkgfile]) {
self._checkedPackages[pkgfile] = true;
if (path.existsSync(pkgfile)) {
var pkgBody = fs.readFileSync(pkgfile, 'utf8');
try {
var npmpkg = JSON.parse(pkgBody);
if (npmpkg.main !== undefined) {
pkg.main = npmpkg.main;
}
if (npmpkg.browserify !== undefined) {
pkg.browserify = npmpkg.browserify;
}
}
catch (err) {
// ignore broken package.jsons just like node
}
self.include(pkgfile, makeTarget(pkgfile, opts.root),
'module.exports = ' + JSON.stringify(pkg), opts.root
);
}
}
var body = opts.body || self.readFile(file);
self.include(file, opts.target, body, opts.root);
try {
var required = self.detective.find(body);
}
catch (err) {
process.nextTick(function () {
self.emit('syntaxError', err);
});
return self;
}
if (pkg.browserify && pkg.browserify.require) {
required.strings = required.strings.concat(
pkg.browserify.require
);
}
if (required.expressions.length) {
console.error('Expressions in require() statements:');
required.expressions.forEach(function (ex) {
console.error(' require(' + ex + ')');
});
}
nub(required.strings).forEach(function (req) {
self.require(req, { basedir : opts.basedir, root : opts.root })
});
return self;
};
function isPrefixOf (x, y) {
console.log('pôf', x, y);
return y.slice(0, x.length) === x;
}
Wrap.prototype.has = function (file, target) {
if (this.files[file]) return true;
var filenames = Object.keys(this.files);
for (var i = 0; i < filenames.length; i++) {
var f = this.files[filenames[i]];
if (f.target === target) return true;
}
return false;
};
Wrap.prototype.resolver = function (file, basedir) {
return resolve.sync(file, {
basedir : basedir,
extensions : this.extensions,
packageFilter : function (pkg) {
var b = pkg.browserify;
if (b) {
if (typeof b === 'string') {
pkg.main = b;
}
else if (typeof b === 'object' && b.main) {
pkg.main = b.main;
}
}
return pkg
}
});
}
var require = function (file, cwd) {
var resolved = require.resolve(file, cwd || '/');
var mod = require.modules[resolved];
if (!mod) throw new Error(
'Failed to resolve module ' + file + ', tried ' + resolved
);
var res = mod._cached ? mod._cached : mod();
return res;
}
require.paths = [];
require.modules = {};
require.extensions = $extensions;
require._core = {
'assert': true,
'events': true,
'fs': true,
'path': true,
'vm': true
};
require.resolve = (function () {
return function (x, cwd) {
if (!cwd) cwd = '/';
if (require._core[x]) return x;
var path = require.modules.path();
var y = cwd || '.';
if(y === '.') y = '/';
if (x.match(/^(?:\.\.?\/|\/)/)) {
var m = loadAsFileSync(path.resolve(y, x))
|| loadAsDirectorySync(path.resolve(y, x));
if (m) return m;
}
var n = loadNodeModulesSync(x, y);
if (n) return n;
throw new Error("Cannot find module '" + x + "'");
function loadAsFileSync (x) {
if (require.modules[x]) {
return x;
}
for (var i = 0; i < require.extensions.length; i++) {
var ext = require.extensions[i];
if (require.modules[x + ext]) return x + ext;
}
}
function loadAsDirectorySync (x) {
x = x.replace(/\/+$/, '');
var pkgfile = x + '/package.json';
if (require.modules[pkgfile]) {
var pkg = require.modules[pkgfile]();
var b = pkg.browserify;
if (typeof b === 'object' && b.main) {
var m = loadAsFileSync(path.resolve(x, b.main));
if (m) return m;
}
else if (typeof b === 'string') {
var m = loadAsFileSync(path.resolve(x, b));
if (m) return m;
}
else if (pkg.main) {
var m = loadAsFileSync(path.resolve(x, pkg.main));
if (m) return m;
}
}
return loadAsFileSync(x + '/index');
}
function loadNodeModulesSync (x, start) {
var dirs = nodeModulesPathsSync(start);
for (var i = 0; i < dirs.length; i++) {
var dir = dirs[i];
var m = loadAsFileSync(dir + '/' + x);
if (m) return m;
var n = loadAsDirectorySync(dir + '/' + x);
if (n) return n;
}
var m = loadAsFileSync(x);
if (m) return m;
}
function nodeModulesPathsSync (start) {
var parts;
if (start === '/') parts = [ '' ];
else parts = path.normalize(start).split('/');
var dirs = [];
for (var i = parts.length - 1; i >= 0; i--) {
if (parts[i] === 'node_modules') continue;
var dir = parts.slice(0, i + 1).join('/') + '/node_modules';
dirs.push(dir);
}
return dirs;
}
};
})();
require.alias = function (from, to) {
var path = require.modules.path();
var res = null;
try {
res = require.resolve(from + '/package.json', '/');
}
catch (err) {
res = require.resolve(from, '/');
}
var basedir = path.dirname(res);
var keys = (Object.keys || function (obj) {
var res = [];
for (var key in obj) res.push(key)
return res;
})(require.modules);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (key.slice(0, basedir.length + 1) === basedir + '/') {
var f = key.slice(basedir.length);
require.modules[to + f] = require.modules[basedir + f];
}
else if (key === basedir) {
require.modules[to] = require.modules[basedir];
}
}
};
require.define = function (filename, fn) {
var dirname = require._core[filename]
? ''
: require.modules.path().dirname(filename)
;
var require_ = function (file) {
return require(file, dirname)
};
require_.resolve = function (name) {
return require.resolve(name, dirname);
};
require_.modules = require.modules;
require_.define = require.define;
var module_ = { exports : {} };
require.modules[filename] = function () {
require.modules[filename]._cached = module_.exports;
fn.call(
module_.exports,
require_,
module_,
module_.exports,
dirname,
filename
);
require.modules[filename]._cached = module_.exports;
return module_.exports;
};
};
var fs = require('fs');
var path = require('path');
// http://nodejs.org/docs/v0.4.8/api/all.html#all_Together...
var core = exports.core = [
'assert', 'buffer', 'child_process', 'crypto', 'dgram', 'dns', 'events',
'fs', 'http', 'https', 'net', 'os', 'path', 'querystring', 'repl', 'stream',
'sys', 'tls', 'tty', 'url', 'util', 'vm'
].reduce(function (acc, x) { acc[x] = true; return acc }, {});
exports.isCore = function (x) { return core[x] };
exports.sync = function (x, opts) {
if (core[x]) return x;
if (!opts) opts = {};
var extensions = opts.extensions || [ '.js' ];
var y = opts.basedir
|| path.dirname(require.cache[__filename].parent.filename)
;
if (x.match(/^(?:\.\.?\/|\/)/)) {
var m = loadAsFileSync(path.resolve(y, x))
|| loadAsDirectorySync(path.resolve(y, x));
if (m) return m;
}
var n = loadNodeModulesSync(x, y);
if (n) return n;
throw new Error("Cannot find module '" + x + "'");
function loadAsFileSync (x) {
if (path.existsSync(x) && fs.statSync(x).isFile()) {
return x;
}
for (var i = 0; i < extensions.length; i++) {
var file = x + extensions[i];
if (path.existsSync(file) && fs.statSync(file).isFile()) {
return file;
}
}
}
function loadAsDirectorySync (x) {
var pkgfile = path.join(x, 'package.json');
if (path.existsSync(pkgfile) && fs.statSync(pkgfile).isFile()) {
var body = fs.readFileSync(pkgfile, 'utf8');
try {
var pkg = JSON.parse(body);
if (opts.packageFilter) {
pkg = opts.packageFilter(pkg);
}
if (pkg.main) {
var m = loadAsFileSync(path.resolve(x, pkg.main));
if (m) return m;
}
}
catch (err) {}
}
return loadAsFileSync(path.join(x, 'index'));
}
function loadNodeModulesSync (x, start) {
var dirs = nodeModulesPathsSync(start);
for (var i = 0; i < dirs.length; i++) {
var dir = dirs[i];
var m = loadAsFileSync(path.join(dir, x));
if (m) return m;
var n = loadAsDirectorySync(path.join(dir, x));
if (n) return n;
}
}
function nodeModulesPathsSync (start) {
var parts = start.split(process.platform === 'win32' ? /\\+/ : /\/+/);
var dirs = [];
for (var i = parts.length - 1; i >= 0; i--) {
if (parts[i] === 'node_modules') continue;
var dir = path.join(path.join.apply(path, parts.slice(0, i + 1)), 'node_modules');
dirs.push(dir);
}
return dirs;
}
};
@cjblomqvist
Copy link

Worth noting is that browserify/index.js wasn't actually changed anything (I've compared to the status of the file when it was changed).

@mklabs
Copy link
Author

mklabs commented Apr 20, 2012

true =/ thx for the feedback, deleted the index.js file

I totally forgot about this gist, I should clean this up and don't leave this around.

@cjblomqvist
Copy link

Actually, the change in wrappers/prelude.js is also unnecessary anymore. I cleaned up your code and made a pull request to the browserify repo. All info can be found: browserify/browserify#125

There is one place I added comments about a couple of regexps that I thought may need to be changed as well, but to be frank, I didn't put that much effort into understanding your, or browserify's code, to be sure. Thx for your great gist!

@mklabs
Copy link
Author

mklabs commented Apr 20, 2012

\o/

Thank you for that! That's cool to hear, if it can get to browserify repo and have it work on windows too, would be great news.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment