Revert D5321193: BREAKING: Add regenerator-runtime on demand, based on the files

Differential Revision: D5321193

fbshipit-source-id: 9113ed78e59ae9e9f3f86ca2fda2db3bd8c0dd7c
This commit is contained in:
Christoph Nakazawa 2017-07-07 10:35:45 -07:00 committed by Facebook Github Bot
parent 0e4b4f7c7b
commit b26b048c78
6 changed files with 100 additions and 221 deletions

View File

@ -10,28 +10,26 @@
*/ */
'use strict'; 'use strict';
/* eslint-disable max-len */ const babel = require('babel-core');
const constantFolding = require('../constant-folding'); const constantFolding = require('../constant-folding');
const {transform, transformFromAst} = require('babel-core'); function parse(code) {
return babel.transform(code, {code: false, babelrc: false, compact: true});
}
const babelOptions = { const babelOptions = {
babelrc: false, babelrc: false,
compact: true, compact: true,
retainLines: false,
}; };
function toString(ast) { function normalize({code}) {
return normalize(transformFromAst(ast, babelOptions).code); return babel.transform(code, babelOptions).code;
}
function normalize(code) {
return transform(code, babelOptions).code;
} }
describe('constant expressions', () => { describe('constant expressions', () => {
it('can optimize conditional expressions with constant conditions', () => { it('can optimize conditional expressions with constant conditions', () => {
const before = ` const code = `
a( a(
'production'=="production", 'production'=="production",
'production'!=='development', 'production'!=='development',
@ -41,97 +39,56 @@ describe('constant expressions', () => {
'android'==='android' ? {a:1} : {a:0}, 'android'==='android' ? {a:1} : {a:0},
'foo'==='bar' ? b : c, 'foo'==='bar' ? b : c,
f() ? g() : h() f() ? g() : h()
); );`;
`; expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual(
'a(true,true,2,true,{},{a:1},c,f()?g():h());',
const after = ` );
a(
true,
true,
2,
true,
{},
{a:1},
c,
f() ? g() : h()
);
`;
const {ast} = constantFolding('arbitrary.js', {code: before});
expect(toString(ast)).toEqual(normalize(after));
}); });
it('can optimize ternary expressions with constant conditions', () => { it('can optimize ternary expressions with constant conditions', () => {
const before = ` const code = `var a = true ? 1 : 2;
var a = true ? 1 : 2; var b = 'android' == 'android'
var b = 'android' == 'android' ? ('production' != 'production' ? 'a' : 'A')
? ('production' != 'production' ? 'a' : 'A') : 'i';`;
: 'i'; expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual(
`; "var a=1;var b='A';",
);
const after = `
var a = 1;
var b = 'A';
`;
const {ast} = constantFolding('arbitrary.js', {code: before});
expect(toString(ast)).toEqual(normalize(after));
}); });
it('can optimize logical operator expressions with constant conditions', () => { it('can optimize logical operator expressions with constant conditions', () => {
const before = ` const code = `
var a = true || 1; var a = true || 1;
var b = 'android' == 'android' && var b = 'android' == 'android' &&
'production' != 'production' || null || "A"; 'production' != 'production' || null || "A";`;
`; expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual(
'var a=true;var b="A";',
const after = ` );
var a = true;
var b = "A";
`;
const {ast} = constantFolding('arbitrary.js', {code: before});
expect(toString(ast)).toEqual(normalize(after));
}); });
it('can optimize logical operators with partly constant operands', () => { it('can optimize logical operators with partly constant operands', () => {
const before = ` const code = `
var a = "truthy" || z(); var a = "truthy" || z();
var b = "truthy" && z(); var b = "truthy" && z();
var c = null && z(); var c = null && z();
var d = null || z(); var d = null || z();
var e = !1 && z(); var e = !1 && z();
`; `;
expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual(
const after = ` 'var a="truthy";var b=z();var c=null;var d=z();var e=false;',
var a = "truthy"; );
var b = z();
var c = null;
var d = z();
var e = false;
`;
const {ast} = constantFolding('arbitrary.js', {code: before});
expect(toString(ast)).toEqual(normalize(after));
}); });
it('can remode an if statement with a falsy constant test', () => { it('can remode an if statement with a falsy constant test', () => {
const before = ` const code = `
if ('production' === 'development' || false) { if ('production' === 'development' || false) {
var a = 1; var a = 1;
} }
`; `;
expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual('');
// Intentionally empty: all dead code.
const after = `
`;
const {ast} = constantFolding('arbitrary.js', {code: before});
expect(toString(ast)).toEqual(normalize(after));
}); });
it('can optimize if-else-branches with constant conditions', () => { it('can optimize if-else-branches with constant conditions', () => {
const before = ` const code = `
if ('production' == 'development') { if ('production' == 'development') {
var a = 1; var a = 1;
var b = a + 2; var b = a + 2;
@ -142,20 +99,13 @@ describe('constant expressions', () => {
var a = 'b'; var a = 'b';
} }
`; `;
expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual(
const after = ` '{var a=3;var b=a+4;}',
{ );
var a = 3;
var b = a + 4;
}
`;
const {ast} = constantFolding('arbitrary.js', {code: before});
expect(toString(ast)).toEqual(normalize(after));
}); });
it('can optimize nested if-else constructs', () => { it('can optimize nested if-else constructs', () => {
const before = ` const code = `
if ('ios' === "android") { if ('ios' === "android") {
if (true) { if (true) {
require('a'); require('a');
@ -170,16 +120,8 @@ describe('constant expressions', () => {
} }
} }
`; `;
expect(normalize(constantFolding('arbitrary.js', parse(code)))).toEqual(
const after = ` "{{require('c');}}",
{ );
{
require('c');
}
}
`;
const {ast} = constantFolding('arbitrary.js', {code: before});
expect(toString(ast)).toEqual(normalize(after));
}); });
}); });

View File

@ -14,8 +14,7 @@ jest
.mock('../constant-folding') .mock('../constant-folding')
.mock('../extract-dependencies') .mock('../extract-dependencies')
.mock('../inline') .mock('../inline')
.mock('../minify') .mock('../minify');
.mock('../regenerator-insertion');
const {objectContaining} = jasmine; const {objectContaining} = jasmine;
@ -235,28 +234,19 @@ describe('code transformation worker:', () => {
}); });
describe('Minifications:', () => { describe('Minifications:', () => {
let constantFolding, inline, regeneratorInsertion; let constantFolding, inline, options;
let options;
let transformResult, dependencyData; let transformResult, dependencyData;
const filename = 'arbitrary/file.js'; const filename = 'arbitrary/file.js';
const resultCode = 'arbitrary(result(code));'; const foldedCode = 'arbitrary(folded(code));';
const resultMap = {version: 3, sources: ['abritrary/file.js']}; const foldedMap = {version: 3, sources: ['fold.js']};
const result = {
ast: {},
code: resultCode,
map: resultMap,
};
beforeEach(() => { beforeEach(() => {
constantFolding = require('../constant-folding').mockReturnValue({
code: foldedCode,
map: foldedMap,
});
extractDependencies = require('../extract-dependencies'); extractDependencies = require('../extract-dependencies');
inline = require('../inline');
constantFolding = require('../constant-folding').mockReturnValue(result);
inline = require('../inline').mockReturnValue(result);
regeneratorInsertion = require('../regenerator-insertion').mockReturnValue(
result,
);
options = {minify: true, transform: {generateSourceMaps: true}}; options = {minify: true, transform: {generateSourceMaps: true}};
dependencyData = { dependencyData = {
@ -265,32 +255,18 @@ describe('code transformation worker:', () => {
}; };
extractDependencies.mockImplementation( extractDependencies.mockImplementation(
code => (code === resultCode ? dependencyData : {}), code => (code === foldedCode ? dependencyData : {}),
); );
transformer.transform.mockImplementation((src, fileName, _) => result); transformer.transform.mockImplementation(
(src, fileName, _) => transformResult,
);
}); });
it('passes the transform result to `regenerator-insertion` for adding regeneratorRuntime', done => { it('passes the transform result to `inline` for constant inlining', done => {
transformResult = {map: {version: 3}, code: 'arbitrary(code)'};
transformCode(transformer, filename, filename, 'code', options, () => { transformCode(transformer, filename, filename, 'code', options, () => {
expect(regeneratorInsertion).toBeCalledWith(filename, result, options); expect(inline).toBeCalledWith(filename, transformResult, options);
done();
});
});
it('passes the result obtained from `regenerator-insertion` on to `inline`', done => {
const regeneratorInsertionResult = {
map: {version: 3, sources: []},
ast: {},
};
regeneratorInsertion.mockReturnValue(regeneratorInsertionResult);
transformCode(transformer, filename, filename, 'code', options, () => {
expect(inline).toBeCalledWith(
filename,
regeneratorInsertionResult,
options,
);
done(); done();
}); });
}); });
@ -298,16 +274,15 @@ describe('code transformation worker:', () => {
it('passes the result obtained from `inline` on to `constant-folding`', done => { it('passes the result obtained from `inline` on to `constant-folding`', done => {
const inlineResult = {map: {version: 3, sources: []}, ast: {}}; const inlineResult = {map: {version: 3, sources: []}, ast: {}};
inline.mockReturnValue(inlineResult); inline.mockReturnValue(inlineResult);
transformCode(transformer, filename, filename, 'code', options, () => { transformCode(transformer, filename, filename, 'code', options, () => {
expect(constantFolding).toBeCalledWith(filename, inlineResult, options); expect(constantFolding).toBeCalledWith(filename, inlineResult);
done(); done();
}); });
}); });
it('Uses the code obtained from the last plugin to extract dependencies', done => { it('Uses the code obtained from `constant-folding` to extract dependencies', done => {
transformCode(transformer, filename, filename, 'code', options, () => { transformCode(transformer, filename, filename, 'code', options, () => {
expect(extractDependencies).toBeCalledWith(resultCode); expect(extractDependencies).toBeCalledWith(foldedCode);
done(); done();
}); });
}); });
@ -327,7 +302,7 @@ describe('code transformation worker:', () => {
); );
}); });
it('uses data produced by the last plugin for the result', done => { it('uses data produced by `constant-folding` for the result', done => {
transformCode( transformCode(
transformer, transformer,
'filename', 'filename',
@ -336,7 +311,7 @@ describe('code transformation worker:', () => {
options, options,
(_, data) => { (_, data) => {
expect(data.result).toEqual( expect(data.result).toEqual(
objectContaining({code: resultCode, map: resultMap}), objectContaining({code: foldedCode, map: foldedMap}),
); );
done(); done();
}, },

View File

@ -13,9 +13,8 @@
'use strict'; 'use strict';
const babel = require('babel-core'); const babel = require('babel-core');
const invariant = require('fbjs/lib/invariant');
import type {IntermediateTransformResult} from './types.flow'; import type {Ast, SourceMap as MappingsMap} from 'babel-core';
const t = babel.types; const t = babel.types;
const Conditional = { const Conditional = {
@ -32,7 +31,7 @@ const Conditional = {
}, },
}; };
const constantFoldingPlugin = { const plugin = {
visitor: { visitor: {
BinaryExpression: { BinaryExpression: {
exit(path) { exit(path) {
@ -72,32 +71,25 @@ const constantFoldingPlugin = {
}, },
}; };
const plugin = () => constantFoldingPlugin;
function constantFolding( function constantFolding(
filename: string, filename: string,
transformResult: IntermediateTransformResult, transformResult: {
options: {+dev: boolean, +platform: ?string}, ast: Ast,
): IntermediateTransformResult { code?: ?string,
const code = transformResult.code; map: ?MappingsMap,
const babelOptions = { },
) {
return babel.transformFromAst(transformResult.ast, transformResult.code, {
filename, filename,
plugins: [[plugin, options]], plugins: [plugin],
inputSourceMap: transformResult.map, inputSourceMap: transformResult.map,
sourceMaps: true, sourceMaps: true,
sourceFileName: filename, sourceFileName: filename,
code: true,
babelrc: false, babelrc: false,
compact: true, compact: true,
}; retainLines: true,
});
const result = transformResult.ast
? babel.transformFromAst(transformResult.ast, code, babelOptions)
: (code && babel.transform(code, babelOptions)) || {};
const {ast} = result;
invariant(ast != null, 'Missing AST in babel transform results.');
return {ast, code: result.code, map: result.map};
} }
constantFolding.plugin = constantFoldingPlugin; constantFolding.plugin = plugin;
module.exports = constantFolding; module.exports = constantFolding;

View File

@ -22,8 +22,7 @@ const minify = require('./minify');
import type {LogEntry} from '../../Logger/Types'; import type {LogEntry} from '../../Logger/Types';
import type {MappingsMap} from '../../lib/SourceMap'; import type {MappingsMap} from '../../lib/SourceMap';
import type {LocalPath} from '../../node-haste/lib/toLocalPath'; import type {LocalPath} from '../../node-haste/lib/toLocalPath';
import type {IntermediateTransformResult} from './types.flow'; import type {Ast, Plugins as BabelPlugins} from 'babel-core';
import type {Plugins as BabelPlugins} from 'babel-core';
export type TransformedCode = { export type TransformedCode = {
code: string, code: string,
@ -39,7 +38,7 @@ export type Transformer<ExtraOptions: {} = {}> = {
options: ExtraOptions & TransformOptions, options: ExtraOptions & TransformOptions,
plugins?: BabelPlugins, plugins?: BabelPlugins,
src: string, src: string,
|}) => IntermediateTransformResult, |}) => {ast: ?Ast, code: string, map: ?MappingsMap},
getCacheKey: () => string, getCacheKey: () => string,
}; };
@ -84,8 +83,6 @@ type TransformCode = (
Callback<Data>, Callback<Data>,
) => void; ) => void;
const transformers = [inline, constantFolding];
const transformCode: TransformCode = asyncify( const transformCode: TransformCode = asyncify(
( (
transformer: Transformer<*>, transformer: Transformer<*>,
@ -124,29 +121,17 @@ const transformCode: TransformCode = asyncify(
'Missing transform results despite having no error.', 'Missing transform results despite having no error.',
); );
let code; var code, map;
let map;
if (options.minify) { if (options.minify) {
let result = transformed; ({code, map} = constantFolding(
const length = transformers.length; filename,
inline(filename, transformed, options),
for (let i = 0; i < length; i++) { ));
result = transformers[i](filename, result, options); invariant(code != null, 'Missing code from constant-folding transform.');
}
({code, map} = result);
} else { } else {
({code, map} = transformed); ({code, map} = transformed);
} }
invariant(
code != null,
'The last transformer on the list (' +
transformers[transformers.length - 1].name +
') has to output code',
);
if (isJson) { if (isJson) {
code = code.replace(/^\w+\.exports=/, ''); code = code.replace(/^\w+\.exports=/, '');
} else { } else {

View File

@ -15,7 +15,7 @@
const babel = require('babel-core'); const babel = require('babel-core');
const invariant = require('fbjs/lib/invariant'); const invariant = require('fbjs/lib/invariant');
import type {IntermediateTransformResult} from './types.flow'; import type {Ast, SourceMap as MappingsMap} from 'babel-core';
const t = babel.types; const t = babel.types;
const React = {name: 'React'}; const React = {name: 'React'};
@ -115,16 +115,6 @@ function findProperty(objectExpression, key, fallback) {
return property ? property.value : fallback(); return property ? property.value : fallback();
} }
function 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 inlinePlugin = { const inlinePlugin = {
visitor: { visitor: {
Identifier(path, state) { Identifier(path, state) {
@ -172,11 +162,27 @@ const inlinePlugin = {
const plugin = () => inlinePlugin; const plugin = () => inlinePlugin;
function 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))
);
}
type AstResult = {
ast: Ast,
code: ?string,
map: ?MappingsMap,
};
function inline( function inline(
filename: string, filename: string,
transformResult: IntermediateTransformResult, transformResult: {ast?: ?Ast, code: string, map: ?MappingsMap},
options: {+dev: boolean, +platform: ?string}, options: {+dev: boolean, +platform: ?string},
): IntermediateTransformResult { ): AstResult {
const code = transformResult.code; const code = transformResult.code;
const babelOptions = { const babelOptions = {
filename, filename,
@ -191,7 +197,7 @@ function inline(
const result = transformResult.ast const result = transformResult.ast
? babel.transformFromAst(transformResult.ast, code, babelOptions) ? babel.transformFromAst(transformResult.ast, code, babelOptions)
: (code && babel.transform(code, babelOptions)) || {}; : babel.transform(code, babelOptions);
const {ast} = result; const {ast} = result;
invariant(ast != null, 'Missing AST in babel transform results.'); invariant(ast != null, 'Missing AST in babel transform results.');
return {ast, code: result.code, map: result.map}; return {ast, code: result.code, map: result.map};

View File

@ -1,21 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @flow
* @format
*/
'use strict';
import type {Ast, SourceMap as MappingsMap} from 'babel-core';
export type IntermediateTransformResult = {
ast: ?Ast,
code: ?string,
map: ?MappingsMap,
};