From 0f216f8609bf6d9907f3f7299cbddc003c50381d Mon Sep 17 00:00:00 2001 From: Rishi Mondal Date: Tue, 17 Dec 2024 01:23:32 +0530 Subject: [PATCH] feat(docs): add websocket endpoint and advanced flag documentation (#5) --- .../advanced-flag/advance-flag/index.mdx | 39 ++++ .../ForgeX/advanced-flag/docker/index.mdx | 137 ++++++++++++ .../advanced-flag/go-releaser/goreleaser.md | 40 ++++ .../advanced-flag/htmx-template/htmx-templ.md | 78 +++++++ .../advanced-flag/react-vite/react-vite.md | 211 ++++++++++++++++++ .../ForgeX/advanced-flag/tailwind/tailwind.md | 77 +++++++ .../advanced-flag/websocket/websocket.md | 32 +++ 7 files changed, 614 insertions(+) create mode 100644 contents/docs/ForgeX/advanced-flag/advance-flag/index.mdx create mode 100644 contents/docs/ForgeX/advanced-flag/docker/index.mdx create mode 100644 contents/docs/ForgeX/advanced-flag/go-releaser/goreleaser.md create mode 100644 contents/docs/ForgeX/advanced-flag/htmx-template/htmx-templ.md create mode 100644 contents/docs/ForgeX/advanced-flag/react-vite/react-vite.md create mode 100644 contents/docs/ForgeX/advanced-flag/tailwind/tailwind.md create mode 100644 contents/docs/ForgeX/advanced-flag/websocket/websocket.md diff --git a/contents/docs/ForgeX/advanced-flag/advance-flag/index.mdx b/contents/docs/ForgeX/advanced-flag/advance-flag/index.mdx new file mode 100644 index 0000000..4e3fdf1 --- /dev/null +++ b/contents/docs/ForgeX/advanced-flag/advance-flag/index.mdx @@ -0,0 +1,39 @@ +# Advanced Flag in ForgeX + +The `--advanced` flag in ForgeX serves as a switch to enable additional features during project creation. It is applied with the `create` command and unlocks the following features: + +- **HTMX Support using Templ:** Enables the integration of HTMX support for dynamic web pages using Templ. + +- **CI/CD Workflow Setup using GitHub Actions:** Automates the setup of a CI/CD workflow using GitHub Actions. + +- **Websocket Support:** WebSocket endpoint that sends continuous data streams through the WS protocol. + +- **Tailwind:** Adds Tailwind CSS support to the project. + +- **Docker:** Docker configuration for Go projects. + +- **React:** Frontend written in TypeScript, including an example fetch request to the backend. + +## Using the `--advanced` Flag + +To utilize the `--advanced` flag, use the following command: + +```bash +forgex create --name --framework --driver --advanced +``` + +By including the --advanced flag, users can choose one or all of the advanced features. The flag enhances the simplicity of ForgeX while offering flexibility for users who require additional functionality. + +## Recreating the Project Semi-Interactively +To recreate the project using the same configuration semi-interactively, use the following command: + +```bash +forgex create --name my-project --framework chi --driver mysql --advanced +``` + +## Non-Interactive Setup +Non-Interactive setup is also possible: +```bash +forgex create --name my-project --framework chi --driver mysql --advanced --feature htmx --feature githubaction --feature websocket --feature tailwind + +``` diff --git a/contents/docs/ForgeX/advanced-flag/docker/index.mdx b/contents/docs/ForgeX/advanced-flag/docker/index.mdx new file mode 100644 index 0000000..9a93b5d --- /dev/null +++ b/contents/docs/ForgeX/advanced-flag/docker/index.mdx @@ -0,0 +1,137 @@ +# Advanced Flag: Docker Configuration in ForgeX + +The Docker advanced flag provides the app's Dockerfile configuration and creates or updates the `docker-compose.yml` file, which is generated if a DB driver is used. +The Dockerfile includes a two-stage build, resulting in a smaller final image without unnecessary build dependencies. The configuration adjusts dynamically based on the advanced features selected. + +## Dockerfile + +### Standard Dockerfile + +```dockerfile +FROM golang:1.23-alpine AS build + +RUN apk add --no-cache curl + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN go install github.com/a-h/templ/cmd/templ@latest && \ + templ generate && \ + curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss && \ + chmod +x tailwindcss && \ + ./tailwindcss -i cmd/web/assets/css/input.css -o cmd/web/assets/css/output.css + +RUN go build -o main cmd/api/main.go + +FROM alpine:3.20.1 AS prod +WORKDIR /app +COPY --from=build /app/main /app/main +EXPOSE ${PORT} +CMD ["./main"] +``` + +## Dockerfile with React Flag + +```dockerfile +FROM golang:1.23-alpine AS build + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN go build -o main cmd/api/main.go + +FROM alpine:3.20.1 AS prod +WORKDIR /app +COPY --from=build /app/main /app/main +EXPOSE ${PORT} +CMD ["./main"] + +FROM node:20 AS frontend_builder +WORKDIR /frontend + +COPY frontend/package*.json ./ +RUN npm install +COPY frontend/. . +RUN npm run build + +FROM node:20-slim AS frontend +RUN npm install -g serve +COPY --from=frontend_builder /frontend/dist /app/dist +EXPOSE 5173 +CMD ["serve", "-s", "/app/dist", "-l", "5173"] +``` + +## Docker Compose +docker-compose.yml pulls environment variables from the .env file. Below is an example configuration if the Docker flag is used with the MySQL DB driver: + +```dockerfile +services: + app: + build: + context: . + dockerfile: Dockerfile + target: prod + restart: unless-stopped + ports: + - ${PORT}:${PORT} + environment: + APP_ENV: ${APP_ENV} + PORT: ${PORT} + FORGEX_DB_HOST: ${FORGEX_DB_HOST} + FORGEX_DB_PORT: ${FORGEX_DB_PORT} + FORGEX_DB_DATABASE: ${FORGEX_DB_DATABASE} + FORGEX_DB_USERNAME: ${FORGEX_DB_USERNAME} + FORGEX_DB_PASSWORD: ${FORGEX_DB_PASSWORD} + depends_on: + mysql_fx: + condition: service_healthy + networks: + - forgex + mysql_fx: + image: mysql:latest + restart: unless-stopped + environment: + MYSQL_DATABASE: ${FORGEX_DB_DATABASE} + MYSQL_USER: ${FORGEX_DB_USERNAME} + MYSQL_PASSWORD: ${FORGEX_DB_PASSWORD} + MYSQL_ROOT_PASSWORD: ${FORGEX_DB_ROOT_PASSWORD} + ports: + - "${FORGEX_DB_PORT}:3306" + volumes: + - mysql_volume_fx:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "${FORGEX_DB_HOST}", "-u", "${FORGEX_DB_USERNAME}", "--password=${FORGEX_DB_PASSWORD}"] + interval: 5s + timeout: 5s + retries: 3 + start_period: 15s + networks: + - forgex + +volumes: + mysql_volume_fx: +networks: + forgex: +``` +## Notes +Cleaning Docker Leftovers +If you are testing multiple frameworks locally, ensure to clean up Docker leftovers such as volumes. Use the following commands: + +```dockerfile +docker compose down --volumes +docker compose up --build +``` + +or + +```bash +docker compose build --no-cache && docker compose up +``` diff --git a/contents/docs/ForgeX/advanced-flag/go-releaser/goreleaser.md b/contents/docs/ForgeX/advanced-flag/go-releaser/goreleaser.md new file mode 100644 index 0000000..43f1f2c --- /dev/null +++ b/contents/docs/ForgeX/advanced-flag/go-releaser/goreleaser.md @@ -0,0 +1,40 @@ +Release process for Go projects, providing extensive customization options through its configuration file, `.goreleaser.yml`. By default, it ensures dependency cleanliness, builds binaries for various platforms and architectures, facilitates pre-release creation, and organizes binary packaging into archives with naming schemes. + +For comprehensive insights into customization possibilities, refer to the [GoReleaser documentation](https://goreleaser.com/customization/). + +## Usage with Tags + +To initiate release builds with GoReleaser, you need to follow these steps: + +- **Tag Creation:** + When your project is ready for a release, create a new tag in your Git repository. For example: +```bash +git tag v1.0.0 +``` + +- **Tag Pushing:** + Push the tag to the repository to trigger GoReleaser: +```bash +git push origin v1.0.0 +``` + +Following these steps ensures proper tagging of your project, prompting GoReleaser to execute configured releases. This approach simplifies release management and automates artifact distribution. + +## Go Test - Continuous Integration for Go Projects + +The `go-test.yml` file defines a GitHub Actions workflow for continuous integration (CI) of Go projects within a GitHub repository. + +## Workflow Steps + +The job outlined in this workflow includes the following steps: + +1. **Checkout:** + Fetches the project's codebase from the repository. + +2. **Go Setup:** + Configures the Go environment with version 1.21.x. + +3. **Build and Test:** + Builds the project using `go build` and runs tests across all packages (`./...`) using `go test`. + +This workflow serves to automate the testing process of a Go project within a GitHub repository, ensuring code quality and reliability with each commit and pull request. diff --git a/contents/docs/ForgeX/advanced-flag/htmx-template/htmx-templ.md b/contents/docs/ForgeX/advanced-flag/htmx-template/htmx-templ.md new file mode 100644 index 0000000..a1a6149 --- /dev/null +++ b/contents/docs/ForgeX/advanced-flag/htmx-template/htmx-templ.md @@ -0,0 +1,78 @@ +The WEB directory contains the web-related components and assets for the project. It leverages [htmx](https://github.com/bigskysoftware/htmx) and [templ](https://github.com/a-h/templ) in Go for dynamic web content generation. + +## Structure + +``` +web/ +│ +│ +├── assets/ +│ └── js/ +│ └── htmx.min.js # htmx library for dynamic HTML content +│ +├── base.templ # Base template for HTML structure +├── base_templ.go # Generated Go code for base template +├── efs.go # Embeds static files into the Go binary +│ +├── hello.go # Handler for the Hello Web functionality +├── hello.templ # Template for rendering the Hello form and post data +└── hello_templ.go # Generated Go code for hello template +``` + +## Usage + +- **Navigate to Project Directory:** +```bash +cd my-project +``` + +- **Install Templ CLI:** +```bash +go install github.com/a-h/templ/cmd/templ@latest +``` + +- **Generate Templ Function Files:** +```bash +templ generate +``` + +- **Start Server:** +```bash +make run +``` + +## Makefile + +Automates templ with Makefile entries, which are automatically created if the htmx advanced flag is used. +It detects if templ is installed or not and generates templates with the make build command. +Both Windows and Unix-like OS are supported. + +```bash +all: build + +templ-install: + @if ! command -v templ > /dev/null; then \ + read -p "Go's 'templ' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/a-h/templ/cmd/templ@latest; \ + if [ ! -x "$$(command -v templ)" ]; then \ + echo "templ installation failed. Exiting..."; \ + exit 1; \ + fi; \ + else \ + echo "You chose not to install templ. Exiting..."; \ + exit 1; \ + fi; \ + fi + +build: templ-install + @echo "Building..." + @templ generate + @go build -o main cmd/api/main.go +``` + +## Templating + +Templates are generated using the `templ generate` command after project creation. These templates are then compiled into Go code for efficient execution. + +You can test HTMX functionality on `localhost:PORT/web` endpoint. diff --git a/contents/docs/ForgeX/advanced-flag/react-vite/react-vite.md b/contents/docs/ForgeX/advanced-flag/react-vite/react-vite.md new file mode 100644 index 0000000..b79cc27 --- /dev/null +++ b/contents/docs/ForgeX/advanced-flag/react-vite/react-vite.md @@ -0,0 +1,211 @@ +This template provides a minimal setup for getting React working with Vite for the frontend and go on the backend. It allows you to easily integrate React with Tailwind CSS and Vite for fast development. + +The React advanced flag can be combined with the Tailwind flag for enhanced styling capabilities. + +## Project Structure + +```bash +/ (Root) +├── frontend/ # React advanced flag. Excludes HTMX. +│ ├── node_modules/ # Node dependencies. +│ ├── public/ +│ │ ├── index.html +│ │ └── favicon.ico +│ ├── src/ # React source files. +│ │ ├── App.tsx # Main React component. +│ │ ├── assets/ # React assets directory +│ │ │ └── logo.svg +│ │ ├── components/ # React components directory. +│ │ │ ├── Header.tsx +│ │ │ └── Footer.tsx +│ │ ├── styles/ # CSS/SCSS styles directory. +│ │ │ └── global.css +│ │ └── index.tsx # Main entry point for React +│ ├── eslint.config.js # ESLint configuration file. +│ ├── index.html # Base HTML template. +│ ├── package.json # Node.js package configuration. +│ ├── package-lock.json # Lock file for Node.js dependencies. +│ ├── README.md # README file for the React project. +│ ├── tsconfig.app.json # TypeScript configuration for the app. +│ ├── tsconfig.json # Root TypeScript configuration. +│ ├── tsconfig.node.json # TypeScript configuration for Node.js. +│ └── vite.config.ts # Vite configuration file. +``` + +## Usage + +- **Navigate to the `frontend` directory**: + First, navigate to the `frontend` directory where the React project resides. + +```bash +cd frontend +``` + +- **Install Dependencies**: + Use npm to install all necessary dependencies. + +```bash +npm install +``` + +- **Run the Development Server**: + Start the Vite development server for local development. This will launch a live-reloading server on a default port. + +```bash +npm run dev +``` + + You should now be able to access the React application by opening a browser and navigating to `http://localhost:5173`. + + +You can extend the `vite.config.ts` to include additional configurations as needed, such as adding plugins for optimizing the build process, enabling TypeScript support, or configuring Tailwind CSS. + +## Makefile + +The make run target will start the Go server in the backend, install frontend dependencies, and run the Vite development server for the frontend. + +```bash +run: + @go run cmd/api/main.go & + @npm install --prefix ./frontend + @npm run dev --prefix ./frontend +``` + +After running this command, you can verify the connection between the frontend and backend by checking the console. You can also fetch data from the backend to test the integration. + +![React](../public/react.png) + +## Dockerfile + +Combine React advanced flag wiht Docker flag to get Docker and docker-compose configuration and run them with: + +```bash +make docker-run +``` + +### Dockerfile + +```dockerfile +FROM golang:1.23-alpine AS build + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN go build -o main cmd/api/main.go + +FROM alpine:3.20.1 AS prod +WORKDIR /app +COPY --from=build /app/main /app/main +EXPOSE ${PORT} +CMD ["./main"] + + +FROM node:20 AS frontend_builder +WORKDIR /frontend + +COPY frontend/package*.json ./ +RUN npm install +COPY frontend/. . +RUN npm run build + +FROM node:20-slim AS frontend +RUN npm install -g serve +COPY --from=frontend_builder /frontend/dist /app/dist +EXPOSE 5173 +CMD ["serve", "-s", "/app/dist", "-l", "5173"] +``` + +### Docker compose without db + +```yaml +services: + app: + build: + context: . + dockerfile: Dockerfile + target: prod + restart: unless-stopped + ports: + - ${PORT}:${PORT} + environment: + APP_ENV: ${APP_ENV} + PORT: ${PORT} + frontend: + build: + context: . + dockerfile: Dockerfile + target: frontend + restart: unless-stopped + ports: + - 5173:5173 + depends_on: + - app +``` + +### Docker compose with db + +```yaml +services: + app: + build: + context: . + dockerfile: Dockerfile + target: prod + restart: unless-stopped + ports: + - ${PORT}:${PORT} + environment: + APP_ENV: ${APP_ENV} + PORT: ${PORT} + BLUEPRINT_DB_HOST: ${BLUEPRINT_DB_HOST} + BLUEPRINT_DB_PORT: ${BLUEPRINT_DB_PORT} + BLUEPRINT_DB_DATABASE: ${BLUEPRINT_DB_DATABASE} + BLUEPRINT_DB_USERNAME: ${BLUEPRINT_DB_USERNAME} + BLUEPRINT_DB_PASSWORD: ${BLUEPRINT_DB_PASSWORD} + BLUEPRINT_DB_SCHEMA: ${BLUEPRINT_DB_SCHEMA} + depends_on: + psql_bp: + condition: service_healthy + networks: + - blueprint + frontend: + build: + context: . + dockerfile: Dockerfile + target: frontend + restart: unless-stopped + depends_on: + - app + ports: + - 5173:5173 + networks: + - blueprint + psql_bp: + image: postgres:latest + restart: unless-stopped + environment: + POSTGRES_DB: ${BLUEPRINT_DB_DATABASE} + POSTGRES_USER: ${BLUEPRINT_DB_USERNAME} + POSTGRES_PASSWORD: ${BLUEPRINT_DB_PASSWORD} + ports: + - "${BLUEPRINT_DB_PORT}:5432" + volumes: + - psql_volume_bp:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "sh -c 'pg_isready -U ${BLUEPRINT_DB_USERNAME} -d ${BLUEPRINT_DB_DATABASE}'"] + interval: 5s + timeout: 5s + retries: 3 + start_period: 15s + networks: + - blueprint + +volumes: + psql_volume_bp: +networks: + blueprint: +``` diff --git a/contents/docs/ForgeX/advanced-flag/tailwind/tailwind.md b/contents/docs/ForgeX/advanced-flag/tailwind/tailwind.md new file mode 100644 index 0000000..ea60875 --- /dev/null +++ b/contents/docs/ForgeX/advanced-flag/tailwind/tailwind.md @@ -0,0 +1,77 @@ +Tailwind is closely coupled with the advanced HTMX flag, and HTMX will be automatically used if you select Tailwind in your project. + +We do not introduce outside dependencies automatically, and you need compile output.css (file is empty by default) with the Tailwind CLI tool. + +The project tree would look like this: +```bash +/ (Root) +├── cmd/ +│ ├── api/ +│ │ └── main.go +│ └── web/ +│ ├── assets/ +│ │ ├── css/ +│ │ │ ├── input.css +│ │ │ └── output.css +│ │ └── js/ +│ │ └── htmx.min.js +│ ├── base.templ +│ ├── base_templ.go +│ ├── efs.go +│ ├── hello.go +│ ├── hello.templ +│ └── hello_templ.go +├── internal/ +│ └── server/ +│ ├── routes.go +│ ├── routes_test.go +│ └── server.go +├── go.mod +├── go.sum +├── Makefile +├── README.md +└── tailwind.config.js +``` + +## Standalone Tailwind CLI + +The The idea is to avoid using Node.js and npm to build output.css. + +The Makefile will have entries for downloading and compiling CSS. It will automatically detect the OS and download the latest release from the [official repository](https://github.com/tailwindlabs/tailwindcss/releases). + +## Linux Makefile Example +```bash +all: build +templ-install: + @if ! command -v templ > /dev/null; then \ + read -p "Go's 'templ' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/a-h/templ/cmd/templ@latest; \ + if [ ! -x "$$(command -v templ)" ]; then \ + echo "templ installation failed. Exiting..."; \ + exit 1; \ + fi; \ + else \ + echo "You chose not to install templ. Exiting..."; \ + exit 1; \ + fi; \ + fi + +tailwind-install: + @if [ ! -f tailwindcss ]; then curl -sL https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 -o tailwindcss; fi + @chmod +x tailwindcss + +build: tailwind-install templ-install + @echo "Building..." + @templ generate + @./tailwindcss -i cmd/web/assets/css/input.css -o cmd/web/assets/css/output.css + @go build -o main cmd/api/main.go +``` + +## Use Tailwind CSS in your project + +By default, simple CSS examples are included in the codebase. +Update base.templ and hello.templ, then rerun templ generate to see the changes at the `localhost:PORT/web` endpoint. + +![Tailwind](../public/tailwind.png) + diff --git a/contents/docs/ForgeX/advanced-flag/websocket/websocket.md b/contents/docs/ForgeX/advanced-flag/websocket/websocket.md new file mode 100644 index 0000000..c7bea3a --- /dev/null +++ b/contents/docs/ForgeX/advanced-flag/websocket/websocket.md @@ -0,0 +1,32 @@ +A `/websocket` endpoint is added in `routes.go` to facilitate websocket connections. Upon accessing this endpoint, the server establishes a websocket connection and begins transmitting timestamp messages at 2-second intervals. WS is utilized across all Go-blueprint supported frameworks. This simple implementation showcases how flexible project is. + +### Code Implementation + +```go +func (s *Server) websocketHandler(c *gin.Context) { + w := c.Writer + r := c.Request + socket, err := websocket.Accept(w, r, nil) + + if err != nil { + log.Printf("could not open websocket: %v", err) + _, _ = w.Write([]byte("could not open websocket")) + w.WriteHeader(http.StatusInternalServerError) + return + } + + defer socket.Close(websocket.StatusGoingAway, "server closing websocket") + + ctx := r.Context() + socketCtx := socket.CloseRead(ctx) + + for { + payload := fmt.Sprintf("server timestamp: %d", time.Now().UnixNano()) + err := socket.Write(socketCtx, websocket.MessageText, []byte(payload)) + if err != nil { + break + } + time.Sleep(time.Second * 2) + } +} +```