Edward's Tech Site

this site made with Next.js 13, see the code

HOWTO: Mar 29 - Go
Set up Go scripting CLI in a Vite React site to speed up development
  • this howto is for you if
    • you have never used Go and are looking for a pragmatic way to use it in your projects
    • want to create command line tools that speed up your development, e.g. scripts like Angular's ng generate component component-name, but for your own projects
  • what we will build
    • we will start with a React site that reads a JSON file of flashcards
    • and change it so that we can update a simpler text file of flashcards which we parse into JSON with an npm command that executes a Go script
  • what we will do
    • we will set up a Vite React site that shows flashcards from data in a JSON file
    • we will set up Go so that we can run an npm script which parses a text file into the JSON file
    • note that the idea here is not to use Go to create an API
      • but to run scripts that e.g. create or alter JSON and.tsx files, etc.
      • this is the idea of Datapod, to be able to execute scripts that help you code faster
        • this is somewhat like in Angular the command to create a component: ng generate component component-name
    • this howto the first steps in building a Datapod called "Datapod for React/Go/JSON"
      • so what we do is realistic
      • but the steps in this howto are just enough to get up and running with Go scripts that can be executed from the command line
        • which is useful in any project if you want to quickly make automated tasks
        • and you will quickly find that Go is a pleasant language to work in: simple and pragmatic
      • of course a further concept of Datapod is that eventually I will build a backend which in turn allows the frontend to execute these commands
        • this will allow e.g. a developer to fill out a form and click a button in the frontend in order to (1) create a page, (2) parse data, etc.
  • code is here
  • live-coding video of this howto is here
  • >>> 1. install Go, clone the React site, and create two npm scripts which each run a test Go script
    • install Go: ../installhttps://go.dev/doc/install
    • create a Vite React site by creating a repo with this template and cloning it locally: ../datapod-for-react-jsonhttps://github.com/edwardtanguay/datapod-for-react-json
    • in root, create "scripts" directory
    • in the bash shell, go into that scripts directory
    • go mod init github.com/edwardtanguay/datapod-for-react-go-json
      • change this to a GitHub name in your control and the name of your project: "github.com/yourname/yourproject"
      • this will create a go.mod file
    • now create these directories and files:
    • /scripts/cmd/create-page/main.go
      • package main
         
        import "fmt"
         
        func main() {
        fmt.Println("this will create a new page in the app")
        }
    • /scripts/cmd/parse-data/main.go
      • package main
         
        import "fmt"
         
        func main() {
        fmt.Println("this will parse data in a text file into a JSON file")
        }
    • in package.json, add these two npm script commands to run these Go commands
      • "cp": "cd scripts/cmd/create-page && go run .",
        "pd": "cd scripts/cmd/parse-data && go run .",
    • note that these commands change into the directory first, then run the script from there
      • this will be important when we import functions from with relative paths later
    • execute the npm commands from the command line
      • npm run cp
      • npm run pd
  • >>> 2. start React site and create text flashcard file
    • start React site
      • npm i
      • npm run dev
    • note that the flashcards showing on the Welcome page are being loaded from the /datajson/flashcards.json file
    • create /data/flashcards.txt
      • it
        and it will take some time
        e ci vorrà del tempo
         
        it
        this will ensure that you get
        cìo garantirà di ottenere
         
        es
        this has certain advantages
        est tiene ciertas ventajas
         
        es
        in such a way that
        de tal manera que
    • we will now program the parse-data script so that it parses this text file flashcard objects, and then overwrites the flashcards.json file with this new data
  • >>> 3. set up utilities that can be used by any command
    • we have two scripts, create-page and parse-data, that we want to program
    • and in my Datapod there will be many more scripts, e.g. create-component, delete-page, etc.
    • all of these scripts should be able to use a common library of tools
      • this is what we are going to set up now
    • create this folder and files
    • debug.go
      • package utils
         
        import "fmt"
         
        /*
        Output information in console in a uniform way
         
        devlog("no files are locked")
         
        devlog(fmt.Sprintf("There are %d flashcards.", len(flashcards)))
        */
        func Devlog(line string) {
        fmt.Printf("DEBUG ### %s ################################\n", line)
        }
    • files.go
      • package utils
         
        import (
        "os"
        "strings"
        )
         
        /*
        Get all lines from a file as a slice of strings
         
        lines := getLinesFromFile("../../notes.txt")
         
        use relative path
        */
        func GetLinesFromFile(fileName string) []string {
        byteContents, err := os.ReadFile(fileName)
        if err != nil {
        panic(err)
        }
        contents := string(byteContents)
        lines := strings.Split(contents, "\n")
        for i, line := range lines {
        lines[i] = strings.TrimSpace(line)
        }
        return lines
        }
    • note that the funtions Devlog and GetLinesFromFile are both capitalized
      • this is important in Go in order for them to be imported from other files
    • in the create-page script, let's use the debug function
    • create-page/main.go
      • package main
         
        import (
        "datapod-for-react-go-json/utils"
        )
         
        func main() {
        utils.Devlog("this will create a page")
        }
    • watch how the Trae editor works with Go to give you an easy developer experience of importing what you need:
      • this should also work in VSCode or Cursor
    • notice also that the /*...*/ comment block above your utility functions will show up in these editors as well, which gives you context-related help on the functions you are using
    • now let's use the file utility function in the parse-data script
    • parse-data/main.go
      • package main
         
        import (
        "datapod-for-react-go-json/utils"
        "fmt"
        )
         
        func main() {
        utils.Devlog("this shows the lines of the text file")
        lines := utils.GetLinesFromFile("../../../data/flashcards.txt")
        for i, line := range lines {
        fmt.Printf("%03d: %s\n", i+1, line)
        }
        }
    • execute the command: npm run pd
  • >>> 4. program the parse-data script to convert the text file of flashcards into JSON
    • first we need a utils function to create a random suuid
      • utils/general.go
        • package utils
           
          import (
          "crypto/rand"
          "math/big"
          )
           
          /*
          Return a random suuid (short uuid = 6 characters)
           
          suuid := GenerateShortUUID()
           
          returns e.g. "q35HZa"
          */
          func GenerateShortUUID() string {
          const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
          const length = 6
          bytes := make([]byte, length)
          for i := 0; i < length; i++ {
          randomByte, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
          if err != nil {
          panic(err)
          }
          bytes[i] = charset[randomByte.Int64()]
          }
          return string(bytes)
          }
    • then let's completely rewrite the parse-data code to create flashcards.json based on flashcards.txt
      • parse-data/main.go
        • package main
           
          import (
          "datapod-for-react-go-json/utils"
          "encoding/json"
          "fmt"
          "os"
          "strings"
          )
           
          type Flashcard struct {
          Suuid string `json:"suuid"`
          Category string `json:"category"`
          Front string `json:"front"`
          Back string `json:"back"`
          }
           
          func main() {
          fmt.Println("parsing flashcards.txt into flashcards.json...")
          lines := utils.GetLinesFromFile("../../../data/flashcards.txt")
           
          var flashcards []Flashcard
          for i := 0; i < len(lines); i += 4 {
          if i+3 > len(lines) {
          break
          }
          category := strings.TrimSpace(lines[i])
          front := strings.TrimSpace(lines[i+1])
          back := strings.TrimSpace(lines[i+2])
           
          flashcards = append(flashcards, Flashcard{
          Suuid: utils.GenerateShortUUID(),
          Category: category,
          Front: front,
          Back: back,
          })
          }
           
          jsonData, err := json.MarshalIndent(flashcards, "", "\t")
          if err != nil {
          fmt.Printf("Error marshaling JSON: %v\n", err)
          return
          }
           
          err = os.WriteFile("../../../datajson/flashcards.json", jsonData, 0644)
          if err != nil {
          fmt.Printf("Error writing JSON file: %v\n", err)
          return
          }
           
          fmt.Println("successfully updated flashcards.json")
          }
    • now when you add a flashcard to flashcards.txt and run the npm run pd command, a new flashcard will appear on your site
  • >>> 5. next steps
    • my next steps will be to program the "create page" commmand, which will create a file and change two files
      • but that is a bit involved for this howto which was just to show how to set everything up and organize your directories and files
      • creating more commands is more of the same coding that we did for the parse-data command
    • I hope this howto got you working with Go in a pragmatic way, creating scripts that help speed up your development