Skip to content

Commit

Permalink
relocate "var" to the top level when bundling
Browse files Browse the repository at this point in the history
This change does not introduce any new functionality yet. It's just a preparatory change for some upcoming code splitting work.
  • Loading branch information
evanw committed Nov 29, 2020
1 parent 9175625 commit 918d44e
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 3 deletions.
3 changes: 2 additions & 1 deletion internal/bundler/snapshots/snapshots_default.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1940,11 +1940,12 @@ TestRequireWithoutCallInsideTry
// /entry.js
try {
oldLocale = globalLocale._abbr;
var aliasedRequire = require;
aliasedRequire = require;
aliasedRequire("./locale/" + name);
getSetGlobalLocale(oldLocale);
} catch (e) {
}
var aliasedRequire;

================================================================================
TestRuntimeNameCollisionNoBundle
Expand Down
5 changes: 3 additions & 2 deletions internal/bundler/snapshots/snapshots_packagejson.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ var require_component_indexof = __commonJS((exports, module) => {

// /Users/user/project/node_modules/component-classes/index.js
try {
var index = require_component_indexof();
index = require_component_indexof();
} catch (err) {
var index = require_component_indexof();
index = require_component_indexof();
}
var index;

================================================================================
TestPackageJsonBrowserMapModuleDisabled
Expand Down
62 changes: 62 additions & 0 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ type parser struct {
// Temporary variables used for lowering
tempRefsToDeclare []tempRef
tempRefCount int

// When bundling, hoisted top-level local variables declared with "var" in
// nested scopes are moved up to be declared in the top-level scope instead.
// The old "var" statements are turned into regular assignments instead. This
// makes it easier to quickly scan the top-level statements for "var" locals
// with the guarantee that all will be found.
relocatedTopLevelVars []js_ast.LocRef
}

// This is used as part of an incremental build cache key. Some of these values
Expand Down Expand Up @@ -7209,6 +7216,34 @@ func (p *parser) visitAndAppendStmt(stmts []js_ast.Stmt, stmt js_ast.Stmt) []js_
s.Decls = p.lowerObjectRestInDecls(s.Decls)
s.Kind = p.selectLocalKind(s.Kind)

// Relocate "var" statements in nested scopes to the top-level scope when
// bundling. This makes it easy to pick out all top-level declarations by
// only looking at the array of top-level statements.
if p.options.mode == config.ModeBundle && s.Kind == js_ast.LocalVar && p.currentScope != p.moduleScope {
scope := p.currentScope
for !scope.Kind.StopsHoisting() {
scope = scope.Parent
}
if scope == p.moduleScope {
wrapIdentifier := func(loc logger.Loc, ref js_ast.Ref) js_ast.Expr {
p.relocatedTopLevelVars = append(p.relocatedTopLevelVars, js_ast.LocRef{Loc: loc, Ref: ref})
p.recordUsage(ref)
return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}
}
var value js_ast.Expr
for _, decl := range s.Decls {
binding := p.convertBindingToExpr(decl.Binding, wrapIdentifier)
if decl.Value != nil {
value = maybeJoinWithComma(value, js_ast.Assign(binding, *decl.Value))
}
}
if value.Data != nil {
stmts = append(stmts, js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SExpr{Value: value}})
}
return stmts
}
}

case *js_ast.SExpr:
s.Value = p.visitExpr(s.Value)

Expand Down Expand Up @@ -10325,6 +10360,33 @@ func (p *parser) appendPart(parts []js_ast.Part, stmts []js_ast.Stmt) []js_ast.P
Stmts: p.visitStmtsAndPrependTempRefs(stmts, prependTempRefsOpts{}),
SymbolUses: p.symbolUses,
}

// Insert any relocated variable statements now
if len(p.relocatedTopLevelVars) > 0 {
alreadyDeclared := make(map[js_ast.Ref]bool)
for _, local := range p.relocatedTopLevelVars {
// Follow links because "var" declarations may be merged due to hoisting
for {
link := p.symbols[local.Ref.InnerIndex].Link
if link == js_ast.InvalidRef {
break
}
local.Ref = link
}

// Only declare a given relocated variable once
if !alreadyDeclared[local.Ref] {
alreadyDeclared[local.Ref] = true
part.Stmts = append(part.Stmts, js_ast.Stmt{Loc: local.Loc, Data: &js_ast.SLocal{
Decls: []js_ast.Decl{{
Binding: js_ast.Binding{Loc: local.Loc, Data: &js_ast.BIdentifier{Ref: local.Ref}},
}},
}})
}
}
p.relocatedTopLevelVars = nil
}

if len(part.Stmts) > 0 {
part.CanBeRemovedIfUnused = p.stmtsCanBeRemovedIfUnused(part.Stmts)
part.DeclaredSymbols = p.declaredSymbols
Expand Down

0 comments on commit 918d44e

Please sign in to comment.