Skip to main content


npm install @babel/helper-hoist-variables --save


type EmitFunction = (
id: t.Identifier,
idName: string,
hasInit: boolean,
) => any;

declare export default hoistVariables(path: NodePath, emit: EmitFunction, kind: "var" | "let" = "var");


hoistVariables traverses a given path and replaces variable declarations (var x = 1) with assignment expressions (x = 1). It can also replace left hand side expressions for (x of []); like in for (var x of []);). The binding identifiers (x) from the declarations will be emitted via the EmitFunction callback. hoistVariables is only applied to declarations within the same scope of path, in other words, it will not hoist variables defined inside a function body nested inside path. If kind is "let" it will hoist let declarations.

Generally an EmitFunction will declare such variables in outer scope.


import hoistVariables from "@babel/helper-hoist-variables";

// a naive plugin transforms
// `(function myEval(){ var x = 1; })()`
// to
// `var x;(function myEval(){ x = 1; })()`

module.exports = api => {
return {
visitor: {
Function(path) {
if ( === "myEval") {
const outerScope = path.scope.parent;
id => {
// Use Scope#push to register a `var` binding in
// the outer scope
outerScope.push({ id });

@babel/plugin-proposal-do-expressions also uses the same technique to hoist the var declarations in do blocks to the containing function scope.