main.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "log"
  7. "net/http"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. )
  12. func main() {
  13. if len(os.Args) <= 1 || os.Args[1] == "serve" {
  14. serve()
  15. return
  16. }
  17. switch os.Args[1] {
  18. case "build":
  19. out := "dist/xjs.js"
  20. if len(os.Args) >= 3 && strings.TrimSpace(os.Args[2]) != "" {
  21. out = os.Args[2]
  22. }
  23. if err := build(out); err != nil {
  24. log.Fatal(err)
  25. }
  26. log.Printf("Built %s\n", out)
  27. default:
  28. fmt.Println("Usage:")
  29. fmt.Println(" go run main.go serve # dev server (default)")
  30. fmt.Println(" go run main.go build [out.js] # bundle animal.js + layer.js into dist/xjs.js (or out.js)")
  31. os.Exit(2)
  32. }
  33. }
  34. func serve() {
  35. // Serve files from the current directory
  36. fs := http.FileServer(http.Dir("."))
  37. http.Handle("/", fs)
  38. log.Println("Listening on :8080...")
  39. if err := http.ListenAndServe(":8080", nil); err != nil {
  40. log.Fatal(err)
  41. }
  42. }
  43. func readFile(path string) ([]byte, error) {
  44. f, err := os.Open(path)
  45. if err != nil {
  46. return nil, err
  47. }
  48. defer f.Close()
  49. return io.ReadAll(f)
  50. }
  51. func ensureDirForFile(out string) error {
  52. dir := filepath.Dir(out)
  53. if dir == "." || dir == "/" {
  54. return nil
  55. }
  56. return os.MkdirAll(dir, 0o755)
  57. }
  58. func build(out string) error {
  59. animal, err := readFile("animal.js")
  60. if err != nil {
  61. return fmt.Errorf("read animal.js: %w", err)
  62. }
  63. layer, err := readFile("layer.js")
  64. if err != nil {
  65. return fmt.Errorf("read layer.js: %w", err)
  66. }
  67. var buf bytes.Buffer
  68. buf.WriteString("// xjs.js - combined single-file build (animal + layer)\n")
  69. buf.WriteString("// Generated by `go run main.go build`.\n")
  70. buf.WriteString("// NOTE: Do not edit this file directly in development.\n")
  71. buf.WriteString("// Edit animal.js / layer.js instead.\n\n")
  72. // Keep layer first to match previous bundled layout; runtime lookups are lazy anyway.
  73. buf.WriteString("/* --- layer.js --- */\n")
  74. buf.Write(layer)
  75. if !bytes.HasSuffix(layer, []byte("\n")) {
  76. buf.WriteByte('\n')
  77. }
  78. buf.WriteString("\n/* --- animal.js --- */\n")
  79. buf.Write(animal)
  80. if !bytes.HasSuffix(animal, []byte("\n")) {
  81. buf.WriteByte('\n')
  82. }
  83. // Export globals expected by docs/users.
  84. buf.WriteString("\n;(function(g){\n")
  85. buf.WriteString(" try { if (g && g.animal && !g.xjs) g.xjs = g.animal; } catch {}\n")
  86. buf.WriteString(" try { if (g && g.XJS_GLOBAL_DOLLAR && !g.$ && g.xjs) g.$ = g.xjs; } catch {}\n")
  87. buf.WriteString("})(typeof window !== 'undefined' ? window : (typeof globalThis !== 'undefined' ? globalThis : this));\n")
  88. if err := ensureDirForFile(out); err != nil {
  89. return fmt.Errorf("mkdir %s: %w", filepath.Dir(out), err)
  90. }
  91. if err := os.WriteFile(out, buf.Bytes(), 0o644); err != nil {
  92. return fmt.Errorf("write %s: %w", out, err)
  93. }
  94. return nil
  95. }