package jsbundler import "path/filepath" // Config tells the bundler where the application tree and the shared kjol JS // tree live. The bundler always runs from the app root, so relative paths are // resolved against that working directory (absolute paths also work). // // When WebDir is empty the bundler runs in single-tree mode: the kit, vendored // runtime, icons, and styles are expected under AppFrontend (the pre-extraction // layout). When WebDir points at kjol/go/jsruntime, those come from the shared // tree and the app supplies only its pages/routes/brand. type Config struct { AppFrontend string // app frontend source root (default "frontend") WebDir string // path to kjol/go/jsruntime; "" => single-tree under AppFrontend Output string // build output dir (default "wwwroot") GenGoDir string // dir for generated Go, e.g. public_pages.gen.go (default "internal/handlers") GenTSDir string // dir for generated TS, e.g. faIcons.ts (default AppFrontend/src/ui/generated) } // Package-level resolved configuration. Set once by Configure (called from // Build / StartDevHMR) and read by every stage. Defaults preserve the original // single-tree behaviour so nothing breaks before an app opts into the kjol tree. var ( frontendDir = "frontend" outputDir = "wwwroot" webDir = "" // kjol/go/jsruntime; empty => single-tree genGoDir = "internal/handlers" genTSDir = filepath.Join("frontend", "src", "ui", "generated") ) // Configure applies c, filling defaults for empty fields. func Configure(c Config) { if c.AppFrontend != "" { frontendDir = c.AppFrontend } if c.Output != "" { outputDir = c.Output } if c.GenGoDir != "" { genGoDir = c.GenGoDir } webDir = c.WebDir if c.GenTSDir != "" { genTSDir = c.GenTSDir } else { genTSDir = filepath.Join(frontendDir, "src", "ui", "generated") } } // webRoot is the kjol JS tree (@kjol/* root), falling back to the app frontend // in single-tree mode. func webRoot() string { if webDir != "" { return webDir } return frontendDir } // uikitDir is where the shared Solid component kit lives (@ui/* root). func uikitDir() string { if webDir != "" { return filepath.Join(webDir, "uikit") } return filepath.Join(frontendDir, "src", "ui") } // iconsDirs lists the FontAwesome SVG source roots in resolution precedence // order: the app's own kit first, kjol's second. // // The app has to win. kjol ships a SUBSET — the icons its own kit and example // reference — while an app carries the full FontAwesome kit it licensed. If kjol // were searched first (or searched alone, as this used to be when WebDir was // set), an app adopting the shared tree would silently regenerate its registry // from kjol's few dozen icons and lose every other icon it uses, with no error: // the registry would simply come back smaller and the icons would render blank. // // Searching both, app-first, means an app-side icon of the same name overrides // kjol's, and an icon kjol has never heard of still resolves. func iconsDirs() []string { if webDir != "" { return []string{filepath.Join(frontendDir, "icons"), filepath.Join(webDir, "icons")} } return []string{filepath.Join(frontendDir, "icons")} } // vendorDirs lists the vendored-runtime roots in resolution precedence order. // The kjol runtime comes first so its solid-js wins (a split reactive instance // silently breaks effect flushing). func vendorDirs() []string { if webDir != "" { return []string{filepath.Join(webDir, "runtime"), filepath.Join(frontendDir, "vendor")} } return []string{filepath.Join(frontendDir, "vendor")} } // faOutPath is where the generated FA registry is written (app-owned). func faOutPath() string { return filepath.Join(genTSDir, "faIcons.ts") }