mirror of
https://github.com/status-im/metro.git
synced 2025-01-14 04:54:27 +00:00
Let the inline plugin use the babel types from arg
Summary: Before the inline plugin was explicitly requiring babel itself. With the babel upgrade path that's a problem since it will try to pull in babel 6 even when we want babel 7 (because it's a different package name). To remedy this the plugin is now a function which will use the `types` api from the given context rather than the required global. I also moved out the `inline` function that only seems to be used in tests. They're now just living in the tests. Had to add some flow annotations to generic objects since Flow was complaining about missing types and that would require adding the full babel api which is outside of the scope of this task. Reviewed By: jeanlauliac Differential Revision: D7083815 fbshipit-source-id: 59b8365d8c3c3dc00b23a3735037dcc9483c0b2c
This commit is contained in:
parent
8292958c00
commit
56e7aed7cb
@ -9,18 +9,52 @@
|
|||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const inline = require('../inline');
|
const inlinePlugin = require('../inline-plugin');
|
||||||
|
const invariant = require('fbjs/lib/invariant');
|
||||||
|
|
||||||
const {transformSync} = require('../../../babel-bridge');
|
const {transformSync} = require('../../../babel-bridge');
|
||||||
const {transformFromAstSync} = require('../../../babel-bridge');
|
const {transformFromAstSync} = require('../../../babel-bridge');
|
||||||
|
|
||||||
import type {TransformResult} from '@babel/core';
|
import type {TransformResult} from '@babel/core';
|
||||||
|
import type {Ast} from 'babel-core';
|
||||||
|
import type {BabelSourceMap} from 'babel-core';
|
||||||
|
|
||||||
const babelOptions = {
|
const babelOptions = {
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
compact: true,
|
compact: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type AstResult = {
|
||||||
|
ast: Ast,
|
||||||
|
code: ?string,
|
||||||
|
map: ?BabelSourceMap,
|
||||||
|
};
|
||||||
|
|
||||||
|
function inline(
|
||||||
|
filename: string,
|
||||||
|
transformResult: {ast?: ?Ast, code: string, map: ?BabelSourceMap},
|
||||||
|
options: {+dev: boolean, +platform: ?string},
|
||||||
|
): AstResult {
|
||||||
|
const code = transformResult.code;
|
||||||
|
const babelOptions = {
|
||||||
|
filename,
|
||||||
|
plugins: [[inlinePlugin, options]],
|
||||||
|
inputSourceMap: transformResult.map,
|
||||||
|
sourceMaps: true,
|
||||||
|
sourceFileName: filename,
|
||||||
|
code: false,
|
||||||
|
babelrc: false,
|
||||||
|
compact: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = transformResult.ast
|
||||||
|
? transformFromAstSync(transformResult.ast, code, babelOptions)
|
||||||
|
: transformSync(code, babelOptions);
|
||||||
|
const {ast} = result;
|
||||||
|
invariant(ast != null, 'Missing AST in babel transform results.');
|
||||||
|
return {ast, code: result.code, map: result.map};
|
||||||
|
}
|
||||||
|
|
||||||
function toString(ast): string {
|
function toString(ast): string {
|
||||||
return normalize(transformFromAstSync(ast, babelOptions).code);
|
return normalize(transformFromAstSync(ast, babelOptions).code);
|
||||||
}
|
}
|
||||||
@ -475,7 +509,7 @@ describe('inline constants', () => {
|
|||||||
|
|
||||||
const transformed = transformSync(code, {
|
const transformed = transformSync(code, {
|
||||||
...babelOptions,
|
...babelOptions,
|
||||||
plugins: [stripFlow, [inline.plugin, {dev: false}]],
|
plugins: [stripFlow, [inlinePlugin, {dev: false}]],
|
||||||
}).code;
|
}).code;
|
||||||
|
|
||||||
expect(transformed).toEqual('const a=false;');
|
expect(transformed).toEqual('const a=false;');
|
||||||
@ -490,7 +524,7 @@ describe('inline constants', () => {
|
|||||||
|
|
||||||
const transformed = transformSync(code, {
|
const transformed = transformSync(code, {
|
||||||
...babelOptions,
|
...babelOptions,
|
||||||
plugins: [stripFlow, [inline.plugin, {dev: true}]],
|
plugins: [stripFlow, [inlinePlugin, {dev: true}]],
|
||||||
}).code;
|
}).code;
|
||||||
|
|
||||||
expect(transformed).toEqual('__d(()=>{const a=true;});');
|
expect(transformed).toEqual('__d(()=>{const a=true;});');
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
jest
|
jest
|
||||||
.mock('../constant-folding')
|
.mock('../constant-folding')
|
||||||
.mock('../inline')
|
.mock('../inline-plugin')
|
||||||
.mock('metro-minify-uglify');
|
.mock('metro-minify-uglify');
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
@ -16,7 +16,7 @@ const assetTransformer = require('../../assetTransformer');
|
|||||||
const collectDependencies = require('../../ModuleGraph/worker/collectDependencies');
|
const collectDependencies = require('../../ModuleGraph/worker/collectDependencies');
|
||||||
const constantFolding = require('./constant-folding');
|
const constantFolding = require('./constant-folding');
|
||||||
const getMinifier = require('../../lib/getMinifier');
|
const getMinifier = require('../../lib/getMinifier');
|
||||||
const inline = require('./inline');
|
const inlinePlugin = require('./inline-plugin');
|
||||||
const optimizeDependencies = require('../../ModuleGraph/worker/optimizeDependencies');
|
const optimizeDependencies = require('../../ModuleGraph/worker/optimizeDependencies');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
@ -231,9 +231,9 @@ function transformCode(
|
|||||||
|
|
||||||
const plugins = options.dev
|
const plugins = options.dev
|
||||||
? []
|
? []
|
||||||
: [[inline.plugin, options], [constantFolding.plugin, options]];
|
: [[inlinePlugin, options], [constantFolding.plugin, options]];
|
||||||
|
|
||||||
// $FlowFixMe: impossible to type a dynamic require.
|
// $FlowFixMe TODO t26372934 Plugin system
|
||||||
const transformer: Transformer<*> = require(transformerPath);
|
const transformer: Transformer<*> = require(transformerPath);
|
||||||
|
|
||||||
const transformerArgs = {
|
const transformerArgs = {
|
||||||
|
@ -10,138 +10,153 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const {babelTypes: t} = require('../../babel-bridge');
|
import typeof {types as BabelTypes} from 'babel-core';
|
||||||
|
|
||||||
const importMap = new Map([['ReactNative', 'react-native']]);
|
const importMap = new Map([['ReactNative', 'react-native']]);
|
||||||
|
|
||||||
const isPlatformNode = (
|
function createInlinePlatformChecks(t: BabelTypes) {
|
||||||
node: Object,
|
const isPlatformNode = (
|
||||||
scope: Object,
|
node: Object,
|
||||||
isWrappedModule: boolean,
|
scope: Object,
|
||||||
) =>
|
isWrappedModule: boolean,
|
||||||
isPlatformOS(node, scope, isWrappedModule) ||
|
) =>
|
||||||
isReactPlatformOS(node, scope, isWrappedModule) ||
|
isPlatformOS(node, scope, isWrappedModule) ||
|
||||||
isPlatformOSOS(node, scope, isWrappedModule);
|
isReactPlatformOS(node, scope, isWrappedModule) ||
|
||||||
|
isPlatformOSOS(node, scope, isWrappedModule);
|
||||||
|
|
||||||
const isPlatformSelectNode = (
|
const isPlatformSelectNode = (
|
||||||
node: Object,
|
node: Object,
|
||||||
scope: Object,
|
scope: Object,
|
||||||
isWrappedModule: boolean,
|
isWrappedModule: boolean,
|
||||||
) =>
|
) =>
|
||||||
isPlatformSelect(node, scope, isWrappedModule) ||
|
isPlatformSelect(node, scope, isWrappedModule) ||
|
||||||
isReactPlatformSelect(node, scope, isWrappedModule);
|
isReactPlatformSelect(node, scope, isWrappedModule);
|
||||||
|
|
||||||
const isPlatformOS = (node, scope, isWrappedModule) =>
|
const isPlatformOS = (node, scope, isWrappedModule) =>
|
||||||
t.isIdentifier(node.property, {name: 'OS'}) &&
|
t.isIdentifier(node.property, {name: 'OS'}) &&
|
||||||
isImportOrGlobal(node.object, scope, [{name: 'Platform'}], isWrappedModule);
|
isImportOrGlobal(node.object, scope, [{name: 'Platform'}], isWrappedModule);
|
||||||
|
|
||||||
const isReactPlatformOS = (node, scope, isWrappedModule) =>
|
const isReactPlatformOS = (node, scope, isWrappedModule) =>
|
||||||
t.isIdentifier(node.property, {name: 'OS'}) &&
|
t.isIdentifier(node.property, {name: 'OS'}) &&
|
||||||
t.isMemberExpression(node.object) &&
|
t.isMemberExpression(node.object) &&
|
||||||
t.isIdentifier(node.object.property, {name: 'Platform'}) &&
|
t.isIdentifier(node.object.property, {name: 'Platform'}) &&
|
||||||
isImportOrGlobal(
|
isImportOrGlobal(
|
||||||
node.object.object,
|
node.object.object,
|
||||||
scope,
|
scope,
|
||||||
[{name: 'React'}, {name: 'ReactNative'}],
|
[{name: 'React'}, {name: 'ReactNative'}],
|
||||||
isWrappedModule,
|
isWrappedModule,
|
||||||
);
|
|
||||||
|
|
||||||
const isPlatformOSOS = (node, scope, isWrappedModule) =>
|
|
||||||
t.isIdentifier(node.property, {name: 'OS'}) &&
|
|
||||||
isImportOrGlobal(node.object, scope, [{name: 'PlatformOS'}], isWrappedModule);
|
|
||||||
|
|
||||||
const isPlatformSelect = (node, scope, isWrappedModule) =>
|
|
||||||
t.isMemberExpression(node.callee) &&
|
|
||||||
t.isIdentifier(node.callee.object, {name: 'Platform'}) &&
|
|
||||||
t.isIdentifier(node.callee.property, {name: 'select'}) &&
|
|
||||||
isImportOrGlobal(
|
|
||||||
node.callee.object,
|
|
||||||
scope,
|
|
||||||
[{name: 'Platform'}],
|
|
||||||
isWrappedModule,
|
|
||||||
);
|
|
||||||
|
|
||||||
const isReactPlatformSelect = (node, scope, isWrappedModule) =>
|
|
||||||
t.isMemberExpression(node.callee) &&
|
|
||||||
t.isIdentifier(node.callee.property, {name: 'select'}) &&
|
|
||||||
t.isMemberExpression(node.callee.object) &&
|
|
||||||
t.isIdentifier(node.callee.object.property, {name: 'Platform'}) &&
|
|
||||||
isImportOrGlobal(
|
|
||||||
node.callee.object.object,
|
|
||||||
scope,
|
|
||||||
[{name: 'React'}, {name: 'ReactNative'}],
|
|
||||||
isWrappedModule,
|
|
||||||
);
|
|
||||||
|
|
||||||
const isPlatformOSSelect = (
|
|
||||||
node: Object,
|
|
||||||
scope: Object,
|
|
||||||
isWrappedModule: boolean,
|
|
||||||
) =>
|
|
||||||
t.isMemberExpression(node.callee) &&
|
|
||||||
t.isIdentifier(node.callee.object, {name: 'PlatformOS'}) &&
|
|
||||||
t.isIdentifier(node.callee.property, {name: 'select'}) &&
|
|
||||||
isImportOrGlobal(
|
|
||||||
node.callee.object,
|
|
||||||
scope,
|
|
||||||
[{name: 'PlatformOS'}],
|
|
||||||
isWrappedModule,
|
|
||||||
);
|
|
||||||
|
|
||||||
const getReplacementForPlatformOSSelect = (node: Object, platform: string) => {
|
|
||||||
const matchingProperty = node.arguments[0].properties.find(
|
|
||||||
p => p.key.name === platform,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!matchingProperty) {
|
|
||||||
throw new Error(
|
|
||||||
'No matching property was found for PlatformOS.select:\n' +
|
|
||||||
JSON.stringify(node),
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return matchingProperty.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isGlobal = binding => !binding;
|
const isPlatformOSOS = (node, scope, isWrappedModule) =>
|
||||||
|
t.isIdentifier(node.property, {name: 'OS'}) &&
|
||||||
|
isImportOrGlobal(
|
||||||
|
node.object,
|
||||||
|
scope,
|
||||||
|
[{name: 'PlatformOS'}],
|
||||||
|
isWrappedModule,
|
||||||
|
);
|
||||||
|
|
||||||
const isRequireCall = (node, dependencyId, scope) =>
|
const isPlatformSelect = (node, scope, isWrappedModule) =>
|
||||||
t.isCallExpression(node) &&
|
t.isMemberExpression(node.callee) &&
|
||||||
t.isIdentifier(node.callee, {name: 'require'}) &&
|
t.isIdentifier(node.callee.object, {name: 'Platform'}) &&
|
||||||
checkRequireArgs(node.arguments, dependencyId);
|
t.isIdentifier(node.callee.property, {name: 'select'}) &&
|
||||||
|
isImportOrGlobal(
|
||||||
|
node.callee.object,
|
||||||
|
scope,
|
||||||
|
[{name: 'Platform'}],
|
||||||
|
isWrappedModule,
|
||||||
|
);
|
||||||
|
|
||||||
const isImport = (node, scope, patterns) =>
|
const isReactPlatformSelect = (node, scope, isWrappedModule) =>
|
||||||
patterns.some(pattern => {
|
t.isMemberExpression(node.callee) &&
|
||||||
const importName = importMap.get(pattern.name) || pattern.name;
|
t.isIdentifier(node.callee.property, {name: 'select'}) &&
|
||||||
return isRequireCall(node, importName, scope);
|
t.isMemberExpression(node.callee.object) &&
|
||||||
});
|
t.isIdentifier(node.callee.object.property, {name: 'Platform'}) &&
|
||||||
|
isImportOrGlobal(
|
||||||
|
node.callee.object.object,
|
||||||
|
scope,
|
||||||
|
[{name: 'React'}, {name: 'ReactNative'}],
|
||||||
|
isWrappedModule,
|
||||||
|
);
|
||||||
|
|
||||||
const isImportOrGlobal = (node, scope, patterns, isWrappedModule) => {
|
const isPlatformOSSelect = (
|
||||||
const identifier = patterns.find(pattern => t.isIdentifier(node, pattern));
|
node: Object,
|
||||||
return (
|
scope: Object,
|
||||||
(identifier &&
|
isWrappedModule: boolean,
|
||||||
isToplevelBinding(scope.getBinding(identifier.name), isWrappedModule)) ||
|
) =>
|
||||||
isImport(node, scope, patterns)
|
t.isMemberExpression(node.callee) &&
|
||||||
);
|
t.isIdentifier(node.callee.object, {name: 'PlatformOS'}) &&
|
||||||
};
|
t.isIdentifier(node.callee.property, {name: 'select'}) &&
|
||||||
|
isImportOrGlobal(
|
||||||
|
node.callee.object,
|
||||||
|
scope,
|
||||||
|
[{name: 'PlatformOS'}],
|
||||||
|
isWrappedModule,
|
||||||
|
);
|
||||||
|
|
||||||
const checkRequireArgs = (args, dependencyId) => {
|
const getReplacementForPlatformOSSelect = (
|
||||||
const pattern = t.stringLiteral(dependencyId);
|
node: Object,
|
||||||
return (
|
platform: string,
|
||||||
t.isStringLiteral(args[0], pattern) ||
|
) => {
|
||||||
(t.isMemberExpression(args[0]) &&
|
const matchingProperty = node.arguments[0].properties.find(
|
||||||
t.isNumericLiteral(args[0].property) &&
|
p => p.key.name === platform,
|
||||||
t.isStringLiteral(args[1], pattern))
|
);
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const isToplevelBinding = (binding, isWrappedModule) =>
|
if (!matchingProperty) {
|
||||||
isGlobal(binding) ||
|
throw new Error(
|
||||||
!binding.scope.parent ||
|
'No matching property was found for PlatformOS.select:\n' +
|
||||||
(isWrappedModule && !binding.scope.parent.parent);
|
JSON.stringify(node),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return matchingProperty.value;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
const isGlobal = binding => !binding;
|
||||||
isPlatformNode,
|
|
||||||
isPlatformSelectNode,
|
const isRequireCall = (node, dependencyId, scope) =>
|
||||||
isPlatformOSSelect,
|
t.isCallExpression(node) &&
|
||||||
getReplacementForPlatformOSSelect,
|
t.isIdentifier(node.callee, {name: 'require'}) &&
|
||||||
};
|
checkRequireArgs(node.arguments, dependencyId);
|
||||||
|
|
||||||
|
const isImport = (node, scope, patterns) =>
|
||||||
|
patterns.some(pattern => {
|
||||||
|
const importName = importMap.get(pattern.name) || pattern.name;
|
||||||
|
return isRequireCall(node, importName, scope);
|
||||||
|
});
|
||||||
|
|
||||||
|
const isImportOrGlobal = (node, scope, patterns, isWrappedModule) => {
|
||||||
|
const identifier = patterns.find(pattern => t.isIdentifier(node, pattern));
|
||||||
|
return (
|
||||||
|
(identifier &&
|
||||||
|
isToplevelBinding(
|
||||||
|
scope.getBinding(identifier.name),
|
||||||
|
isWrappedModule,
|
||||||
|
)) ||
|
||||||
|
isImport(node, scope, patterns)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkRequireArgs = (args, dependencyId) => {
|
||||||
|
const pattern = t.stringLiteral(dependencyId);
|
||||||
|
return (
|
||||||
|
t.isStringLiteral(args[0], pattern) ||
|
||||||
|
(t.isMemberExpression(args[0]) &&
|
||||||
|
t.isNumericLiteral(args[0].property) &&
|
||||||
|
t.isStringLiteral(args[1], pattern))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isToplevelBinding = (binding, isWrappedModule) =>
|
||||||
|
isGlobal(binding) ||
|
||||||
|
!binding.scope.parent ||
|
||||||
|
(isWrappedModule && !binding.scope.parent.parent);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isPlatformNode,
|
||||||
|
isPlatformSelectNode,
|
||||||
|
isPlatformOSSelect,
|
||||||
|
getReplacementForPlatformOSSelect,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = createInlinePlatformChecks;
|
||||||
|
119
packages/metro/src/JSTransformer/worker/inline-plugin.js
Normal file
119
packages/metro/src/JSTransformer/worker/inline-plugin.js
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2016-present, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const createInlinePlatformChecks = require('./inline-platform');
|
||||||
|
|
||||||
|
import typeof {types as BabelTypes} from 'babel-core';
|
||||||
|
import type {Ast} from 'babel-core';
|
||||||
|
|
||||||
|
type Context = {types: BabelTypes};
|
||||||
|
|
||||||
|
const env = {name: 'env'};
|
||||||
|
const nodeEnv = {name: 'NODE_ENV'};
|
||||||
|
const processId = {name: 'process'};
|
||||||
|
|
||||||
|
const dev = {name: '__DEV__'};
|
||||||
|
|
||||||
|
function inlinePlugin(context: Context) {
|
||||||
|
const t = context.types;
|
||||||
|
|
||||||
|
const {
|
||||||
|
isPlatformNode,
|
||||||
|
isPlatformSelectNode,
|
||||||
|
isPlatformOSSelect,
|
||||||
|
getReplacementForPlatformOSSelect,
|
||||||
|
} = createInlinePlatformChecks(t);
|
||||||
|
|
||||||
|
const isGlobal = binding => !binding;
|
||||||
|
|
||||||
|
const isFlowDeclared = binding => t.isDeclareVariable(binding.path);
|
||||||
|
|
||||||
|
const isGlobalOrFlowDeclared = binding =>
|
||||||
|
isGlobal(binding) || isFlowDeclared(binding);
|
||||||
|
|
||||||
|
const isLeftHandSideOfAssignmentExpression = (node: Ast, parent) =>
|
||||||
|
t.isAssignmentExpression(parent) && parent.left === node;
|
||||||
|
|
||||||
|
const isProcessEnvNodeEnv = (node: Ast, scope) =>
|
||||||
|
t.isIdentifier(node.property, nodeEnv) &&
|
||||||
|
t.isMemberExpression(node.object) &&
|
||||||
|
t.isIdentifier(node.object.property, env) &&
|
||||||
|
t.isIdentifier(node.object.object, processId) &&
|
||||||
|
isGlobal(scope.getBinding(processId.name));
|
||||||
|
|
||||||
|
const isDev = (node: Ast, parent, scope) =>
|
||||||
|
t.isIdentifier(node, dev) &&
|
||||||
|
isGlobalOrFlowDeclared(scope.getBinding(dev.name)) &&
|
||||||
|
!t.isMemberExpression(parent);
|
||||||
|
|
||||||
|
function findProperty(objectExpression, key, fallback) {
|
||||||
|
const property = objectExpression.properties.find(p => {
|
||||||
|
if (t.isIdentifier(p.key) && p.key.name === key) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t.isStringLiteral(p.key) && p.key.value === key) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return property ? property.value : fallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
visitor: {
|
||||||
|
Identifier(path: Object, state: Object) {
|
||||||
|
if (isDev(path.node, path.parent, path.scope)) {
|
||||||
|
path.replaceWith(t.booleanLiteral(state.opts.dev));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MemberExpression(path: Object, state: Object) {
|
||||||
|
const node = path.node;
|
||||||
|
const scope = path.scope;
|
||||||
|
const opts = state.opts;
|
||||||
|
|
||||||
|
if (!isLeftHandSideOfAssignmentExpression(node, path.parent)) {
|
||||||
|
if (isPlatformNode(node, scope, opts.isWrapped)) {
|
||||||
|
path.replaceWith(t.stringLiteral(opts.platform));
|
||||||
|
} else if (isProcessEnvNodeEnv(node, scope)) {
|
||||||
|
path.replaceWith(
|
||||||
|
t.stringLiteral(opts.dev ? 'development' : 'production'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CallExpression(path: Object, state: Object) {
|
||||||
|
const node = path.node;
|
||||||
|
const scope = path.scope;
|
||||||
|
const arg = node.arguments[0];
|
||||||
|
const opts = state.opts;
|
||||||
|
|
||||||
|
if (isPlatformSelectNode(node, scope, opts.isWrapped)) {
|
||||||
|
const fallback = () =>
|
||||||
|
findProperty(arg, 'default', () => t.identifier('undefined'));
|
||||||
|
const replacement = t.isObjectExpression(arg)
|
||||||
|
? findProperty(arg, opts.platform, fallback)
|
||||||
|
: node;
|
||||||
|
|
||||||
|
path.replaceWith(replacement);
|
||||||
|
} else if (isPlatformOSSelect(node, scope, opts.isWrapped)) {
|
||||||
|
path.replaceWith(
|
||||||
|
getReplacementForPlatformOSSelect(node, opts.platform),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = inlinePlugin;
|
@ -1,147 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2016-present, Facebook, Inc.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*
|
|
||||||
* @flow
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const inlinePlatform = require('./inline-platform');
|
|
||||||
const invariant = require('fbjs/lib/invariant');
|
|
||||||
|
|
||||||
const {transformSync} = require('../../babel-bridge');
|
|
||||||
const {transformFromAstSync} = require('../../babel-bridge');
|
|
||||||
const {babelTypes: t} = require('../../babel-bridge');
|
|
||||||
|
|
||||||
import type {Ast} from '@babel/core';
|
|
||||||
import type {BabelSourceMap} from '@babel/core';
|
|
||||||
|
|
||||||
const env = {name: 'env'};
|
|
||||||
const nodeEnv = {name: 'NODE_ENV'};
|
|
||||||
const processId = {name: 'process'};
|
|
||||||
|
|
||||||
const dev = {name: '__DEV__'};
|
|
||||||
|
|
||||||
const isGlobal = binding => !binding;
|
|
||||||
|
|
||||||
const isFlowDeclared = binding => t.isDeclareVariable(binding.path);
|
|
||||||
|
|
||||||
const isGlobalOrFlowDeclared = binding =>
|
|
||||||
isGlobal(binding) || isFlowDeclared(binding);
|
|
||||||
|
|
||||||
const isLeftHandSideOfAssignmentExpression = (node, parent) =>
|
|
||||||
t.isAssignmentExpression(parent) && parent.left === node;
|
|
||||||
|
|
||||||
const isProcessEnvNodeEnv = (node, scope) =>
|
|
||||||
t.isIdentifier(node.property, nodeEnv) &&
|
|
||||||
t.isMemberExpression(node.object) &&
|
|
||||||
t.isIdentifier(node.object.property, env) &&
|
|
||||||
t.isIdentifier(node.object.object, processId) &&
|
|
||||||
isGlobal(scope.getBinding(processId.name));
|
|
||||||
|
|
||||||
const isDev = (node, parent, scope) =>
|
|
||||||
t.isIdentifier(node, dev) &&
|
|
||||||
isGlobalOrFlowDeclared(scope.getBinding(dev.name)) &&
|
|
||||||
!t.isMemberExpression(parent);
|
|
||||||
|
|
||||||
function findProperty(objectExpression, key, fallback) {
|
|
||||||
const property = objectExpression.properties.find(p => {
|
|
||||||
if (t.isIdentifier(p.key) && p.key.name === key) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t.isStringLiteral(p.key) && p.key.value === key) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
return property ? property.value : fallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
const inlinePlugin = {
|
|
||||||
visitor: {
|
|
||||||
Identifier(path, state) {
|
|
||||||
if (isDev(path.node, path.parent, path.scope)) {
|
|
||||||
path.replaceWith(t.booleanLiteral(state.opts.dev));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MemberExpression(path, state) {
|
|
||||||
const node = path.node;
|
|
||||||
const scope = path.scope;
|
|
||||||
const opts = state.opts;
|
|
||||||
|
|
||||||
if (!isLeftHandSideOfAssignmentExpression(node, path.parent)) {
|
|
||||||
if (inlinePlatform.isPlatformNode(node, scope, opts.isWrapped)) {
|
|
||||||
path.replaceWith(t.stringLiteral(opts.platform));
|
|
||||||
} else if (isProcessEnvNodeEnv(node, scope)) {
|
|
||||||
path.replaceWith(
|
|
||||||
t.stringLiteral(opts.dev ? 'development' : 'production'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
CallExpression(path, state) {
|
|
||||||
const node = path.node;
|
|
||||||
const scope = path.scope;
|
|
||||||
const arg = node.arguments[0];
|
|
||||||
const opts = state.opts;
|
|
||||||
|
|
||||||
if (inlinePlatform.isPlatformSelectNode(node, scope, opts.isWrapped)) {
|
|
||||||
const fallback = () =>
|
|
||||||
findProperty(arg, 'default', () => t.identifier('undefined'));
|
|
||||||
const replacement = t.isObjectExpression(arg)
|
|
||||||
? findProperty(arg, opts.platform, fallback)
|
|
||||||
: node;
|
|
||||||
|
|
||||||
path.replaceWith(replacement);
|
|
||||||
} else if (
|
|
||||||
inlinePlatform.isPlatformOSSelect(node, scope, opts.isWrapped)
|
|
||||||
) {
|
|
||||||
path.replaceWith(
|
|
||||||
inlinePlatform.getReplacementForPlatformOSSelect(node, opts.platform),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const plugin = () => inlinePlugin;
|
|
||||||
|
|
||||||
type AstResult = {
|
|
||||||
ast: Ast,
|
|
||||||
code: ?string,
|
|
||||||
map: ?BabelSourceMap,
|
|
||||||
};
|
|
||||||
|
|
||||||
function inline(
|
|
||||||
filename: string,
|
|
||||||
transformResult: {ast?: ?Ast, code: string, map: ?BabelSourceMap},
|
|
||||||
options: {+dev: boolean, +platform: ?string},
|
|
||||||
): AstResult {
|
|
||||||
const code = transformResult.code;
|
|
||||||
const babelOptions = {
|
|
||||||
filename,
|
|
||||||
plugins: [[plugin, options]],
|
|
||||||
inputSourceMap: transformResult.map,
|
|
||||||
sourceMaps: true,
|
|
||||||
sourceFileName: filename,
|
|
||||||
code: false,
|
|
||||||
babelrc: false,
|
|
||||||
compact: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = transformResult.ast
|
|
||||||
? transformFromAstSync(transformResult.ast, code, babelOptions)
|
|
||||||
: transformSync(code, babelOptions);
|
|
||||||
const {ast} = result;
|
|
||||||
invariant(ast != null, 'Missing AST in babel transform results.');
|
|
||||||
return {ast, code: result.code, map: result.map};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline.plugin = inlinePlugin;
|
|
||||||
module.exports = inline;
|
|
@ -14,18 +14,18 @@ const constantFolding = require('../../JSTransformer/worker/constant-folding')
|
|||||||
.plugin;
|
.plugin;
|
||||||
const generate = require('./generate');
|
const generate = require('./generate');
|
||||||
const getMinifier = require('../../lib/getMinifier');
|
const getMinifier = require('../../lib/getMinifier');
|
||||||
const inline = require('../../JSTransformer/worker/inline').plugin;
|
const inlinePlugin = require('../../JSTransformer/worker/inline-plugin');
|
||||||
const invariant = require('fbjs/lib/invariant');
|
const invariant = require('fbjs/lib/invariant');
|
||||||
const optimizeDependencies = require('./optimizeDependencies');
|
const optimizeDependencies = require('./optimizeDependencies');
|
||||||
const sourceMap = require('source-map');
|
const sourceMap = require('source-map');
|
||||||
|
|
||||||
const {transformSync} = require('../../babel-bridge');
|
const {transformSync} = require('../../babel-bridge');
|
||||||
|
|
||||||
|
import type {PostMinifyProcess} from '../../Bundler/index.js';
|
||||||
import type {TransformedSourceFile, TransformResult} from '../types.flow';
|
import type {TransformedSourceFile, TransformResult} from '../types.flow';
|
||||||
import type {BabelSourceMap} from '@babel/core';
|
import type {BabelSourceMap} from '@babel/core';
|
||||||
import type {MetroSourceMap} from 'metro-source-map';
|
|
||||||
import type {PostMinifyProcess} from '../../Bundler/index.js';
|
|
||||||
import type {TransformResult as BabelTransformResult} from '@babel/core';
|
import type {TransformResult as BabelTransformResult} from '@babel/core';
|
||||||
|
import type {MetroSourceMap} from 'metro-source-map';
|
||||||
|
|
||||||
export type OptimizationOptions = {|
|
export type OptimizationOptions = {|
|
||||||
dev: boolean,
|
dev: boolean,
|
||||||
@ -118,7 +118,7 @@ function optimizeCode(
|
|||||||
return transformSync(code, {
|
return transformSync(code, {
|
||||||
plugins: [
|
plugins: [
|
||||||
[constantFolding],
|
[constantFolding],
|
||||||
[inline, {...inliningOptions, isWrapped: true}],
|
[inlinePlugin, {...inliningOptions, isWrapped: true}],
|
||||||
],
|
],
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
code: false,
|
code: false,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user