prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
199 lines (156 loc) • 8.82 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.optimizeReactComponentTreeRoot = optimizeReactComponentTreeRoot;
var _realm = require("../realm.js");
var _index = require("../values/index.js");
var _utils = require("../serializer/utils.js");
var _utils2 = require("./utils.js");
var _types = require("../serializer/types.js");
var _reconcilation = require("./reconcilation.js");
var _errors = require("./errors.js");
var _singletons = require("../singletons.js");
var _index2 = require("../methods/index.js");
var _invariant = _interopRequireDefault(require("../invariant.js"));
var _logger = require("../utils/logger.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* 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.
*/
/* strict-local */
function writeEffectsKeyOfComponentValue(realm, componentType, componentTreeState, transforms) {
if ((0, _utils2.valueIsClassComponent)(realm, componentType)) {
if (componentTreeState.status === "SIMPLE") {
// if the root component was a class and is now simple, we can convert it from a class
// component to a functional component
if (componentType instanceof _index.BoundFunctionValue) {
let targetFunction = componentType.$BoundTargetFunction;
(0, _invariant.default)(targetFunction instanceof _index.ECMAScriptSourceFunctionValue);
(0, _utils2.convertSimpleClassComponentToFunctionalComponent)(realm, targetFunction, transforms);
(0, _utils2.normalizeFunctionalComponentParamaters)(targetFunction);
return targetFunction;
} else {
(0, _utils2.convertSimpleClassComponentToFunctionalComponent)(realm, componentType, transforms);
(0, _utils2.normalizeFunctionalComponentParamaters)(componentType);
return componentType;
}
} else {
let prototype = (0, _index2.Get)(realm, componentType, "prototype");
(0, _invariant.default)(prototype instanceof _index.ObjectValue);
let renderMethod = (0, _index2.Get)(realm, prototype, "render");
(0, _invariant.default)(renderMethod instanceof _index.ECMAScriptSourceFunctionValue);
return renderMethod;
}
} else {
if (componentTreeState.status === "COMPLEX") {
(0, _utils2.convertFunctionalComponentToComplexClassComponent)(realm, componentType, componentTreeState.componentType, transforms);
let prototype = (0, _index2.Get)(realm, componentType, "prototype");
(0, _invariant.default)(prototype instanceof _index.ObjectValue);
let renderMethod = (0, _index2.Get)(realm, prototype, "render");
(0, _invariant.default)(renderMethod instanceof _index.ECMAScriptSourceFunctionValue);
return renderMethod;
} else {
if (componentType instanceof _index.BoundFunctionValue) {
let targetFunction = componentType.$BoundTargetFunction;
(0, _invariant.default)(targetFunction instanceof _index.ECMAScriptSourceFunctionValue);
(0, _utils2.normalizeFunctionalComponentParamaters)(targetFunction);
return targetFunction;
} else {
(0, _utils2.normalizeFunctionalComponentParamaters)(componentType);
return componentType;
}
}
}
}
function applyWriteEffectsForOptimizedComponent(realm, componentType, _effects, componentTreeState, evaluatedNode, writeEffects, preEvaluationComponentToWriteEffectFunction, parentOptimizedFunction) {
let effects = _effects;
let transforms = [];
let writeEffectsKey = writeEffectsKeyOfComponentValue(realm, componentType, componentTreeState, transforms); // NB: Must be done here because its required by cAE
preEvaluationComponentToWriteEffectFunction.set(componentType, writeEffectsKey);
let additionalFunctionEffects = (0, _utils.createAdditionalEffects)(realm, effects, false, "ReactAdditionalFunctionEffects", writeEffects, preEvaluationComponentToWriteEffectFunction, writeEffectsKey, parentOptimizedFunction, transforms);
if (additionalFunctionEffects === null) {
throw new _errors.ReconcilerFatalError(`Failed to optimize React component tree for "${evaluatedNode.name}" due to an unsupported completion`, evaluatedNode);
}
effects = additionalFunctionEffects.effects;
let value = effects.result;
if (value === realm.intrinsics.undefined) {
// if we get undefined, then this component tree failed and a message was already logged
// in the reconciler
return;
}
writeEffects.set(writeEffectsKey, additionalFunctionEffects); // apply contextTypes for legacy context
if (componentTreeState.contextTypes.size > 0) {
let contextTypes = new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype);
let noOpFunc = (0, _utils2.createNoopFunction)(realm);
for (let key of componentTreeState.contextTypes) {
_singletons.Properties.Set(realm, contextTypes, key, noOpFunc, true);
}
_singletons.Properties.Set(realm, componentType, "contextTypes", contextTypes, true);
}
}
function optimizeReactComponentTreeBranches(realm, reconciler, writeEffects, logger, alreadyEvaluated, preEvaluationComponentToWriteEffectFunction) {
if (realm.react.verbose && reconciler.branchedComponentTrees.length > 0) {
logger.logInformation(` Evaluating React component tree branches...`);
} // for now we just use abstract props/context, in the future we'll create a new branch with a new component
// that used the props/context. It will extend the original component and only have a render method
for (let _ref of reconciler.branchedComponentTrees) {
let {
rootValue: branchRootValue,
evaluatedNode
} = _ref;
let branchComponentType = (0, _utils2.getComponentTypeFromRootValue)(realm, branchRootValue);
if (branchComponentType === null) {
evaluatedNode.status = "UNKNOWN_TYPE";
continue;
}
if (alreadyEvaluated.has(branchComponentType)) {
return;
}
alreadyEvaluated.set(branchComponentType, evaluatedNode);
reconciler.clearComponentTreeState();
if (realm.react.verbose) {
logger.logInformation(` Evaluating ${evaluatedNode.name} (branch)`);
}
let parentOptimizedFunction = realm.currentOptimizedFunction;
let branchEffects = realm.withNewOptimizedFunction(() => reconciler.resolveReactComponentTree(branchComponentType, null, null, evaluatedNode), branchComponentType);
if (realm.react.verbose) {
logger.logInformation(` ✔ ${evaluatedNode.name} (branch)`);
}
let branchComponentTreeState = reconciler.componentTreeState;
applyWriteEffectsForOptimizedComponent(realm, branchComponentType, branchEffects, branchComponentTreeState, evaluatedNode, writeEffects, preEvaluationComponentToWriteEffectFunction, parentOptimizedFunction);
}
}
function optimizeReactComponentTreeRoot(realm, componentRoot, config, writeEffects, logger, statistics, alreadyEvaluated, preEvaluationComponentToWriteEffectFunction) {
let reconciler = new _reconcilation.Reconciler(realm, config, alreadyEvaluated, statistics, logger);
let componentType = (0, _utils2.getComponentTypeFromRootValue)(realm, componentRoot);
if (componentType === null) {
return;
}
if (alreadyEvaluated.has(componentType)) {
return;
}
let evaluatedRootNode = (0, _utils2.createReactEvaluatedNode)("ROOT", (0, _utils2.getComponentName)(realm, componentType));
statistics.evaluatedRootNodes.push(evaluatedRootNode);
alreadyEvaluated.set(componentType, evaluatedRootNode);
if (realm.react.verbose) {
logger.logInformation(` Evaluating ${evaluatedRootNode.name} (root)`);
}
let parentOptimizedFunction = realm.currentOptimizedFunction;
let componentTreeEffects = realm.withNewOptimizedFunction(() => reconciler.resolveReactComponentTree(componentType, null, null, evaluatedRootNode), componentType);
if (realm.react.verbose) {
logger.logInformation(` ✔ ${evaluatedRootNode.name} (root)`);
}
applyWriteEffectsForOptimizedComponent(realm, componentType, componentTreeEffects, reconciler.componentTreeState, evaluatedRootNode, writeEffects, preEvaluationComponentToWriteEffectFunction, parentOptimizedFunction);
let startingComponentTreeBranches = 0;
do {
startingComponentTreeBranches = reconciler.branchedComponentTrees.length;
optimizeReactComponentTreeBranches(realm, reconciler, writeEffects, logger, alreadyEvaluated, preEvaluationComponentToWriteEffectFunction);
} while (startingComponentTreeBranches !== reconciler.branchedComponentTrees.length);
}
//# sourceMappingURL=optimizing.js.map