Improve constant inlining, add `process.platform`
Reviewed By: bestander Differential Revision: D3235716 fb-gh-sync-id: f9019ec0042827e409fa84ba74f4c426ccad1519 fbshipit-source-id: f9019ec0042827e409fa84ba74f4c426ccad1519
This commit is contained in:
parent
4e05d00f0d
commit
e6bafca39e
|
@ -81,7 +81,7 @@ function polyfillLazyGlobal(name, valueFn, scope = GLOBAL) {
|
|||
configurable: true,
|
||||
enumerable: true,
|
||||
get() {
|
||||
return this[name] = valueFn();
|
||||
return (this[name] = valueFn());
|
||||
},
|
||||
set(value) {
|
||||
Object.defineProperty(this, name, {
|
||||
|
@ -199,12 +199,14 @@ function setUpProfile() {
|
|||
}
|
||||
}
|
||||
|
||||
function setUpProcessEnv() {
|
||||
function setUpProcess() {
|
||||
GLOBAL.process = GLOBAL.process || {};
|
||||
GLOBAL.process.env = GLOBAL.process.env || {};
|
||||
if (!GLOBAL.process.env.NODE_ENV) {
|
||||
GLOBAL.process.env.NODE_ENV = __DEV__ ? 'development' : 'production';
|
||||
}
|
||||
|
||||
polyfillLazyGlobal('platform', () => require('Platform').OS, GLOBAL.process);
|
||||
}
|
||||
|
||||
function setUpDevTools() {
|
||||
|
@ -217,7 +219,7 @@ function setUpDevTools() {
|
|||
}
|
||||
}
|
||||
|
||||
setUpProcessEnv();
|
||||
setUpProcess();
|
||||
setUpConsole();
|
||||
setUpTimers();
|
||||
setUpAlert();
|
||||
|
|
|
@ -35,7 +35,7 @@ describe('inline constants', () => {
|
|||
var a = __DEV__ ? 1 : 2;
|
||||
var b = a.__DEV__;
|
||||
var c = function __DEV__(__DEV__) {};
|
||||
}`
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {dev: true});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/__DEV__/, 'true')));
|
||||
});
|
||||
|
@ -44,7 +44,7 @@ describe('inline constants', () => {
|
|||
const code = `function a() {
|
||||
var a = Platform.OS;
|
||||
var b = a.Platform.OS;
|
||||
}`
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.OS/, '"ios"')));
|
||||
});
|
||||
|
@ -55,7 +55,18 @@ describe('inline constants', () => {
|
|||
function a() {
|
||||
if (Platform.OS === 'android') a = function() {};
|
||||
var b = a.Platform.OS;
|
||||
}`
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.OS/, '"ios"')));
|
||||
});
|
||||
|
||||
it('replaces Platform.OS in the code if Platform is a top level import from react-native', () => {
|
||||
const code = `
|
||||
var Platform = require('react-native').Platform;
|
||||
function a() {
|
||||
if (Platform.OS === 'android') a = function() {};
|
||||
var b = a.Platform.OS;
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.OS/, '"ios"')));
|
||||
});
|
||||
|
@ -64,7 +75,7 @@ describe('inline constants', () => {
|
|||
const code = `function a() {
|
||||
var a = require('Platform').OS;
|
||||
var b = a.require('Platform').OS;
|
||||
}`
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
|
||||
expect(toString(ast)).toEqual(
|
||||
normalize(code.replace(/require\('Platform'\)\.OS/, '"android"')));
|
||||
|
@ -74,18 +85,27 @@ describe('inline constants', () => {
|
|||
const code = `function a() {
|
||||
var a = React.Platform.OS;
|
||||
var b = a.React.Platform.OS;
|
||||
}`
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/React\.Platform\.OS/, '"ios"')));
|
||||
});
|
||||
|
||||
it('replaces ReactNative.Platform.OS in the code if ReactNative is a global', () => {
|
||||
const code = `function a() {
|
||||
var a = ReactNative.Platform.OS;
|
||||
var b = a.ReactNative.Platform.OS;
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/ReactNative\.Platform\.OS/, '"ios"')));
|
||||
});
|
||||
|
||||
it('replaces React.Platform.OS in the code if React is a top level import', () => {
|
||||
const code = `
|
||||
var React = require('React');
|
||||
function a() {
|
||||
if (React.Platform.OS === 'android') a = function() {};
|
||||
var b = a.React.Platform.OS;
|
||||
}`
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/React.Platform\.OS/, '"ios"')));
|
||||
});
|
||||
|
@ -94,19 +114,40 @@ describe('inline constants', () => {
|
|||
const code = `function a() {
|
||||
var a = require('React').Platform.OS;
|
||||
var b = a.require('React').Platform.OS;
|
||||
}`
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
|
||||
expect(toString(ast)).toEqual(
|
||||
normalize(code.replace(/require\('React'\)\.Platform\.OS/, '"android"')));
|
||||
});
|
||||
|
||||
it('replaces ReactNative.Platform.OS in the code if ReactNative is a top level import', () => {
|
||||
const code = `
|
||||
var ReactNative = require('react-native');
|
||||
function a() {
|
||||
if (ReactNative.Platform.OS === 'android') a = function() {};
|
||||
var b = a.ReactNative.Platform.OS;
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
|
||||
expect(toString(ast)).toEqual(normalize(code.replace(/ReactNative.Platform\.OS/, '"android"')));
|
||||
});
|
||||
|
||||
it('replaces require("react-native").Platform.OS in the code', () => {
|
||||
const code = `function a() {
|
||||
var a = require('react-native').Platform.OS;
|
||||
var b = a.require('react-native').Platform.OS;
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
|
||||
expect(toString(ast)).toEqual(
|
||||
normalize(code.replace(/require\('react-native'\)\.Platform\.OS/, '"android"')));
|
||||
});
|
||||
|
||||
it('replaces process.env.NODE_ENV in the code', () => {
|
||||
const code = `function a() {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return require('Prod');
|
||||
}
|
||||
return require('Dev');
|
||||
}`
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {dev: false});
|
||||
expect(toString(ast)).toEqual(
|
||||
normalize(code.replace(/process\.env\.NODE_ENV/, '"production"')));
|
||||
|
@ -118,16 +159,28 @@ describe('inline constants', () => {
|
|||
return require('Prod');
|
||||
}
|
||||
return require('Dev');
|
||||
}`
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {dev: true});
|
||||
expect(toString(ast)).toEqual(
|
||||
normalize(code.replace(/process\.env\.NODE_ENV/, '"development"')));
|
||||
});
|
||||
|
||||
it('replaces process.platform in the code', () => {
|
||||
const code = `function a() {
|
||||
if (process.platform === 'android') {
|
||||
return require('./android');
|
||||
}
|
||||
return require('./ios');
|
||||
}`;
|
||||
const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
|
||||
expect(toString(ast)).toEqual(
|
||||
normalize(code.replace(/process\.platform\b/, '"ios"')));
|
||||
});
|
||||
|
||||
it('accepts an AST as input', function() {
|
||||
const code = `function ifDev(a,b){return __DEV__?a:b;}`;
|
||||
const code = 'function ifDev(a,b){return __DEV__?a:b;}';
|
||||
const {ast} = inline('arbitrary.hs', {ast: toAst(code)}, {dev: false});
|
||||
expect(toString(ast)).toEqual(code.replace(/__DEV__/, 'false'))
|
||||
expect(toString(ast)).toEqual(code.replace(/__DEV__/, 'false'));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
const babel = require('babel-core');
|
||||
const t = babel.types;
|
||||
|
||||
const react = {name: 'React'};
|
||||
const React = {name: 'React'};
|
||||
const ReactNative = {name: 'ReactNative'};
|
||||
const platform = {name: 'Platform'};
|
||||
const os = {name: 'OS'};
|
||||
const requirePattern = {name: 'require'};
|
||||
|
@ -19,9 +20,12 @@ const requirePattern = {name: 'require'};
|
|||
const env = {name: 'env'};
|
||||
const nodeEnv = {name: 'NODE_ENV'};
|
||||
const processId = {name: 'process'};
|
||||
const platformId = {name: 'platform'};
|
||||
|
||||
const dev = {name: '__DEV__'};
|
||||
|
||||
const importMap = new Map([['ReactNative', 'react-native']]);
|
||||
|
||||
const isGlobal = (binding) => !binding;
|
||||
|
||||
const isToplevelBinding = (binding) => isGlobal(binding) || !binding.scope.parent;
|
||||
|
@ -31,20 +35,27 @@ const isRequireCall = (node, dependencyId, scope) =>
|
|||
t.isIdentifier(node.callee, requirePattern) &&
|
||||
t.isStringLiteral(node.arguments[0], t.stringLiteral(dependencyId));
|
||||
|
||||
const isImport = (node, scope, pattern) =>
|
||||
t.isIdentifier(node, pattern) &&
|
||||
isToplevelBinding(scope.getBinding(pattern.name)) ||
|
||||
isRequireCall(node, pattern.name, scope);
|
||||
const isImport = (node, scope, patterns) =>
|
||||
patterns.some(pattern => {
|
||||
const importName = importMap.get(pattern.name) || pattern.name;
|
||||
return isRequireCall(node, importName, scope);
|
||||
});
|
||||
|
||||
function isImportOrGlobal(node, scope, patterns) {
|
||||
const identifier = patterns.find(pattern => t.isIdentifier(node, pattern));
|
||||
return identifier && isToplevelBinding(scope.getBinding(identifier.name)) ||
|
||||
isImport(node, scope, patterns);
|
||||
}
|
||||
|
||||
const isPlatformOS = (node, scope) =>
|
||||
t.isIdentifier(node.property, os) &&
|
||||
isImport(node.object, scope, platform);
|
||||
isImportOrGlobal(node.object, scope, [platform]);
|
||||
|
||||
const isReactPlatformOS = (node, scope) =>
|
||||
t.isIdentifier(node.property, os) &&
|
||||
t.isMemberExpression(node.object) &&
|
||||
t.isIdentifier(node.object.property, platform) &&
|
||||
isImport(node.object.object, scope, react);
|
||||
isImportOrGlobal(node.object.object, scope, [React, ReactNative]);
|
||||
|
||||
const isProcessEnvNodeEnv = (node, scope) =>
|
||||
t.isIdentifier(node.property, nodeEnv) &&
|
||||
|
@ -53,6 +64,11 @@ const isProcessEnvNodeEnv = (node, scope) =>
|
|||
t.isIdentifier(node.object.object, processId) &&
|
||||
isGlobal(scope.getBinding(processId.name));
|
||||
|
||||
const isProcessPlatform = (node, scope) =>
|
||||
t.isIdentifier(node.property, platformId) &&
|
||||
t.isIdentifier(node.object, processId) &&
|
||||
isGlobal(scope.getBinding(processId.name));
|
||||
|
||||
const isDev = (node, parent, scope) =>
|
||||
t.isIdentifier(node, dev) &&
|
||||
isGlobal(scope.getBinding(dev.name)) &&
|
||||
|
@ -71,11 +87,12 @@ const inlinePlugin = {
|
|||
|
||||
if (isPlatformOS(node, scope) || isReactPlatformOS(node, scope)) {
|
||||
path.replaceWith(t.stringLiteral(state.opts.platform));
|
||||
}
|
||||
|
||||
if(isProcessEnvNodeEnv(node, scope)) {
|
||||
} else if (isProcessEnvNodeEnv(node, scope)) {
|
||||
path.replaceWith(
|
||||
t.stringLiteral(state.opts.dev ? 'development' : 'production'));
|
||||
} else if (isProcessPlatform(node, scope)) {
|
||||
path.replaceWith(
|
||||
t.stringLiteral(state.opts.platform));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue