Skip to content

Commit

Permalink
Make the packager work with babel strict mode transform
Browse files Browse the repository at this point in the history
At the moment we have to disable strict mode for the
transform-es2015-modules-commonjs because strict mode leaks to the global
scope and breaks the bridge. It was due to the way the polyfills were bundled in the package. To fix it, I wrapped the polyfill modules in an IIFE. Then when strict mode was enabled some polyfills were broken due to strict mode errors so that was fixed too. Also removed the IIFE from the polyfills that included one.
  • Loading branch information
janicduplessis committed Jan 20, 2016
1 parent 4f37fe6 commit 9701013
Show file tree
Hide file tree
Showing 15 changed files with 955 additions and 942 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
require('regenerator/runtime');

if (typeof GLOBAL === 'undefined') {
GLOBAL = this;
global.GLOBAL = this;
}

if (typeof window === 'undefined') {
window = GLOBAL;
global.window = GLOBAL;
}

function setUpConsole() {
Expand Down Expand Up @@ -70,6 +70,15 @@ function polyfillGlobal(name, newValue, scope = GLOBAL) {
Object.defineProperty(scope, name, {...descriptor, value: newValue});
}

/**
* Polyfill a module if it is not already defined in `scope`.
*/
function polyfillIfNeeded(name, polyfill, scope = GLOBAL) {
if (typeof scope[name] === 'undefined') {
Object.defineProperty(scope, name, {value: polyfill});
}
}

function setUpErrorHandler() {
if (global.__fbDisableExceptionsManager) {
return;
Expand All @@ -78,7 +87,7 @@ function setUpErrorHandler() {
function handleError(e, isFatal) {
try {
require('ExceptionsManager').handleException(e, isFatal);
} catch(ee) {
} catch (ee) {
console.log('Failed to print error: ', ee.message);
}
}
Expand Down Expand Up @@ -146,7 +155,7 @@ function setUpXHR() {
}

function setUpGeolocation() {
GLOBAL.navigator = GLOBAL.navigator || {};
polyfillIfNeeded('navigator', {});
polyfillGlobal('geolocation', require('Geolocation'), GLOBAL.navigator);
}

Expand Down Expand Up @@ -175,9 +184,9 @@ function setUpProcessEnv() {
}

function setUpNumber() {
Number.EPSILON = Number.EPSILON || Math.pow(2, -52);
Number.MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1;
Number.MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER || -(Math.pow(2, 53) - 1);
polyfillIfNeeded('EPSILON', Math.pow(2, -52), Number);
polyfillIfNeeded('MAX_SAFE_INTEGER', Math.pow(2, 53) - 1, Number);
polyfillIfNeeded('MIN_SAFE_INTEGER', -(Math.pow(2, 53) - 1), Number);
}

function setUpDevTools() {
Expand Down
58 changes: 28 additions & 30 deletions Libraries/JavaScriptAppEngine/polyfills/document.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
/* eslint global-strict: 0 */
(function(GLOBAL) {
/**
* The document must be shimmed before anything else that might define the
* `ExecutionEnvironment` module (which checks for `document.createElement`).
*/
/* eslint strict: 0 */
/**
* The document must be shimmed before anything else that might define the
* `ExecutionEnvironment` module (which checks for `document.createElement`).
*/

// The browser defines Text and Image globals by default. If you forget to
// require them, then the error message is very confusing.
function getInvalidGlobalUseError(name) {
return new Error(
'You are trying to render the global ' + name + ' variable as a ' +
'React element. You probably forgot to require ' + name + '.'
);
// The browser defines Text and Image globals by default. If you forget to
// require them, then the error message is very confusing.
function getInvalidGlobalUseError(name) {
return new Error(
'You are trying to render the global ' + name + ' variable as a ' +
'React element. You probably forgot to require ' + name + '.'
);
}
global.Text = {
get defaultProps() {
throw getInvalidGlobalUseError('Text');
}
GLOBAL.Text = {
get defaultProps() {
throw getInvalidGlobalUseError('Text');
}
};
GLOBAL.Image = {
get defaultProps() {
throw getInvalidGlobalUseError('Image');
}
};
// Force `ExecutionEnvironment.canUseDOM` to be false.
if (GLOBAL.document) {
GLOBAL.document.createElement = null;
};
global.Image = {
get defaultProps() {
throw getInvalidGlobalUseError('Image');
}
};
// Force `ExecutionEnvironment.canUseDOM` to be false.
if (global.document) {
global.document.createElement = null;
}

// There is no DOM so MutationObserver doesn't make sense. It is used
// as feature detection in Bluebird Promise implementation
GLOBAL.MutationObserver = undefined;
})(this);
// There is no DOM so MutationObserver doesn't make sense. It is used
// as feature detection in Bluebird Promise implementation
global.MutationObserver = undefined;
3 changes: 2 additions & 1 deletion Libraries/vendor/emitter/mixInEventEmitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ var TYPES_KEY = keyOf({__types: true});
*/
function mixInEventEmitter(klass, types) {
invariant(types, 'Must supply set of valid event types');
invariant(!this.__eventEmitter, 'An active emitter is already mixed in');

// If this is a constructor, write to the prototype, otherwise write to the
// singleton object.
var target = klass.prototype || klass;

invariant(!target.__eventEmitter, 'An active emitter is already mixed in');

var ctor = klass.constructor;
if (ctor) {
invariant(
Expand Down
29 changes: 29 additions & 0 deletions packager/react-packager/src/Resolver/__tests__/Resolver-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ describe('Resolver', function() {
return module;
}

function createPolyfill(id, dependencies) {
var polyfill = new Polyfill({});
polyfill.getName.mockImpl(() => Promise.resolve(id));
polyfill.getDependencies.mockImpl(() => Promise.resolve(dependencies));
polyfill.isPolyfill.mockReturnValue(true);
return polyfill;
}

describe('getDependencies', function() {
pit('should get dependencies with polyfills', function() {
var module = createModule('index');
Expand Down Expand Up @@ -1020,5 +1028,26 @@ describe('Resolver', function() {
].join('\n'));
});
});

pit('should resolve polyfills', function () {
const depResolver = new Resolver({
projectRoot: '/root',
});
const polyfill = createPolyfill('test polyfill', []);
const code = [
'global.fetch = () => 1;',
].join('\n');
return depResolver.wrapModule(
null,
polyfill,
code
).then(processedCode => {
expect(processedCode.code).toEqual([
'(function(global) {',
' global.fetch = () => 1;',
"})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);",
].join('\n'));
});
});
});
});
12 changes: 11 additions & 1 deletion packager/react-packager/src/Resolver/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,9 @@ class Resolver {

wrapModule(resolutionResponse, module, code) {
if (module.isPolyfill()) {
return Promise.resolve({code});
return Promise.resolve({
code: definePolyfillCode(code),
});
}

return this.resolveRequires(resolutionResponse, module, code).then(
Expand All @@ -239,4 +241,12 @@ function defineModuleCode(moduleName, code) {
].join('');
}

function definePolyfillCode(code) {
return [
'(function(global) {\n',
` ${code}`,
`\n})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);`,
].join('');
}

module.exports = Resolver;
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,51 @@
* @polyfill
*/

/*eslint-disable */
/*jslint bitwise: true */
/* eslint-disable */

(function(undefined) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
function findIndex(predicate, context) {
if (this == null) {
throw new TypeError(
'Array.prototype.findIndex called on null or undefined'
);
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
for (var i = 0; i < length; i++) {
if (predicate.call(context, list[i], i, list)) {
return i;
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
function findIndex(predicate, context) {
if (this == null) {
throw new TypeError(
'Array.prototype.findIndex called on null or undefined'
);
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
for (var i = 0; i < length; i++) {
if (predicate.call(context, list[i], i, list)) {
return i;
}
return -1;
}
return -1;
}

if (!Array.prototype.findIndex) {
Object.defineProperty(Array.prototype, 'findIndex', {
enumerable: false,
writable: true,
configurable: true,
value: findIndex
});
}
if (!Array.prototype.findIndex) {
Object.defineProperty(Array.prototype, 'findIndex', {
enumerable: false,
writable: true,
configurable: true,
value: findIndex
});
}

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
enumerable: false,
writable: true,
configurable: true,
value: function(predicate, context) {
if (this == null) {
throw new TypeError(
'Array.prototype.find called on null or undefined'
);
}
var index = findIndex.call(this, predicate, context);
return index === -1 ? undefined : this[index];
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
enumerable: false,
writable: true,
configurable: true,
value: function(predicate, context) {
if (this == null) {
throw new TypeError(
'Array.prototype.find called on null or undefined'
);
}
});
}
})();
var index = findIndex.call(this, predicate, context);
return index === -1 ? undefined : this[index];
}
});
}
Loading

0 comments on commit 9701013

Please sign in to comment.