Skip to content

Commit

Permalink
Fix package entry url with ?raw flag
Browse files Browse the repository at this point in the history
  • Loading branch information
ije committed Jan 4, 2025
1 parent e4f3d01 commit 5f5d78c
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 265 deletions.
198 changes: 0 additions & 198 deletions server/build.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package server

import (
"bufio"
"bytes"
"encoding/base64"
"encoding/json"
Expand All @@ -12,7 +11,6 @@ import (
"path"
"regexp"
"sort"
"strconv"
"strings"

"github.com/esm-dev/esm.sh/server/npm_replacements"
Expand Down Expand Up @@ -40,7 +38,6 @@ type BuildContext struct {
target string
pinedTarget bool
dev bool
zoneId string
wd string
pkgJson *PackageJSON
path string
Expand Down Expand Up @@ -266,7 +263,6 @@ func (ctx *BuildContext) buildModule(analyzeMode bool) (meta *BuildMeta, include
target: ctx.target,
pinedTarget: ctx.pinedTarget,
dev: ctx.dev,
zoneId: ctx.zoneId,
}
err = b.install()
if err != nil {
Expand Down Expand Up @@ -1244,7 +1240,6 @@ REBUILD:
target: ctx.target,
pinedTarget: ctx.pinedTarget,
dev: ctx.dev,
zoneId: ctx.zoneId,
}
err = b.install()
if err == nil {
Expand Down Expand Up @@ -1457,196 +1452,3 @@ func (ctx *BuildContext) install() (err error) {
}
return
}

func (ctx *BuildContext) analyzeSplitting() (err error) {
if ctx.bundleMode == BundleDefault && ctx.pkgJson.Exports.Len() > 1 {
exportNames := set.New[string]()
exportAll := false
for _, exportName := range ctx.pkgJson.Exports.keys {
exportName := stripEntryModuleExt(exportName)
if (exportName == "." || strings.HasPrefix(exportName, "./")) && !endsWith(exportName, ".json", ".css", ".wasm", ".d.ts", ".d.mts") {
if exportName == "./*" {
exportAll = true
break
}
if !strings.ContainsRune(exportName, '*') {
v := ctx.pkgJson.Exports.values[exportName]
if s, ok := v.(string); ok {
if endsWith(s, ".json", ".css", ".wasm", ".d.ts", ".d.mts") {
continue
}
} else if obj, ok := v.(JSONObject); ok {
// ignore types only exports
if len(obj.keys) == 1 && obj.keys[0] == "types" {
continue
}
}
if exportName == "." {
exportNames.Add("")
} else if strings.HasPrefix(exportName, "./") {
exportNames.Add(exportName[2:])
}
}
}
}
if !exportAll && exportNames.Len() > 1 {
splittingTxtPath := path.Join(ctx.wd, "splitting.txt")
readSplittingTxt := func() bool {
f, err := os.Open(splittingTxtPath)
if err != nil {
return false
}
defer f.Close()

var a []string
var i int
var r = bufio.NewReader(f)
for {
line, readErr := r.ReadString('\n')
if readErr == nil || readErr == io.EOF {
line = strings.TrimSpace(line)
if line != "" {
if a == nil {
n, e := strconv.Atoi(line)
if e != nil {
break
}
a = make([]string, n+1)
}
a[i] = line
i++
}
}
if readErr != nil {
break
}
}
if len(a) > 0 {
n, e := strconv.Atoi(a[0])
if e == nil && n <= len(a)-1 {
ctx.splitting = set.NewReadOnly[string](a[1 : n+1]...)
if DEBUG {
log.Debugf("build(%s): splitting.txt found with %d shared modules", ctx.esm.Specifier(), ctx.splitting.Len())
}
return true
}
}
return false
}

// check if the splitting has been analyzed
if readSplittingTxt() {
return
}

// only one analyze process is allowed at the same time for the same package
unlock := installMutex.Lock(splittingTxtPath)
defer unlock()

// skip analyze if the package has been analyzed by another request
if readSplittingTxt() {
return
}

defer func() {
splitting := []string{}
if ctx.splitting != nil {
splitting = ctx.splitting.Values()
}
// write the splitting result to 'splitting.txt'
sizeStr := strconv.FormatUint(uint64(len(splitting)), 10)
bufSize := len(sizeStr) + 1
for _, s := range splitting {
bufSize += len(s) + 1
}
buf := make([]byte, bufSize)
i := copy(buf, sizeStr)
buf[i] = '\n'
i++
for _, s := range splitting {
i += copy(buf[i:], s)
buf[i] = '\n'
i++
}
os.WriteFile(splittingTxtPath, buf[0:bufSize-1], 0644)
}()

refs := map[string]Ref{}
for _, exportName := range exportNames.Values() {
esmPath := ctx.esm
esmPath.SubPath = exportName
esmPath.SubModuleName = stripEntryModuleExt(exportName)
b := &BuildContext{
esm: esmPath,
npmrc: ctx.npmrc,
args: ctx.args,
externalAll: ctx.externalAll,
target: ctx.target,
pinedTarget: ctx.pinedTarget,
dev: ctx.dev,
zoneId: ctx.zoneId,
wd: ctx.wd,
pkgJson: ctx.pkgJson,
}
_, includes, err := b.buildModule(true)
if err != nil {
return fmt.Errorf("failed to analyze %s: %v", esmPath.Specifier(), err)
}
for _, include := range includes {
module, importer := include[0], include[1]
ref, ok := refs[module]
if !ok {
ref = Ref{entries: set.New[string](), importers: set.New[string]()}
refs[module] = ref
}
ref.importers.Add(importer)
ref.entries.Add(exportName)
}
}
shared := set.New[string]()
for mod, ref := range refs {
if ref.entries.Len() > 1 && ref.importers.Len() > 1 {
shared.Add(mod)
}
}
var bubble func(modulePath string, f func(string), mark *set.Set[string])
bubble = func(modulePath string, f func(string), mark *set.Set[string]) {
hasMark := mark != nil
if !hasMark {
mark = set.New[string]()
} else if mark.Has(modulePath) {
return
}
mark.Add(modulePath)
ref, ok := refs[modulePath]
if ok {
if shared.Has(modulePath) && hasMark {
f(modulePath)
return
}
for _, importer := range ref.importers.Values() {
bubble(importer, f, mark)
}
} else {
// modulePath is an entry module
f(modulePath)
}
}
if shared.Len() > 0 {
splitting := set.New[string]()
for _, modulePath := range shared.Values() {
refBy := set.New[string]()
bubble(modulePath, func(importer string) { refBy.Add(importer) }, nil)
if refBy.Len() > 1 {
splitting.Add(modulePath)
}
}
ctx.splitting = splitting.ReadOnly()
if DEBUG {
log.Debugf("build(%s): found %d shared modules from %d modules", ctx.esm.Specifier(), shared.Len(), len(refs))
}
}
}
}
return
}
Loading

0 comments on commit 5f5d78c

Please sign in to comment.