95 lines
3.0 KiB
Go
95 lines
3.0 KiB
Go
// Solid JSX/TSX compilation (part of package bundler): compiles Solid JSX/TSX to
|
|
// optimized Solid dom-expressions output (template cloning + fine-grained
|
|
// updates) with a Go-native compiler — no Node, no Babel, no goja. The compiler
|
|
// lives in compile_solid.go (parser) and compile_solid_gen.go (codegen);
|
|
// segment.go supplies the top-level splitter it uses to find component
|
|
// declarations for solid-refresh instrumentation.
|
|
//
|
|
// Compile is the prod path (SSR + release bundles); CompileDev adds solid-refresh
|
|
// HMR instrumentation. Both are plain function calls — fast enough that the old
|
|
// per-declaration incremental caching is gone. A small in-memory cache dedups
|
|
// identical transforms within a process (e.g. a module served to several page
|
|
// loads under HMR); there is no on-disk cache and no compiler bootstrap.
|
|
package bundler
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
esbuild "github.com/evanw/esbuild/pkg/api"
|
|
)
|
|
|
|
// cache dedups transforms by content within a process, so a module unchanged
|
|
// across dev page reloads (or repeated in a build) isn't recompiled.
|
|
var cache = struct {
|
|
sync.RWMutex
|
|
m map[string]string
|
|
}{m: map[string]string{}}
|
|
|
|
// cacheKey keys a transform by filename + mode + source.
|
|
func cacheKey(src, filename string, dev bool) string {
|
|
h := sha256.New()
|
|
h.Write([]byte(filename))
|
|
h.Write([]byte{0})
|
|
if dev {
|
|
h.Write([]byte{1})
|
|
} else {
|
|
h.Write([]byte{0})
|
|
}
|
|
h.Write([]byte{0})
|
|
h.Write([]byte(src))
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
// Compile compiles one JSX/TSX source to Solid dom-expressions output (prod: no
|
|
// HMR instrumentation). Results are cached by content for this process.
|
|
func Compile(src, filename string) (string, error) { return compileCached(src, filename, false) }
|
|
|
|
// CompileDev is Compile with solid-refresh HMR instrumentation — the dev module
|
|
// server's entry.
|
|
func CompileDev(src, filename string) (string, error) { return compileCached(src, filename, true) }
|
|
|
|
func compileCached(src, filename string, dev bool) (string, error) {
|
|
key := cacheKey(src, filename, dev)
|
|
cache.RLock()
|
|
if out, ok := cache.m[key]; ok {
|
|
cache.RUnlock()
|
|
return out, nil
|
|
}
|
|
cache.RUnlock()
|
|
|
|
out, err := compileSolidGo(src, filename, dev)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
cache.Lock()
|
|
cache.m[key] = out
|
|
cache.Unlock()
|
|
return out, nil
|
|
}
|
|
|
|
// Plugin returns the esbuild OnLoad hook that Solid-compiles every .tsx/.jsx file
|
|
// in the bundle graph (prod path). Plain .ts/.js files are left to esbuild.
|
|
func Plugin() esbuild.Plugin {
|
|
return esbuild.Plugin{
|
|
Name: "solid-jsx",
|
|
Setup: func(b esbuild.PluginBuild) {
|
|
b.OnLoad(esbuild.OnLoadOptions{Filter: `\.(tsx|jsx)$`}, func(a esbuild.OnLoadArgs) (esbuild.OnLoadResult, error) {
|
|
data, err := os.ReadFile(a.Path)
|
|
if err != nil {
|
|
return esbuild.OnLoadResult{}, err
|
|
}
|
|
out, err := Compile(string(data), filepath.Base(a.Path))
|
|
if err != nil {
|
|
return esbuild.OnLoadResult{}, err
|
|
}
|
|
loader := esbuild.LoaderJS
|
|
return esbuild.OnLoadResult{Contents: &out, Loader: loader}, nil
|
|
})
|
|
},
|
|
}
|
|
}
|