Files
react-native/packager/react-packager/src/Server/index.js
Amjad Masad 5aa5e7a875 2015-02-09 updates
[react-packager] Update other instances of projectRoot to projectRoots | Amjad Masad
[react-packager] Debug page | Amjad Masad
2015-02-11 16:37:51 -08:00

166 lines
4.7 KiB
JavaScript

var url = require('url');
var path = require('path');
var FileWatcher = require('../FileWatcher')
var Packager = require('../Packager');
var Activity = require('../Activity');
var q = require('q');
module.exports = Server;
function Server(options) {
this._projectRoots = options.projectRoots;
this._packages = Object.create(null);
this._packager = new Packager({
projectRoots: options.projectRoots,
blacklistRE: options.blacklistRE,
polyfillModuleNames: options.polyfillModuleNames || [],
runtimeCode: options.runtimeCode,
cacheVersion: options.cacheVersion,
resetCache: options.resetCache,
dev: options.dev,
});
this._fileWatcher = new FileWatcher(options.projectRoots);
var onFileChange = this._onFileChange.bind(this);
this._fileWatcher.on('all', onFileChange);
}
Server.prototype._onFileChange = function(type, filepath, root) {
var absPath = path.join(root, filepath);
this._packager.invalidateFile(absPath);
// Make sure the file watcher event runs through the system before
// we rebuild the packages.
setImmediate(this._rebuildPackages.bind(this, absPath))
};
Server.prototype._rebuildPackages = function(filepath) {
var buildPackage = this._buildPackage.bind(this);
var packages = this._packages;
Object.keys(packages).forEach(function(key) {
var options = getOptionsFromPath(url.parse(key).pathname);
packages[key] = buildPackage(options).then(function(p) {
// Make a throwaway call to getSource to cache the source string.
p.getSource();
return p;
});
});
};
Server.prototype.kill = function() {
q.all([
this._fileWatcher.end(),
this._packager.kill(),
]);
};
Server.prototype._buildPackage = function(options) {
return this._packager.package(
options.main,
options.runModule,
options.sourceMapUrl
);
};
Server.prototype.buildPackageFromUrl = function(reqUrl) {
var options = getOptionsFromPath(url.parse(reqUrl).pathname);
return this._buildPackage(options);
};
Server.prototype._processDebugRequest = function(reqUrl, res) {
var ret = '<!doctype html>';
var pathname = url.parse(reqUrl).pathname;
var parts = pathname.split('/').filter(Boolean);
if (parts.length === 1) {
ret += '<div><a href="/debug/packages">Cached Packages</a></div>';
ret += '<div><a href="/debug/graph">Dependency Graph</a></div>';
res.end(ret);
} else if (parts[1] === 'packages') {
ret += '<h1> Cached Packages </h1>';
q.all(Object.keys(this._packages).map(function(url) {
return this._packages[url].then(function(p) {
ret += '<div><h2>' + url + '</h2>';
ret += p.getDebugInfo();
});
}, this)).then(
function() { res.end(ret); },
function(e) {
res.wrteHead(500);
res.end('Internal Error');
console.log(e.stack);
}
);
} else if (parts[1] === 'graph'){
ret += '<h1> Dependency Graph </h2>';
ret += this._packager.getGraphDebugInfo();
res.end(ret);
} else {
res.writeHead('404');
res.end('Invalid debug request');
return;
}
};
Server.prototype.processRequest = function(req, res, next) {
var requestType;
if (req.url.match(/\.bundle$/)) {
requestType = 'bundle';
} else if (req.url.match(/\.map$/)) {
requestType = 'map';
} else if (req.url.match(/^\/debug/)) {
this._processDebugRequest(req.url, res);
return;
} else {
return next();
}
var startReqEventId = Activity.startEvent('request:' + req.url);
var options = getOptionsFromPath(url.parse(req.url).pathname);
var building = this._packages[req.url] || this._buildPackage(options)
this._packages[req.url] = building;
building.then(
function(p) {
if (requestType === 'bundle') {
res.end(p.getSource());
Activity.endEvent(startReqEventId);
} else if (requestType === 'map') {
res.end(JSON.stringify(p.getSourceMap()));
Activity.endEvent(startReqEventId);
}
},
function(error) {
handleError(res, error);
}
).done();
};
function getOptionsFromPath(pathname) {
var parts = pathname.split('.');
// Remove the leading slash.
var main = parts[0].slice(1) + '.js';
return {
runModule: parts.slice(1).some(function(part) {
return part === 'runModule';
}),
main: main,
sourceMapUrl: parts.slice(0, -1).join('.') + '.map'
};
}
function handleError(res, error) {
res.writeHead(500, {
'Content-Type': 'application/json; charset=UTF-8',
});
if (error.type === 'TransformError') {
res.end(JSON.stringify(error));
} else {
console.error(error.stack || error);
res.end(JSON.stringify({
type: 'InternalError',
message: 'react-packager has encountered an internal error, ' +
'please check your terminal error output for more details',
}));
}
}