Simplify require polyfill

Reviewed By: @vjeux

Differential Revision: D2544415

fb-gh-sync-id: ab48b5fba169c43c68dd24dc95ea1d0322ed67c4
This commit is contained in:
Bhuwan Khattar 2015-10-15 12:53:12 -07:00 committed by facebook-github-bot-7
parent 643769fc8e
commit 83b8a30beb
2 changed files with 42 additions and 564 deletions

View File

@ -150,7 +150,6 @@ HasteDependencyResolver.prototype.wrapModule = function(resolutionResponse, modu
name => defineModuleCode({ name => defineModuleCode({
code: code.replace(replacePatterns.IMPORT_RE, relativizeCode) code: code.replace(replacePatterns.IMPORT_RE, relativizeCode)
.replace(replacePatterns.REQUIRE_RE, relativizeCode), .replace(replacePatterns.REQUIRE_RE, relativizeCode),
deps: JSON.stringify(resolvedDepsArr),
moduleName: name, moduleName: name,
}) })
); );
@ -162,11 +161,10 @@ HasteDependencyResolver.prototype.getDebugInfo = function() {
return this._depGraph.getDebugInfo(); return this._depGraph.getDebugInfo();
}; };
function defineModuleCode({moduleName, code, deps}) { function defineModuleCode({moduleName, code}) {
return [ return [
`__d(`, `__d(`,
`'${moduleName}',`, `'${moduleName}',`,
`${deps},`,
'function(global, require, module, exports) {', 'function(global, require, module, exports) {',
` ${code}`, ` ${code}`,
'\n});', '\n});',

View File

@ -1,587 +1,67 @@
/* eslint global-strict:0,eqeqeq:0,no-bitwise:0,no-undef:0 */ /* eslint strict:0 */
(function(global) { (function(global) {
var modules = Object.create(null);
var inGuard = false;
// avoid redefining require() function define(id, factory) {
if (global.require) { modules[id] = {
return; factory,
module: {exports: {}},
isInitialized: false,
hasError: false,
};
} }
var __DEV__ = global.__DEV__;
var toString = Object.prototype.toString;
/**
* module index: {
* mod1: {
* exports: { ... },
* id: 'mod1',
* dependencies: ['mod1', 'mod2'],
* factory: function() { ... },
* waitingMap: { mod1: 1, mod3: 1, mod4: 1 },
* waiting: 2
* }
* }
*/
var modulesMap = {},
/**
* inverse index: {
* mod1: [modules, waiting for mod1],
* mod2: [modules, waiting for mod2]
* }
*/
dependencyMap = {},
/**
* modules whose reference counts are set out of order
*/
predefinedRefCounts = {},
_counter = 0,
REQUIRE_WHEN_READY = 1,
USED_AS_TRANSPORT = 2,
hop = Object.prototype.hasOwnProperty;
function _debugUnresolvedDependencies(names) {
var unresolved = Array.prototype.slice.call(names);
var visited = {};
var ii, name, module, dependency;
while (unresolved.length) {
name = unresolved.shift();
if (visited[name]) {
continue;
}
visited[name] = true;
module = modulesMap[name];
if (!module || !module.waiting) {
continue;
}
for (ii = 0; ii < module.dependencies.length; ii++) {
dependency = module.dependencies[ii];
if (!modulesMap[dependency] || modulesMap[dependency].waiting) {
unresolved.push(dependency);
}
}
}
for (name in visited) if (hop.call(visited, name)) {
unresolved.push(name);
}
var messages = [];
for (ii = 0; ii < unresolved.length; ii++) {
name = unresolved[ii];
var message = name;
module = modulesMap[name];
if (!module) {
message += ' is not defined';
} else if (!module.waiting) {
message += ' is ready';
} else {
var unresolvedDependencies = [];
for (var jj = 0; jj < module.dependencies.length; jj++) {
dependency = module.dependencies[jj];
if (!modulesMap[dependency] || modulesMap[dependency].waiting) {
unresolvedDependencies.push(dependency);
}
}
message += ' is waiting for ' + unresolvedDependencies.join(', ');
}
messages.push(message);
}
return messages.join('\n');
}
/**
* This is mainly for logging in ModuleErrorLogger.
*/
function ModuleError(msg) {
this.name = 'ModuleError';
this.message = msg;
this.stack = Error(msg).stack;
this.framesToPop = 2;
}
ModuleError.prototype = Object.create(Error.prototype);
ModuleError.prototype.constructor = ModuleError;
var _performance =
global.performance ||
global.msPerformance ||
global.webkitPerformance || {};
if (!_performance.now) {
_performance = global.Date;
}
var _now = _performance ?
_performance.now.bind(_performance) : function(){ return 0; };
var _factoryStackCount = 0;
var _factoryTime = 0;
var _totalFactories = 0;
var _inGuard = false;
/**
* The require function conforming to CommonJS spec:
* http://wiki.commonjs.org/wiki/Modules/1.1.1
*
* To define a CommonJS-compliant module add the providesModule
* Haste header to your file instead of @provides. Your file is going
* to be executed in a separate context. Every variable/function you
* define will be local (private) to that module. To export local members
* use "exports" variable or return the exported value at the end of your
* file. Your code will have access to the "module" object.
* The "module" object will have an "id" property that is the id of your
* current module. "module" object will also have "exports" property that
* is the same as "exports" variable passed into your module context.
* You can require other modules using their ids.
*
* Haste will automatically pick dependencies from require() calls. So
* you don't have to manually specify @requires in your header.
*
* You cannot require() modules from non-CommonJS files. Write a legacy stub
* (@providesLegacy) and use @requires instead.
*
* @example
*
* / **
* * @providesModule math
* * /
* exports.add = function() {
* var sum = 0, i = 0, args = arguments, l = args.length;
* while (i < l) {
* sum += args[i++];
* }
* return sum;
* };
*
* / **
* * @providesModule increment
* * /
* var add = require('math').add;
* return function(val) {
* return add(val, 1);
* };
*
* / **
* * @providesModule program
* * /
* var inc = require('increment');
* var a = 1;
* inc(a); // 2
*
* module.id == "program";
*
*
* @param {String} id
* @throws when module is not loaded or not ready to be required
*/
function require(id) { function require(id) {
var module = modulesMap[id], dep, i, msg; var mod = modules[id];
if (module && module.exports) { if (mod && mod.isInitialized) {
// If ref count is 1, this was the last call, so undefine the module. return mod.module.exports;
// The ref count can be null or undefined, but those are never === 1.
if (module.refcount-- === 1) {
delete modulesMap[id];
}
return module.exports;
} }
if (global.ErrorUtils && !_inGuard) {
_inGuard = true; return requireImpl(id);
}
function requireImpl(id) {
if (global.ErrorUtils && !inGuard) {
inGuard = true;
var returnValue;
try { try {
var ret = require.apply(this, arguments); returnValue = requireImpl.apply(this, arguments);
} catch(e) { } catch (e) {
global.ErrorUtils.reportFatalError(e); global.ErrorUtils.reportFatalError(e);
} }
_inGuard = false; inGuard = false;
return ret; return returnValue;
} }
if (!module) { var mod = modules[id];
msg = 'Requiring unknown module "' + id + '"'; if (!mod) {
var msg = 'Requiring unknown module "' + id + '"';
if (__DEV__) { if (__DEV__) {
msg += '. If you are sure the module is there, try restarting the packager.'; msg += '. If you are sure the module is there, try restarting the packager.';
} }
throw new ModuleError(msg); throw new Error(msg);
} }
if (module.hasError) { if (mod.hasError) {
throw new ModuleError( throw new Error(
'Requiring module "' + id + '" which threw an exception' 'Requiring module "' + id + '" which threw an exception'
); );
} }
if (module.waiting) { try {
throw new ModuleError( // keep args in sync with with defineModuleCode in
'Requiring module "' + id + '" with unresolved dependencies: ' + // packager/react-packager/src/DependencyResolver/index.js
_debugUnresolvedDependencies([id]) mod.factory.call(global, global, require, mod.module, mod.module.exports);
); mod.isInitialized = true;
} catch (e) {
mod.hasError = true;
throw e;
} }
var exports = module.exports = {}; return mod.module.exports;
var factory = module.factory;
if (toString.call(factory) === '[object Function]') {
var args = [],
dependencies = module.dependencies,
length = dependencies.length,
ret;
if (module.special & USED_AS_TRANSPORT) {
length = Math.min(length, factory.length);
}
try {
for (i = 0; args.length < length; i++) {
dep = dependencies[i];
if (!module.inlineRequires[dep]) {
args.push(dep === 'module' ? module :
(dep === 'exports' ? exports :
require.call(null, dep)));
}
}
++_totalFactories;
if (_factoryStackCount++ === 0) {
_factoryTime -= _now();
}
try {
ret = factory.apply(module.context || global, args);
} catch (e) {
if (modulesMap.ex && modulesMap.erx) {
// when ErrorUtils is ready, ex and erx are ready. otherwise, we
// don't append module id to the error message but still throw it
var ex = require.call(null, 'ex');
var erx = require.call(null, 'erx');
var messageWithParams = erx(e.message);
if (messageWithParams[0].indexOf(' from module "%s"') < 0) {
messageWithParams[0] += ' from module "%s"';
messageWithParams[messageWithParams.length] = id;
}
e.message = ex.apply(null, messageWithParams);
}
throw e;
} finally {
if (--_factoryStackCount === 0) {
_factoryTime += _now();
}
}
} catch (e) {
module.hasError = true;
module.exports = null;
throw e;
}
if (ret) {
if (__DEV__) {
if (typeof ret != 'object' && typeof ret != 'function') {
throw new ModuleError(
'Factory for module "' + id + '" returned ' +
'an invalid value "' + ret + '". ' +
'Returned value should be either a function or an object.'
);
}
}
module.exports = ret;
}
} else {
module.exports = factory;
}
// If ref count is 1, this was the last call, so undefine the module.
// The ref count can be null or undefined, but those are never === 1.
if (module.refcount-- === 1) {
delete modulesMap[id];
}
return module.exports;
} }
require.__getFactoryTime = function() { global.__d = define;
return (_factoryStackCount ? _now() : 0) + _factoryTime;
};
require.__getTotalFactories = function() {
return _totalFactories;
};
/**
* Asynchronously loads any missing dependency and executes the provided
* callback once all of them are satisfied.
*
* Note that the dependencies on the provided array must be string literals
* as the packager uses this information to figure out how the modules are
* packaged into different bundles.
*/
require.ensure = function(dependencies, callback) {
throw '`require.ensure` is still not supported';
};
/**
* The define function conforming to CommonJS proposal:
* http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition
*
* define() allows you to explicitly state dependencies of your module
* in javascript. It's most useful in non-CommonJS files.
*
* define() is used internally by haste as a transport for CommonJS
* modules. So there's no need to use define() if you use providesModule
*
* @example
* / **
* * @provides alpha
* * /
*
* // Sets up the module with ID of "alpha", that uses require,
* // exports and the module with ID of "beta":
* define("alpha", ["require", "exports", "beta"],
* function (require, exports, beta) {
* exports.verb = function() {
* return beta.verb();
* //Or:
* return require("beta").verb();
* }
* });
*
* / **
* * @provides alpha
* * /
* // An anonymous module could be defined (module id derived from filename)
* // that returns an object literal:
*
* define(["alpha"], function (alpha) {
* return {
* verb: function(){
* return alpha.verb() + 2;
* }
* };
* });
*
* / **
* * @provides alpha
* * /
* // A dependency-free module can define a direct object literal:
*
* define({
* add: function(x, y){
* return x + y;
* }
* });
*
* @param {String} id optional
* @param {Array} dependencies optional
* @param {Object|Function} factory
*/
function define(id, dependencies, factory,
_special, _context, _refCount, _inlineRequires) {
if (dependencies === undefined) {
dependencies = [];
factory = id;
id = _uid();
} else if (factory === undefined) {
factory = dependencies;
if (toString.call(id) === '[object Array]') {
dependencies = id;
id = _uid();
} else {
dependencies = [];
}
}
// Non-standard: we allow modules to be undefined. This is designed for
// temporary modules.
var canceler = { cancel: _undefine.bind(this, id) };
var record = modulesMap[id];
// Nonstandard hack: we call define with null deps and factory, but a
// non-null reference count (e.g. define('name', null, null, 0, null, 4))
// when this module is defined elsewhere and we just need to update the
// reference count. We use this hack to avoid having to expose another
// global function to increment ref counts.
if (record) {
if (_refCount) {
record.refcount += _refCount;
}
// Calling define() on a pre-existing module does not redefine it
return canceler;
} else if (!dependencies && !factory && _refCount) {
// If this module hasn't been defined yet, store the ref count. We'll use
// it when the module is defined later.
predefinedRefCounts[id] = (predefinedRefCounts[id] || 0) + _refCount;
return canceler;
} else {
// Defining a new module
record = { id: id };
record.refcount = (predefinedRefCounts[id] || 0) + (_refCount || 0);
delete predefinedRefCounts[id];
}
if (__DEV__) {
if (
!factory ||
(typeof factory != 'object' && typeof factory != 'function' &&
typeof factory != 'string')) {
throw new ModuleError(
'Invalid factory "' + factory + '" for module "' + id + '". ' +
'Factory should be either a function or an object.'
);
}
if (toString.call(dependencies) !== '[object Array]') {
throw new ModuleError(
'Invalid dependencies for module "' + id + '". ' +
'Dependencies must be passed as an array.'
);
}
}
record.factory = factory;
record.dependencies = dependencies;
record.context = _context;
record.special = _special;
record.inlineRequires = _inlineRequires || {};
record.waitingMap = {};
record.waiting = 0;
record.hasError = false;
modulesMap[id] = record;
_initDependencies(id);
return canceler;
}
function _undefine(id) {
if (!modulesMap[id]) {
return;
}
var module = modulesMap[id];
delete modulesMap[id];
for (var dep in module.waitingMap) {
if (module.waitingMap[dep]) {
delete dependencyMap[dep][id];
}
}
for (var ii = 0; ii < module.dependencies.length; ii++) {
dep = module.dependencies[ii];
if (modulesMap[dep]) {
if (modulesMap[dep].refcount-- === 1) {
_undefine(dep);
}
} else if (predefinedRefCounts[dep]) {
predefinedRefCounts[dep]--;
}
// Subtle: we won't account for this one fewer reference if we don't have
// the dependency's definition or reference count yet.
}
}
function _uid() {
return '__mod__' + _counter++;
}
function _addDependency(module, dep) {
// do not add duplicate dependencies and circ deps
if (!module.waitingMap[dep] && module.id !== dep) {
module.waiting++;
module.waitingMap[dep] = 1;
dependencyMap[dep] || (dependencyMap[dep] = {});
dependencyMap[dep][module.id] = 1;
}
}
function _initDependencies(id) {
var modulesToRequire = [];
var module = modulesMap[id];
var dep, i, subdep;
// initialize id's waitingMap
for (i = 0; i < module.dependencies.length; i++) {
dep = module.dependencies[i];
if (!modulesMap[dep]) {
_addDependency(module, dep);
} else if (modulesMap[dep].waiting) {
for (subdep in modulesMap[dep].waitingMap) {
if (modulesMap[dep].waitingMap[subdep]) {
_addDependency(module, subdep);
}
}
}
}
if (module.waiting === 0 && module.special & REQUIRE_WHEN_READY) {
modulesToRequire.push(id);
}
// update modules depending on id
if (dependencyMap[id]) {
var deps = dependencyMap[id];
var submodule;
dependencyMap[id] = undefined;
for (dep in deps) {
submodule = modulesMap[dep];
// add all deps of id
for (subdep in module.waitingMap) {
if (module.waitingMap[subdep]) {
_addDependency(submodule, subdep);
}
}
// remove id itself
if (submodule.waitingMap[id]) {
submodule.waitingMap[id] = undefined;
submodule.waiting--;
}
if (submodule.waiting === 0 &&
submodule.special & REQUIRE_WHEN_READY) {
modulesToRequire.push(dep);
}
}
}
// run everything that's ready
for (i = 0; i < modulesToRequire.length; i++) {
require.call(null, modulesToRequire[i]);
}
}
function _register(id, exports) {
var module = modulesMap[id] = { id: id };
module.exports = exports;
module.refcount = 0;
}
// pseudo name used in common-require
// see require() function for more info
_register('module', 0);
_register('exports', 0);
_register('global', global);
_register('require', require);
global.require = require; global.require = require;
require.__debug = {
modules: modulesMap,
deps: dependencyMap,
printDependencyInfo: function() {
if (!global.console) {
return;
}
var names = Object.keys(require.__debug.deps);
global.console.log(_debugUnresolvedDependencies(names));
}
};
/**
* All @providesModule files are wrapped by this function by makehaste. It
* is a convenience function around define() that prepends a bunch of required
* modules (global, require, module, etc) so that we don't have to spit that
* out for every module which would be a lot of extra bytes.
*/
global.__d = function(id, deps, factory, _special, _inlineRequires) {
var defaultDeps = ['global', 'require', 'module', 'exports'];
define(id, defaultDeps.concat(deps), factory, _special || USED_AS_TRANSPORT,
null, null, _inlineRequires);
};
})(this); })(this);