Skip to content

Commit

Permalink
fix #631: optionally print a build summary
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Dec 31, 2020
1 parent 1bfd135 commit f702341
Show file tree
Hide file tree
Showing 6 changed files with 316 additions and 13 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## Unreleased

* Add a `--summary` flag that prints helpful information after a build ([#631](https://github.com/evanw/esbuild/issues/631))

Normally esbuild's CLI doesn't print anything after doing a build if nothing went wrong. This allows esbuild to be used as part of a more complex chain of tools without the output cluttering the terminal. However, sometimes it is nice to have a quick overview in your terminal of what the build just did. You can now add the `--summary` flag when using the CLI and esbuild will print a summary of what the build generated. It looks something like this:

```
$ ./esbuild --summary --bundle src/Three.js --outfile=build/three.js --sourcemap
build/three.js 1.0mb ⚠️
build/three.js.map 1.8mb
⚡ Done in 43ms
```
## 0.8.27
* Mark `import.meta` as supported in node 10.4+ ([#626](https://github.com/evanw/esbuild/issues/626))
Expand Down
14 changes: 7 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -442,13 +442,13 @@ demo-three: demo-three-esbuild demo-three-rollup demo-three-webpack demo-three-w

demo-three-esbuild: esbuild | demo/three
rm -fr demo/three/esbuild
time -p ./esbuild --bundle --global-name=THREE --sourcemap --minify demo/three/src/Three.js --outfile=demo/three/esbuild/Three.esbuild.js
time -p ./esbuild --bundle --summary --global-name=THREE --sourcemap --minify demo/three/src/Three.js --outfile=demo/three/esbuild/Three.esbuild.js
du -h demo/three/esbuild/Three.esbuild.js*
shasum demo/three/esbuild/Three.esbuild.js*

demo-three-eswasm: npm/esbuild-wasm/esbuild.wasm | demo/three
rm -fr demo/three/eswasm
time -p ./npm/esbuild-wasm/bin/esbuild --bundle --global-name=THREE \
time -p ./npm/esbuild-wasm/bin/esbuild --bundle --summary --global-name=THREE \
--sourcemap --minify demo/three/src/Three.js --outfile=demo/three/eswasm/Three.eswasm.js
du -h demo/three/eswasm/Three.eswasm.js*
shasum demo/three/eswasm/Three.eswasm.js*
Expand Down Expand Up @@ -528,13 +528,13 @@ bench-three: bench-three-esbuild bench-three-rollup bench-three-webpack bench-th

bench-three-esbuild: esbuild | bench/three
rm -fr bench/three/esbuild
time -p ./esbuild --bundle --global-name=THREE --sourcemap --minify bench/three/src/entry.js --outfile=bench/three/esbuild/entry.esbuild.js
time -p ./esbuild --bundle --summary --global-name=THREE --sourcemap --minify bench/three/src/entry.js --outfile=bench/three/esbuild/entry.esbuild.js
du -h bench/three/esbuild/entry.esbuild.js*
shasum bench/three/esbuild/entry.esbuild.js*

bench-three-eswasm: npm/esbuild-wasm/esbuild.wasm | bench/three
rm -fr bench/three/eswasm
time -p ./npm/esbuild-wasm/bin/esbuild --bundle --global-name=THREE \
time -p ./npm/esbuild-wasm/bin/esbuild --bundle --summary --global-name=THREE \
--sourcemap --minify bench/three/src/entry.js --outfile=bench/three/eswasm/entry.eswasm.js
du -h bench/three/eswasm/entry.eswasm.js*
shasum bench/three/eswasm/entry.eswasm.js*
Expand Down Expand Up @@ -634,7 +634,7 @@ bench-rome: bench-rome-esbuild bench-rome-webpack bench-rome-webpack5 bench-rome

bench-rome-esbuild: esbuild | bench/rome bench/rome-verify
rm -fr bench/rome/esbuild
time -p ./esbuild --bundle --sourcemap --minify bench/rome/src/entry.ts --outfile=bench/rome/esbuild/rome.esbuild.js --platform=node
time -p ./esbuild --bundle --summary --sourcemap --minify bench/rome/src/entry.ts --outfile=bench/rome/esbuild/rome.esbuild.js --platform=node
du -h bench/rome/esbuild/rome.esbuild.js*
shasum bench/rome/esbuild/rome.esbuild.js*
cd bench/rome-verify && rm -fr esbuild && ROME_CACHE=0 node ../rome/esbuild/rome.esbuild.js bundle packages/rome esbuild
Expand Down Expand Up @@ -771,7 +771,7 @@ bench-readmin: bench-readmin-esbuild

bench-readmin-esbuild: esbuild | bench/readmin
rm -fr bench/readmin/esbuild
time -p ./esbuild --bundle --minify --loader:.js=jsx --define:process.env.NODE_ENV='"production"' \
time -p ./esbuild --bundle --summary --minify --loader:.js=jsx --define:process.env.NODE_ENV='"production"' \
--define:global=window --sourcemap --outfile=bench/readmin/esbuild/main.js bench/readmin/repo/src/index.js
echo "$(READMIN_HTML)" > bench/readmin/esbuild/index.html
du -h bench/readmin/esbuild/main.js*
Expand All @@ -780,7 +780,7 @@ bench-readmin-esbuild: esbuild | bench/readmin
bench-readmin-eswasm: npm/esbuild-wasm/esbuild.wasm | bench/readmin
rm -fr bench/readmin/eswasm
time -p ./npm/esbuild-wasm/bin/esbuild \
--bundle --minify --loader:.js=jsx --define:process.env.NODE_ENV='"production"' \
--bundle --summary --minify --loader:.js=jsx --define:process.env.NODE_ENV='"production"' \
--define:global=window --sourcemap --outfile=bench/readmin/eswasm/main.js bench/readmin/repo/src/index.js
echo "$(READMIN_HTML)" > bench/readmin/eswasm/index.html
du -h bench/readmin/eswasm/main.js*
Expand Down
1 change: 1 addition & 0 deletions cmd/esbuild/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ var helpText = func(colors logger.Colors) string {
--serve=... Start a local HTTP server on this host:port for outputs
--sourcemap Emit a source map
--splitting Enable code splitting (currently only for esm)
--summary Print some helpful information at the end of a build
--target=... Environment target (e.g. es2017, chrome58, firefox57,
safari11, edge16, node10, default esnext)
Expand Down
223 changes: 218 additions & 5 deletions internal/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ package logger
import (
"fmt"
"os"
"runtime"
"sort"
"strings"
"sync"
"time"
)

type Log struct {
Expand Down Expand Up @@ -383,11 +385,18 @@ func PrintMessageToStderr(osArgs []string, msg Msg) {
}

type Colors struct {
Default string
Bold string
Dim string
Red string
Green string
Default string
Bold string
Dim string

Red string
Green string
Blue string

Cyan string
Magenta string
Yellow string

Underline string
}

Expand All @@ -414,13 +423,211 @@ func PrintText(file *os.File, level LogLevel, osArgs []string, callback func(Col
colors.Default = colorReset
colors.Bold = colorResetBold
colors.Dim = colorResetDim

colors.Red = colorRed
colors.Green = colorGreen
colors.Blue = colorBlue

colors.Cyan = colorCyan
colors.Magenta = colorMagenta
colors.Yellow = colorYellow

colors.Underline = colorResetUnderline
}
writeStringWithColor(file, callback(colors))
}

type SummaryTableEntry struct {
Dir string
Base string
Size string
Bytes int
IsSourceMap bool
}

// This type is just so we can use Go's native sort function
type SummaryTable []SummaryTableEntry

func (t SummaryTable) Len() int { return len(t) }
func (t SummaryTable) Swap(i int, j int) { t[i], t[j] = t[j], t[i] }

func (t SummaryTable) Less(i int, j int) bool {
ti := t[i]
tj := t[j]

// Sort source maps last
if !ti.IsSourceMap && tj.IsSourceMap {
return true
}
if ti.IsSourceMap && !tj.IsSourceMap {
return false
}

// Sort by size first
if ti.Bytes > tj.Bytes {
return true
}
if ti.Bytes < tj.Bytes {
return false
}

// Sort subdirectories first
if strings.HasPrefix(ti.Dir, tj.Dir) {
return true
}
if strings.HasPrefix(tj.Dir, ti.Dir) {
return false
}

// Sort alphabetically by directory first
if ti.Dir < tj.Dir {
return true
}
if ti.Dir > tj.Dir {
return false
}

// Then sort alphabetically by file name
return ti.Base < tj.Base
}

// Show a warning icon next to output files that are 1mb or larger
const sizeWarningThreshold = 1024 * 1024

func PrintSummary(osArgs []string, table SummaryTable, start time.Time) {
PrintText(os.Stderr, LevelInfo, osArgs, func(colors Colors) string {
isProbablyWindowsCommandPrompt := false
sb := strings.Builder{}

// Assume we are running in Windows Command Prompt if we're on Windows. If
// so, we can't use emoji because it won't be supported. Except we can
// still use emoji if the WT_SESSION environment variable is present
// because that means we're running in the new Windows Terminal instead.
if runtime.GOOS == "windows" {
isProbablyWindowsCommandPrompt = true
for _, env := range os.Environ() {
if strings.HasPrefix(env, "WT_SESSION=") {
isProbablyWindowsCommandPrompt = false
break
}
}
}

if len(table) > 0 {
// Compute the maximum width of the size column
spacingBetweenColumns := 2
hasSizeWarning := false
maxPath := 0
maxSize := 0
for _, entry := range table {
path := len(entry.Dir) + len(entry.Base)
size := len(entry.Size) + spacingBetweenColumns
if path > maxPath {
maxPath = path
}
if size > maxSize {
maxSize = size
}
if !entry.IsSourceMap && entry.Bytes >= sizeWarningThreshold {
hasSizeWarning = true
}
}

margin := " "
layoutWidth := GetTerminalInfo(os.Stderr).Width - 2*len(margin)
if hasSizeWarning {
// Add space for the warning icon
layoutWidth -= 2
}
if layoutWidth > maxPath+maxSize {
layoutWidth = maxPath + maxSize
}
sort.Sort(table)
sb.WriteString("\n")

wasSourceMap := false
for i, entry := range table {
dir, base := entry.Dir, entry.Base
pathWidth := layoutWidth - maxSize

// Truncate the path with "..." to fit on one line
if len(dir)+len(base) > pathWidth {
// Trim the directory from the front, leaving the trailing slash
if len(dir) > 0 {
n := pathWidth - len(base) - 3
if n < 1 {
n = 1
}
dir = "..." + dir[len(dir)-n:]
}

// Trim the file name from the back
if len(dir)+len(base) > pathWidth {
n := pathWidth - len(dir) - 3
if n < 0 {
n = 0
}
base = base[:n] + "..."
}
}

spacer := layoutWidth - len(entry.Size) - len(dir) - len(base)
if spacer < 0 {
spacer = 0
}

// Print a boundary in between normal files and source map files if
// there was more than one normal file. This improves scannability.
if !wasSourceMap && entry.IsSourceMap && i > 1 {
sb.WriteString("\n")
wasSourceMap = true
}

// Put a warning next to the size if it's above a certain threshold
sizeColor := colors.Cyan
sizeWarning := ""
if !entry.IsSourceMap && entry.Bytes >= sizeWarningThreshold {
sizeColor = colors.Yellow

// Emoji don't work in Windows Command Prompt
if !isProbablyWindowsCommandPrompt {
sizeWarning = " ⚠️"
}
}

sb.WriteString(fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s\n",
margin,
colors.Dim,
dir,
colors.Bold,
base,
colors.Default,
strings.Repeat(" ", spacer),
sizeColor,
entry.Size,
sizeWarning,
colors.Default,
))
}
}

lightningSymbol := "⚡ "

// Emoji don't work in Windows Command Prompt
if isProbablyWindowsCommandPrompt {
lightningSymbol = ""
}

sb.WriteString(fmt.Sprintf("\n%s%sDone in %dms%s\n\n",
lightningSymbol,
colors.Green,
time.Since(start).Milliseconds(),
colors.Default,
))
return sb.String()
})
}

func NewDeferLog() Log {
var msgs SortableMsgs
var mutex sync.Mutex
Expand Down Expand Up @@ -450,9 +657,15 @@ func NewDeferLog() Log {
}

const colorReset = "\033[0m"

const colorRed = "\033[31m"
const colorGreen = "\033[32m"
const colorBlue = "\033[34m"

const colorCyan = "\033[36m"
const colorMagenta = "\033[35m"
const colorYellow = "\033[33m"

const colorResetDim = "\033[0;37m"
const colorBold = "\033[1m"
const colorResetBold = "\033[0;1m"
Expand Down
12 changes: 12 additions & 0 deletions internal/logger/logger_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,22 @@ func writeStringWithColor(file *os.File, text string) {
i += len(colorGreen)
attributes = FOREGROUND_GREEN

case strings.HasPrefix(text[i:], colorBlue):
i += len(colorBlue)
attributes = FOREGROUND_BLUE

case strings.HasPrefix(text[i:], colorCyan):
i += len(colorCyan)
attributes = FOREGROUND_GREEN | FOREGROUND_BLUE

case strings.HasPrefix(text[i:], colorMagenta):
i += len(colorMagenta)
attributes = FOREGROUND_RED | FOREGROUND_BLUE

case strings.HasPrefix(text[i:], colorYellow):
i += len(colorYellow)
attributes = FOREGROUND_RED | FOREGROUND_GREEN

case strings.HasPrefix(text[i:], colorResetDim):
i += len(colorResetDim)
attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
Expand Down
Loading

0 comments on commit f702341

Please sign in to comment.