UNPKG

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
"use strict"; 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