rename packages, refactor out tailwind compiler,
This commit is contained in:
89
go/webbundler/export_shim.go
Normal file
89
go/webbundler/export_shim.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package webbundler
|
||||
|
||||
// defaultExportShimPlugin bridges two ESM-strictness mismatches that
|
||||
// existed in the previous custom bundler:
|
||||
//
|
||||
// 1. `export default function Name` also emits `export { Name }` so
|
||||
// callers using `import { Name } from "..."` resolve correctly.
|
||||
// 2. If the source declares `export function/class/const Name` (or
|
||||
// `Name`) where Name matches the file's basename, synthesize
|
||||
// `export { Name as default }` so callers using `import Name from
|
||||
// "..."` resolve correctly. The old bundler made every IIFE
|
||||
// return value available as both the named symbol AND the default
|
||||
// import; standard ESM does not, so esbuild needs the shim until
|
||||
// callers migrate to named imports throughout.
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
esbuild "github.com/evanw/esbuild/pkg/api"
|
||||
)
|
||||
|
||||
func defaultExportShimPlugin() esbuild.Plugin {
|
||||
return esbuild.Plugin{
|
||||
Name: "default-export-shim",
|
||||
Setup: func(b esbuild.PluginBuild) {
|
||||
b.OnLoad(esbuild.OnLoadOptions{Filter: `\.(js|ts)$`}, func(args esbuild.OnLoadArgs) (esbuild.OnLoadResult, error) {
|
||||
raw, err := os.ReadFile(args.Path)
|
||||
if err != nil {
|
||||
return esbuild.OnLoadResult{}, err
|
||||
}
|
||||
out := addNamedExportForDefault(string(raw))
|
||||
out = addDefaultExportForFilenameMatch(out, args.Path)
|
||||
loader := esbuild.LoaderJS
|
||||
if strings.HasSuffix(args.Path, ".ts") {
|
||||
loader = esbuild.LoaderTS
|
||||
}
|
||||
return esbuild.OnLoadResult{Contents: &out, Loader: loader}, nil
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var reFilenameMatchExport = regexp.MustCompile(`(?m)^export\s+(?:async\s+)?(?:function|class|const|let|var)\s+(\w+)`)
|
||||
var reExistingDefault = regexp.MustCompile(`(?m)^export\s+default\b`)
|
||||
|
||||
// addDefaultExportForFilenameMatch synthesizes `export { Name as
|
||||
// default }` if the source declares a top-level export whose name
|
||||
// matches the file's basename and the file does not already have a
|
||||
// default export. This preserves the old bundler's behavior where
|
||||
// `import Foo from "./Foo.js"` resolved against `export function
|
||||
// Foo(...)`.
|
||||
func addDefaultExportForFilenameMatch(src, path string) string {
|
||||
if reExistingDefault.MatchString(src) {
|
||||
return src
|
||||
}
|
||||
base := filepath.Base(path)
|
||||
base = strings.TrimSuffix(base, filepath.Ext(base))
|
||||
if base == "" {
|
||||
return src
|
||||
}
|
||||
for _, m := range reFilenameMatchExport.FindAllStringSubmatch(src, -1) {
|
||||
if m[1] == base {
|
||||
return src + "\nexport { " + base + " as default };\n"
|
||||
}
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
var reExportDefaultDecl = regexp.MustCompile(`(?m)^export\s+default\s+(?:async\s+)?(?:function|class)\s+(\w+)`)
|
||||
|
||||
func addNamedExportForDefault(src string) string {
|
||||
matches := reExportDefaultDecl.FindAllStringSubmatch(src, -1)
|
||||
if len(matches) == 0 {
|
||||
return src
|
||||
}
|
||||
names := make([]string, 0, len(matches))
|
||||
seen := map[string]bool{}
|
||||
for _, m := range matches {
|
||||
if seen[m[1]] {
|
||||
continue
|
||||
}
|
||||
seen[m[1]] = true
|
||||
names = append(names, m[1])
|
||||
}
|
||||
return src + "\nexport { " + strings.Join(names, ", ") + " };\n"
|
||||
}
|
||||
Reference in New Issue
Block a user