with open(r"E:\GitHub\blog\write-go\cmd\writeserver\main.go", "r", encoding="utf-8", errors="replace") as f: content = f.read() # Find the root handler and replace it with a reverse proxy to Next.js # Remove the embedded HTML page approach, replace with reverse proxy # 1. Remove the embed directive content = content.replace('\n//go:embed admin_page.html\nvar adminPageHTML string\n', '\n') content = content.replace('//go:embed admin_page.html\nvar adminPageHTML string\n', '\n') # 2. Remove _ "embed" from imports content = content.replace('\t_ "embed"\n\t"net"\n', '\t"net"\n') content = content.replace('\t_ "embed"\n\t"log/slog"\n', '\t"log/slog"\n') # 3. Add net/http/httputil and net/url for reverse proxy content = content.replace( '\t"net/http"\n', '\t"net/http"\n\t"net/http/httputil"\n\t"net/url"\n' ) # 4. Replace the root handler with reverse proxy old_root = ''' // Root page - admin dashboard mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(404) w.Write([]byte("{\"error\":\"not found\"}")) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Write([]byte(adminPageHTML)) })''' new_root = ''' // Root and non-API routes -> reverse proxy to Next.js (localhost:3000) nextURL, _ := url.Parse("http://localhost:3000") proxy := httputil.NewSingleHostReverseProxy(nextURL) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/api/") { // Let API handlers deal with it http.NotFound(w, r) return } proxy.ServeHTTP(w, r) })''' content = content.replace(old_root, new_root) # 5. Add Next.js auto-start goroutine old_goroutine = 'go autoStartBot()' new_goroutine = '''go autoStartBot() go autoStartNextJS()''' content = content.replace(old_goroutine, new_goroutine) # 6. Add the autoStartNextJS function before the last } old_end = '\n\taddr := fmt.Sprintf("0.0.0.0:%d", port)' new_end = ''' // autoStartNextJS starts Next.js if not running func autoStartNextJS() { time.Sleep(1 * time.Second) // Check if Next.js is already running if _, err := net.DialTimeout("tcp", "127.0.0.1:3000", 2*time.Second); err == nil { lg.Info("Next.js already running on :3000") return } lg.Info("starting Next.js frontend") cmd := exec.Command("npx.cmd", "next", "start", "-p", "3000") cmd.Dir = filepath.Join(config.BLOG_ROOT, "write") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Start(); err != nil { lg.Warn("failed to start Next.js", "err", err) } else { lg.Info("Next.js started", "pid", cmd.Process.Pid) } } addr := fmt.Sprintf("0.0.0.0:%d", port)' content = content.replace(old_end, new_end) with open(r"E:\GitHub\blog\write-go\cmd\writeserver\main.go", "w", encoding="utf-8", errors="replace") as f: f.write(content) print("Done")