# Go & ViteJS ## Go - Go, linguaggio di programmazione compilato, _statically typed_ e con una libreria standard con tutte le cose essenziali. - Ideale per scrivere server HTTP. ## ViteJS > - On demand file serving over native ESM, no bundling required! > - **Hot Module Replacement** (HMR) that stays fast regardless of app size. > - Out-of-the-box support for **TypeScript**, **JSX**, **CSS** and more. > - Pre-configured **Rollup** build with **multi-page** and library mode support. > - Rollup-superset plugin interface shared between dev and build. > - Flexible programmatic APIs with full TypeScript typing. _Documentazione di ViteJS_ --- # Creazione progetto in Golang Inizializziamo il progetto in Go per la backend ```bash # inizializziamo il file go.mod $ go mod init gdg-talk-counter # o anche così... $ go mod init github.com/aziis98/gdg-talk-counter ``` # Creazione progetto in ViteJS Ed il progetto in ViteJS per la frontend ```bash $ npm init # creates the "package.json" file $ npm install -D vite ``` (o anche con un altro package manager alternativo a npm, ad esempio io userò `pnpm`) --- # Il file "package.json" ```json { ... "scripts": { "dev": "vite", // avvia il server di ViteJS in modalità di development "build": "vite build" // crea la cartella "dist/" con tutti gli asset e bundle }, ... } ``` ```bash $ npm run dev $ npm run build ``` --- # Il file "src/main.go" Impostiamo un piccolo server sulla porta `:4000` per servire gli asset e l'API ```go package main ... func main() { mux := http.NewServeMux() setupRoutes(mux) // vedremo meglio questo in seguito server := http.Server{ Addr: ":4000", Handler: mux, } log.Fatal(server.ListenAndServe()) } ``` --- # Configurazione di ViteJS ```js // vite.config.js import { defineConfig } from 'vite' export default defineConfig({ server: { port: 3000, proxy: { '/api': 'http://localhost:4000/', }, }, }) ``` --- # ViteJS come proxy per il server in Go **Development:** ``` ~~~graph-easy --as=boxart [ The developer ] -- :3000 --> [ Dev. Server ] ~~~ ~~~graph-easy --as=boxart [ The developer ] -- :3000/api/... --> [ Dev. Server ] -- :4000/api/... --> [ Backend ] ~~~ ``` **Production:** ``` ~~~graph-easy --as=boxart [ The user ] -- :4000 --> [ Backend ] ~~~ ``` --- # Il file "index.html" ```html GDG Talk Counter

GDG Talk Counter

Carico...
``` --- # Inizializzazione della frontend (VanillaJS) ```js function mountApp($root) { const $counter = $root.querySelector('.counter') const $btnIncrement = $root.querySelector('#btn-increment') const Counter = mountCounter($counter) $btnIncrement.addEventListener('click', async () => { Counter.increment() }) setInterval(async () => { Counter.refresh() }, 1000) } mountApp(document.body) ``` --- # Codice per il contatore ```js import { fetchJSON } from './utils.js' function mountCounter($counter) { function render(count) { $counter.textContent = `Contatore: ${count}` } async function refresh() { const count = await fetchJSON('/api/counter') render(count) } async function increment() { const count = await fetchJSON('/api/increment', { method: 'POST' }) render(count) } refresh() return { refresh, increment } } ``` --- # Tornando alla backend ```go func setupRoutes(mux *http.ServeMux) { // The database counter := 0 // GET /api/status mux.HandleFunc("/api/status", func(w http.ResponseWriter, r *http.Request) { ... }) // GET /api/counter mux.HandleFunc("/api/counter", func(w http.ResponseWriter, r *http.Request) { ... }) // POST /api/increment mux.HandleFunc("/api/increment", func(w http.ResponseWriter, r *http.Request) { ... }) // Static Files mux.Handle("/", http.FileServer((http.Dir("./dist/")))) } ``` --- # La route `GET /api/status` ```go type object map[string]any mux.HandleFunc("/api/status", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(&object{ "status": "ok" }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } }) ``` ```go mux.HandleFunc("/api/value", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(counter) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } }) ```