// Solid JSX/TSX compilation (part of package jsbundler): 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 jsbundler 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 }) }, } }