diff --git a/src/babel/traversal/path/ancestry.js b/src/babel/traversal/path/ancestry.js index 2e7100b678..4a346ecb18 100644 --- a/src/babel/traversal/path/ancestry.js +++ b/src/babel/traversal/path/ancestry.js @@ -8,13 +8,20 @@ import NodePath from "./index"; export function findParent(callback) { var path = this; - while (path) { + while (path = path.parentPath) { if (callback(path)) return path; - path = path.parentPath; } return null; } +/** + * Get the parent function of the current path. + */ + +export function getFunctionParent() { + return this.findParent((path) => path.isFunction() || path.isProgram()); +} + /** * Walk up the tree until we hit a parent node path in a list. */ diff --git a/src/babel/traversal/path/lib/hoister.js b/src/babel/traversal/path/lib/hoister.js index 0100694db3..a4e606fd4f 100644 --- a/src/babel/traversal/path/lib/hoister.js +++ b/src/babel/traversal/path/lib/hoister.js @@ -19,7 +19,7 @@ var referenceVisitor = { state.bindings[node.name] = binding; } else { for (var violationPath of (binding.constantViolations: Array)) { - state.breakOnScopePaths.push(violationPath.scope.path); + state.breakOnScopePaths = state.breakOnScopePaths.concat(violationPath.getAncestry()); } } } @@ -106,12 +106,15 @@ export default class PathHoister { this.getCompatibleScopes(); - var path = this.getAttachmentPath(); - if (!path) return; + var attachTo = this.getAttachmentPath(); + if (!attachTo) return; - var uid = path.scope.generateUidIdentifier("ref"); + // don't bother hoisting to the same function as this will cause multiple branches to be evaluated more than once leading to a bad optimisation + if (attachTo.getFunctionParent() === this.path.getFunctionParent()) return; - path.insertBefore([ + var uid = attachTo.scope.generateUidIdentifier("ref"); + + attachTo.insertBefore([ t.variableDeclaration("var", [ t.variableDeclarator(uid, this.path.node) ]) diff --git a/test/core/fixtures/transformation/optimisation.react.constant-elements/deep-constant-violation/actual.js b/test/core/fixtures/transformation/optimisation.react.constant-elements/deep-constant-violation/actual.js new file mode 100644 index 0000000000..27cb8b16f5 --- /dev/null +++ b/test/core/fixtures/transformation/optimisation.react.constant-elements/deep-constant-violation/actual.js @@ -0,0 +1,9 @@ +function render() { + var children = ; + + if (someCondition) { + children = ; + } + + return