Preface
Back to the classic sentence: " it is, and then makes it ." I believe that many students know the esbuild, which is fast build speed well-known to the public. And, esbuild author Evan Wallace also the official website of the FAQ devoted esbuild why so fast? (Interested students can learn about https://esbuild.github.io/faq/)
So, back to today's article, I will start with the directory structure of esbuild source code, and walk into the bottom world of esbuild with you around the following 2 points:
- First acquainted with the entrance of Esbuild build
- What did the entrance of Esbuild build
1 Get to know the entrance of Esbuild
In Go, package
(packages). Each Go application needs to include an entry package main
, which is the main.go file. So, obviously esbuild itself is also a Go application, that is, its entry file is also the main.go file.
For esbuild, its directory structure:
|—— cmd
|—— docs
|—— images
|—— internal
|—— lib
|—— npm
|—— pkg
|—— require
|—— scripts
.gitignore
go.mod
go.sum
Makefile
README.md
version.txt
It seems that at a glance, there is no main.go file we want, so how do we find the entrance of the entire application?
Students who have studied C should know the Make build tool, which can be used to execute a series of commands we have defined to achieve a certain build goal. Moreover, it is not difficult to find that there is a Makefile in the above directory structure, which is used to register Make commands.
The basic syntax for registering rules in the Makefile file will look like this:
<target> : <prerequisites>
[tab] <commands>
Here, let's understand the meaning of each parameter separately:
target
, that is, the target using the Make command, for example,make a target name
prerequisites
is usually the path corresponding to some files. Once these files are changed, they will be rebuilt when the Make command is executed, otherwise it will nottab
fixed grammatical format requirements, the beginning of thecommands
tab
keycommands
command is the command that will be executed when the Make command is executed to build a target
So, let's take a look at the contents of the Makefile in esbuild:
ESBUILD_VERSION = $(shell cat version.txt)
# Strip debug info
GO_FLAGS += "-ldflags=-s -w"
# Avoid embedding the build path in the executable for more reproducible builds
GO_FLAGS += -trimpath
esbuild: cmd/esbuild/version.go cmd/esbuild/*.go pkg/*/*.go internal/*/*.go go.mod
CGO_ENABLED=0 go build $(GO_FLAGS) ./cmd/esbuild
test:
make -j6 test-common
# These tests are for development
test-common: test-go vet-go no-filepath verify-source-map end-to-end-tests js-api-tests plugin-tests register-test node-unref-tests
# These tests are for release (the extra tests are not included in "test" because they are pretty slow)
test-all:
make -j6 test-common test-deno ts-type-tests test-wasm-node test-wasm-browser lib-typecheck
....
Note: This is only a part of the rules in the Makefile file, interested students can check other rules by themselves~
As you can see, there are many rules registered in the Makefile. esbuild
command we often use corresponds to the esbuild
target here.
According to the introduction of Makefile above and the content here, we can know that the core esbuild
command is implemented by the three related files of cmd/esbuild/version.go cmd/esbuild/*.go
and pkg/*/*.go
and internal/*/*.go go.mod
Then, usually execute the make esbuild
command, which essentially executes the command:
CGO_ENABLED=0 go build $(GO_FLAGS) ./cmd/esbuild
Below, let's take a look at what this command does (meaning):
CGO_ENABLED=0
CGO_ENABLED
is one of Go's environment (env) information. We can use the go env
command to view all the environment information supported by Go.
And here the CGO_ENABLED
to 0
to disabled cgo
, because by default, CGO_ENABLED
as 1
, which is open cgo
, but cgo
will import files containing C code, then that is the final compilation The result will contain some external dynamic links instead of pure static links .
cgo
allows you to use C grammar in .go files. We won’t introduce it in detail here. Interested students can learn about it on their own.
So, at this time, everyone may be thinking about the difference between external dynamic link and static link Why do you need purely statically linked compilation results?
This is because external dynamic linking will break you finally compiled to the platform . Because, there are certain uncertain factors in external dynamic links. Simply put, maybe the application you build now can be used, but the content of the external dynamic link changes on a certain day, then it is likely to cause your program to run. influences.
go build $(GO_FLAGS) ./cmd/esbuild
go build $(GO_FLAGS) ./cmd/esbuild
core is go build
command, which is used to compile the source files, code packages, dependencies and other operations, such as we have here is ./cmd/esbuild/main.go
the compilation operation file.
At this point, we already know that the entry point for cmd/esbuild/main.go
is the 060cc41d30faf3 file. So, let's take a look at what has been done to build the entrance?
2 What does the entrance of Esbuild build?
Although, the code of the entry cmd/esbuild/main.go
only about 268 lines in total. However, in order to facilitate everyone's understanding, I will divide it into the following 3 points to explain step by step:
- Import of basic dependent
package
--help
of the text prompt function of 060cc41d30fb53main
are the specific functions of 060cc41d30fb73?
2.1 Import of basic dependent package
First of all, the basic dependency of package
imported. A total of 8 package
:
import (
"fmt"
"os"
"runtime/debug"
"strings"
"time"
"github.com/evanw/esbuild/internal/api_helpers"
"github.com/evanw/esbuild/internal/logger"
"github.com/evanw/esbuild/pkg/cli"
)
The corresponding functions of these 8 package
fmt
used to format the output I/O functionos
provides system-related interfacesruntime/debug
provides the function of debugging at runtimestrings
a simple function for manipulating UTF-8 encoded stringstime
used to measure and show timegithub.com/evanw/esbuild/internal/api_helpers
used to detect whether the timer is in usegithub.com/evanw/esbuild/internal/logger
used to format the log outputgithub.com/evanw/esbuild/pkg/cli
provides command line interface of esbuild
2.2 --help
of text prompt function of 060cc41d30fcb2
Any tool will have an --help
, which is used to inform the user of the specific commands that can be used. Therefore, the definition of the --help
text prompt function of esbuild also has the same function, the corresponding code (pseudo code):
var helpText = func(colors logger.Colors) string {
return `
` + colors.Bold + `Usage:` + colors.Reset + `
esbuild [options] [entry points]
` + colors.Bold + `Documentation:` + colors.Reset + `
` + colors.Underline + `https://esbuild.github.io/` + colors.Reset + `
` + colors.Bold
...
}
Here we will use the above mentioned logger
this package
of Colors
structure, it is mainly used for beautification in a terminal output, e.g. bold ( Bold
), color ( Red
, Green
):
type Colors struct {
Reset string
Bold string
Dim string
Underline string
Red string
Green string
Blue string
Cyan string
Magenta string
Yellow string
}
The variable created using the Colors
structure will look like this:
var TerminalColors = Colors{
Reset: "\033[0m",
Bold: "\033[1m",
Dim: "\033[37m",
Underline: "\033[4m",
Red: "\033[31m",
Green: "\033[32m",
Blue: "\033[34m",
Cyan: "\033[36m",
Magenta: "\033[35m",
Yellow: "\033[33m",
}
2.3 main
are the main functions of 060cc41d30fd56?
Earlier, we also mentioned that every Go application must have a main package
, that is, the main.go file as the entrance of the application. main
function must also be declared in the main.go file as the entry function of package
main
function, which is the entry file of esbuild, mainly does these two things:
1. Get the input option (option) and process it
We use the above-mentioned os
this package
get input terminal option, that os.Args[1:]
. Among them, [1:]
means to obtain an array composed of all the elements from index 1 to the end of the array.
Then, the osArgs
array will be looped, and each time switch
will determine the specific case
, and the different options will be processed accordingly. For example, the --version
option will output the current version number of esbuild
fmt.Printf("%s\n", esbuildVersion)
os.Exit(0)
The code corresponding to this whole process will be like this:
osArgs := os.Args[1:]
argsEnd := 0
for _, arg := range osArgs {
switch {
case arg == "-h", arg == "-help", arg == "--help", arg == "/?":
logger.PrintText(os.Stdout, logger.LevelSilent, os.Args, helpText)
os.Exit(0)
// Special-case the version flag here
case arg == "--version":
fmt.Printf("%s\n", esbuildVersion)
os.Exit(0)
...
default:
osArgs[argsEnd] = arg
argsEnd++
}
}
And, it’s worth mentioning that the osArgs
array will be reconstructed here, because multiple options can be entered at once.
But osArgs
will start when the subsequent construction passed as a parameter , so here will be treated to remove the option in the array.
2. Call cli.Run() to start the build
For users, we are really concerned about using esbuild to package an application, for example, using the esbuild xxx.js --bundle
command. And this process is completed by the self-executing function at the end of the main
The core of this function is to call cli.Run()
to start the build process and pass in the options that have been processed above.
func() {
...
exitCode = cli.Run(osArgs)
}()
Moreover, before the official start of the build, the logic related to the previous options will be processed according to the specific logic related to CPU trace, stack trace, etc., which will not be introduced here, and interested students will understand by themselves.
Concluding remarks
Okay, here we have roughly gone through the relevant source code of the entry file built by esbuild. From the perspective of students who have never been in touch with Go, it may be a little bit obscure, and there are some branching logics, which are not analyzed in the article, which will continue to be developed in subsequent articles. However, on the whole, opened a new window and saw a different scenery , which is what we as engineers hope to experience 😎. Finally, if there are improper or wrong expressions in the text, you are welcome to mention Issue~
Like 👍
After reading this article, if you have any gains, you can , this will become my motivation to continue to share, thank you~
I'm Wuliu, I like to innovate and tinker with the source code, focusing on the source code (Vue 3, Vite), front-end engineering, cross-end technology learning and sharing. In addition, all my articles will be included in https://github.com/WJCHumble/Blog , welcome to Watch Or Star!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。