Source File
serve_other.go
Belonging Package
github.com/evanw/esbuild/pkg/api
package api
import (
)
type apiHandler struct {
mutex sync.Mutex
outdirPathPrefix string
servedir string
options *config.Options
onRequest func(ServeOnRequestArgs)
rebuild func() BuildResult
currentBuild *runningBuild
fs fs.FS
}
type runningBuild struct {
waitGroup sync.WaitGroup
result BuildResult
}
func ( *apiHandler) () BuildResult {
:= func() *runningBuild {
.mutex.Lock()
defer .mutex.Unlock()
if .currentBuild == nil {
:= &runningBuild{}
.waitGroup.Add(1)
.currentBuild =
time.Sleep(250 * time.Millisecond)
.mutex.Lock()
defer .mutex.Unlock()
.currentBuild = nil
}()
}
return .currentBuild
}()
.waitGroup.Wait()
return .result
}
func ( string) string {
= strings.ReplaceAll(, "&", "&")
= strings.ReplaceAll(, "<", "<")
= strings.ReplaceAll(, ">", ">")
return
}
func ( string) string {
= escapeForHTML()
= strings.ReplaceAll(, "\"", """)
= strings.ReplaceAll(, "'", "'")
return
}
func ( *apiHandler) ( time.Duration, *http.Request, int) {
if .onRequest != nil {
.onRequest(ServeOnRequestArgs{
RemoteAddress: .RemoteAddr,
Method: .Method,
Path: .URL.Path,
Status: ,
TimeInMS: int(.Milliseconds()),
})
}
}
func ( []Message) string {
:= logger.OutputOptions{IncludeSource: true}
:= logger.TerminalInfo{}
:= strings.Builder{}
:= 5
for , := range convertMessagesToInternal(nil, logger.Error, ) {
if == {
.WriteString(fmt.Sprintf("%d out of %d errors shown\n", , len()))
break
}
.WriteString(.String(, ))
}
return .String()
}
func ( *apiHandler) ( http.ResponseWriter, *http.Request) {
:= time.Now()
if len(.Errors) > 0 {
go .notifyRequest(time.Since(), , http.StatusServiceUnavailable)
.Header().Set("Content-Type", "text/plain; charset=utf-8")
.WriteHeader(http.StatusServiceUnavailable)
.Write([]byte(errorsToString(.Errors)))
return
}
var fs.EntryKind
var []byte
:= make(map[string]bool)
:= make(map[string]bool)
if strings.HasPrefix(, .outdirPathPrefix) {
:= [len(.outdirPathPrefix):]
if strings.HasPrefix(, "/") {
= [1:]
}
, = .matchQueryPathToResult(, &, , )
if .servedir != "" && != fs.FileEntry {
:= .fs.Join(.servedir, )
if := .fs.Dir(); != {
if , := .fs.ReadDirectory(); == nil {
if , := .Get(.fs.Base()); != nil && .Kind(.fs) == fs.FileEntry {
if , := .fs.ReadFile(); == nil {
= []byte()
= fs.FileEntry
} else if != syscall.ENOENT {
go .notifyRequest(time.Since(), , http.StatusInternalServerError)
.WriteHeader(http.StatusInternalServerError)
.Write([]byte(fmt.Sprintf("500 - Internal server error: %s", .Error())))
return
}
}
}
}
}
var string
if .servedir != "" && != fs.FileEntry {
if , := .fs.ReadDirectory(.fs.Join(.servedir, )); == nil {
= fs.DirEntry
for , := range .UnorderedKeys() {
, := .Get()
switch .Kind(.fs) {
case fs.DirEntry:
[] = true
case fs.FileEntry:
[] = true
if == "index.html" {
=
}
}
}
} else if != syscall.ENOENT {
go .notifyRequest(time.Since(), , http.StatusInternalServerError)
.WriteHeader(http.StatusInternalServerError)
.Write([]byte(fmt.Sprintf("500 - Internal server error: %s", .Error())))
return
}
}
if == fs.DirEntry && !strings.HasSuffix(.URL.Path, "/") {
.Header().Set("Location", .URL.Path+"/")
go .notifyRequest(time.Since(), , http.StatusFound)
.WriteHeader(http.StatusFound)
.Write(nil)
return
}
if == fs.DirEntry && != "" {
+= "/" +
, := .fs.ReadFile(.fs.Join(.servedir, ))
if == nil {
= []byte()
= fs.FileEntry
} else if != syscall.ENOENT {
go .notifyRequest(time.Since(), , http.StatusInternalServerError)
.WriteHeader(http.StatusInternalServerError)
.Write([]byte(fmt.Sprintf("500 - Internal server error: %s", .Error())))
return
}
}
.Header().Set("Content-Type", "text/plain; charset=utf-8")
go .notifyRequest(time.Since(), , http.StatusNotFound)
.WriteHeader(http.StatusNotFound)
.Write([]byte("404 - Not Found"))
}
if , := parseRangeInt([:], -1); {
return , + 1, true
}
}
}
}
return 0, 0, false
}
func ( string, int) (int, bool) {
if == "" {
return 0, false
}
:= 0
for , := range {
if < '0' || > '9' {
return 0, false
}
= *10 + int(-'0')
if > {
return 0, false
}
}
return , true
}
func ( *apiHandler) (
string,
*BuildResult,
map[string]bool,
map[string]bool,
) (fs.EntryKind, []byte) {
:= false
:=
if != "" {
+= "/"
}
for , := range .OutputFiles {
if , := .fs.Rel(.options.AbsOutputDir, .Path); {
= strings.ReplaceAll(, "\\", "/")
if {
return fs.DirEntry, nil
}
return 0, nil
}
func ( string, map[string]bool, map[string]bool) []byte {
= "/" +
:=
if != "/" {
+= "/"
}
:= strings.Builder{}
.WriteString(`<!doctype html>`)
.WriteString(`<meta charset="utf8">`)
.WriteString(`<title>Directory: `)
.WriteString(escapeForHTML())
.WriteString(`</title>`)
.WriteString(`<h1>Directory: `)
.WriteString(escapeForHTML())
.WriteString(`</h1>`)
.WriteString(`<ul>`)
if != "/" {
:= path.Dir()
if != "/" {
+= "/"
}
.WriteString(fmt.Sprintf(`<li><a href="%s">../</a></li>`, escapeForAttribute()))
}
:= make([]string, 0, len()+len())
for := range {
= append(, )
}
sort.Strings()
for , := range {
.WriteString(fmt.Sprintf(`<li><a href="%s/">%s/</a></li>`, escapeForAttribute(path.Join(, )), escapeForHTML()))
}
= [:0]
for := range {
= append(, )
}
sort.Strings()
for , := range {
.WriteString(fmt.Sprintf(`<li><a href="%s">%s</a></li>`, escapeForAttribute(path.Join(, )), escapeForHTML()))
}
.WriteString(`</ul>`)
return []byte(.String())
}
func ( fs.FS, string) string {
if , := .Rel(.Cwd(), ); {
return strings.ReplaceAll(, "\\", "/")
}
return
}
func ( ServeOptions, BuildOptions) (ServeResult, error) {
, := fs.RealFS(fs.RealFSOptions{
AbsWorkingDir: .AbsWorkingDir,
DoNotCache: true,
})
if != nil {
return ServeResult{},
}
.Incremental = true
.Write = false
if .Watch != nil {
return ServeResult{}, fmt.Errorf("Cannot use \"watch\" with \"serve\"")
}
, := .Rel(.Servedir, )
if ! {
return ServeResult{}, fmt.Errorf(
"Cannot compute relative path from %q to %q\n", .Servedir, )
}
= strings.ReplaceAll(, "\\", "/") // Fix paths on Windows
if == ".." || strings.HasPrefix(, "../") {
return ServeResult{}, fmt.Errorf(
"Output directory %q must be contained in serve directory %q",
prettyPrintPath(, ),
prettyPrintPath(, .Servedir),
)
}
if != "." {
=
}
}
if , := net.Listen(, net.JoinHostPort(, fmt.Sprintf("%d", .Port))); != nil {
return ServeResult{},
} else {
=
}
}
var ServeResult
if , , := net.SplitHostPort(); == nil {
if , := strconv.ParseInt(, 10, 32); == nil {
.Port = uint16()
.Host =
}
}
var *apiHandler
= &apiHandler{
onRequest: .OnRequest,
outdirPathPrefix: ,
servedir: .Servedir,
rebuild: func() BuildResult {
:= buildImpl()
if .options == nil {
.options = &.options
}
return .result
},
fs: ,
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |