8000 [pull] master from tdewolff:master by pull[bot] · Pull Request #175 · RepoBackup/minify · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8000
21 changes: 1 addition & 20 deletions js/js.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"bytes"
"fmt"
"io"
"sort"

"github.com/tdewolff/minify/v2"
"github.com/tdewolff/parse/v2"
Expand Down Expand Up @@ -543,25 +542,7 @@ func (m *jsMinifier) minifyVarDecl(decl *js.VarDecl, onlyDefines bool) {
}
}
} else {
if decl.TokenType == js.VarToken {
sort.SliceStable(decl.List, func(i, j int) bool {
if decl.List[i].Default == nil && decl.List[j].Default == nil {
// sort single-length variables names
// TODO: why not all names? Why need identOrder?
if a, ok := decl.List[i].Binding.(*js.Var); ok && len(a.Data) == 1 {
if b, ok := decl.List[j].Binding.(*js.Var); ok && len(b.Data) == 1 {
return m.renamer.identOrder[a.Data[0]] < m.renamer.identOrder[b.Data[0]]
}
}
} else if decl.List[i].Default == nil {
if _, ok := decl.List[j].Binding.(*js.Var); j != 0 || ok {
// move non-define declarations to the front, except for the first array/object
return true
}
}
return false
})
}
m.optimizeVarOrder(decl)

m.write(decl.TokenType.Bytes())
m.writeSpaceBeforeIdent()
Expand Down
3 changes: 2 additions & 1 deletion js/js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,8 @@ func TestJS(t *testing.T) {
{"String.raw`\\b`", "String.raw`\\b`"}, // #701
{"if(true){const a=setInterval(()=>{clearInterval(a)},100)}", "{const a=setInterval(()=>{clearInterval(a)},100)}"}, // #867
{"({a(key){if(x){b.push({key})}}})", "({a(key){x&&b.push({key})}})"}, // #910
{"(a?.b()).c", "(a?.b()).c"}, // #912
{"(a?.b()).c", "(a?.b()).c"}, // #912
{`var a=0;var b=1,c=[...b],[d]=1;`, "var[d]=1,a=0,b=1,c=[...b]"}, // #926
}

m := minify.New()
Expand Down
95 changes: 65 additions & 30 deletions js/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package js

import (
"bytes"
"slices"
"sort"

"github.com/tdewolff/parse/v2/js"
Expand Down Expand Up @@ -365,18 +366,12 @@ func (m *jsMinifier) hoistVars(body *js.BlockStmt) {
nArrays := 0 // of which lhs arrays
nObjects := 0 // of which lhs objects
hasDefinitions := false
for j, item := range varDecl.List {
for _, item := range varDecl.List {
if item.Default != nil {
// move arrays/objects to the front (saves a space)
if _, ok := item.Binding.(*js.BindingObject); ok {
if j != 0 && nArrays == 0 && nObjects == 0 {
varDecl.List[0], varDecl.List[j] = varDecl.List[j], varDecl.List[0]
}
nObjects++
} else if _, ok := item.Binding.(*js.BindingArray); ok {
if j != 0 && nArrays == 0 && nObjects == 0 {
varDecl.List[0], varDecl.List[j] = varDecl.List[j], varDecl.List[0]
}
nArrays++
}
score -= m.countHoistLength(item.Binding) // var names and commas
Expand Down Expand Up @@ -459,37 +454,77 @@ func (m *jsMinifier) hoistVars(body *js.BlockStmt) {
}
}
}
}
}

// rearrange to put array/object first
var prevRefs []*js.Var
BeginArrayObject:
for i, item := range decl.List {
refs := bindingVars(item.Binding)
if _, ok := item.Binding.(*js.Var); !ok {
if i != 0 {
interferes := false
if item.Default != nil {
InterferenceLoop:
for _, ref := range refs {
for _, v := range prevRefs {
if ref == v {
interferes = true
break InterferenceLoop
}
func (m *jsMinifier) optimizeVarOrder(decl *js.VarDecl) {
// rearrange to put array/object first
var prevRefs []*js.Var
BeginArrayObject:
for i, item := range decl.List {
refs := bindingVars(item.Binding)
if _, ok := item.Binding.(*js.Var); !ok {
if i != 0 {
interferes := false
if item.Default != nil {
InterferenceLoop:
for _, ref := range refs {
for _, v := range prevRefs {
if ref == v {
interferes = true
break InterferenceLoop
}
}
}
if !interferes {
decl.List[0], decl.List[i] = decl.List[i], decl.List[0]
break BeginArrayObject
}
if !interferes {
// put current item to the front but otherwise maintain order
if i == 1 {
decl.List[0], decl.List[1] = decl.List[1], decl.List[0]
} else {
copy(decl.List[1:], decl.List[:i])
decl.List[0] = item
}
} else {
break BeginArrayObject
}
}
if item.Default != nil {
prevRefs = append(prevRefs, refs...)
} else {
break BeginArrayObject
}
}
if item.Default != nil {
prevRefs = append(prevRefs, refs...)
}
}

if decl.TokenType == js.VarToken {
// keep array/object assignment inplace
start := 0
if _, ok := decl.List[0].Binding.(*js.Var); !ok {
start++
}

// sort variable names to optimize gzip compression
slices.SortStableFunc(decl.List[start:], func(a, b js.BindingElement) int {
if a.Default == nil && b.Default == nil {
// sort single-length variables names
if va, ok := a.Binding.(*js.Var); ok && len(va.Data) == 1 {
if vb, ok := b.Binding.(*js.Var); ok && len(vb.Data) == 1 {
// sort by most used identifiers first, this is not in ASCII order
A, B := m.renamer.identOrder[va.Data[0]], m.renamer.identOrder[vb.Data[0]]
if A < B {
return -1
} else if B < A {
return 1
}
return 0
}
}
} else if a.Default == nil {
return -1
} else if b.Default == nil {
return 1
}
return 0
})
}
}
Loading
0