Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial starter kit implementation #1

Merged
merged 2 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: CD

on:
push:
branches:
- main

jobs:
publish:
name: Publish
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
- name: Setup QEMU
uses: docker/setup-qemu-action@v3

- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3

- name: Login to container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
push: true
platforms: linux/amd64,linux/arm64
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
20 changes: 19 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@ concurrency:
cancel-in-progress: true

jobs:
build:
name: Build
runs-on: ubuntu-latest

steps:
- name: Setup QEMU
uses: docker/setup-qemu-action@v3

- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v6
with:
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max

test:
name: Test
runs-on: ubuntu-latest
Expand Down Expand Up @@ -48,6 +66,6 @@ jobs:
check-latest: true

- name: Lint
uses: golangci/golangci-lint-action@v4
uses: golangci/golangci-lint-action@v6
with:
version: latest
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/cover.out
/public/styles/app.css
/tailwindcss
2 changes: 2 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
run:
timeout: 5m
45 changes: 45 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
FROM --platform=${BUILDPLATFORM} debian:stable AS cssbuilder
WORKDIR /app

RUN set -x && apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y curl

# The URL uses x64 instead of amd64
ARG BUILDARCH
RUN ARCH=$( [ "${BUILDARCH}" = "amd64" ] && echo "x64" || echo "arm64" ) && \
curl -sfLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-${ARCH}
RUN mv tailwindcss-linux-* tailwindcss
RUN chmod a+x tailwindcss

COPY tailwind.css ./
COPY tailwind.config.js ./

COPY html ./html/

RUN ./tailwindcss -i tailwind.css -o app.css --minify

FROM --platform=${BUILDPLATFORM} golang AS gobuilder
WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . ./

ARG TARGETARCH
RUN GOOS=linux GOARCH=${TARGETARCH} go build -buildvcs=false -ldflags="-s -w" -o ./app ./cmd/app

FROM debian:stable-slim AS runner
WORKDIR /app

RUN set -x && apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates && \
rm -rf /var/lib/apt/lists/*

COPY public ./public/
COPY --from=cssbuilder /app/app.css ./public/styles/
COPY --from=gobuilder /app/app ./

EXPOSE 8080

CMD ["./app"]
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
TAILWINDCSS_OS_ARCH := macos-arm64
#TAILWINDCSS_OS_ARCH := linux-x64

.PHONY: benchmark
benchmark:
go test -bench=.

.PHONY: build-css
build-css: tailwindcss
./tailwindcss -i tailwind.css -o public/styles/app.css --minify

.PHONY: build-docker
build-docker: build-css
docker build --platform linux/amd64,linux/arm64 .

.PHONY: cover
cover:
go tool cover -html=cover.out
Expand All @@ -10,7 +21,15 @@ cover:
lint:
golangci-lint run

tailwindcss:
curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-$(TAILWINDCSS_OS_ARCH)
mv tailwindcss-$(TAILWINDCSS_OS_ARCH) tailwindcss
chmod +x tailwindcss

.PHONY: test
test:
go test -coverprofile=cover.out -shuffle on ./...

.PHONY: watch-css
watch-css: tailwindcss
./tailwindcss -i tailwind.css -o public/styles/app.css --watch
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# template
# gomponents-starter-kit

[![Go](https://github.com/maragudk/template/actions/workflows/ci.yml/badge.svg)](https://github.com/maragudk/template/actions/workflows/ci.yml)
<img src="logo.png" alt="Logo" width="300" align="right">

[![GoDoc](https://pkg.go.dev/badge/github.com/maragudk/gomponents-starter-kit)](https://pkg.go.dev/github.com/maragudk/gomponents-starter-kit)
[![Go](https://github.com/maragudk/gomponents-starter-kit/actions/workflows/ci.yml/badge.svg)](https://github.com/maragudk/gomponents-starter-kit/actions/workflows/ci.yml)
[![Go](https://github.com/maragudk/gomponents-starter-kit/actions/workflows/cd.yml/badge.svg)](https://github.com/maragudk/gomponents-starter-kit/actions/workflows/cd.yml)

A starter kit for building a web app with gomponents, HTMX, and TailwindCSS in Go.

Made with ✨sparkles✨ by [maragu](https://www.maragu.dev/).

Expand Down
79 changes: 79 additions & 0 deletions cmd/app/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package main

import (
"context"
"log/slog"
"os"
"os/signal"
"syscall"

"golang.org/x/sync/errgroup"
"maragu.dev/env"

"app/http"
"app/sql"
)

func main() {
// Set up a logger that is used throughout the app
log := slog.New(slog.NewTextHandler(os.Stderr, nil))

// Start the app, exit with a non-zero exit code on errors
if err := start(log); err != nil {
log.Error("Error starting app", "error", err)
os.Exit(1)
}
}

func start(log *slog.Logger) error {
log.Info("Starting app")

// We load environment variables from .env if it exists
_ = env.Load()

// Catch signals to gracefully shut down the app
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
defer stop()

// Set up the database, which is injected as a dependency into the HTTP server
// Here, the database is just a fake one.
db := sql.NewDatabase(sql.NewDatabaseOptions{
Log: log,
})
if err := db.Connect(); err != nil {
return err
}

// Set up the HTTP server, injecting the database and logger
s := http.NewServer(http.NewServerOptions{
DB: db,
Log: log,
})

// Use an errgroup to wait for separate goroutines which can error
eg, ctx := errgroup.WithContext(ctx)

// Start the server within the errgroup.
// You can do this for other dependencies as well.
eg.Go(func() error {
return s.Start()
})

// Wait for the context to be done, which happens when a signal is caught
<-ctx.Done()
log.Info("Stopping app")

// Stop the server gracefully
eg.Go(func() error {
return s.Stop()
})

// Wait for the server to stop
if err := eg.Wait(); err != nil {
return err
}

log.Info("Stopped app")

return nil
}
14 changes: 13 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
module template
module app

go 1.23

require (
github.com/go-chi/chi/v5 v5.1.0
golang.org/x/sync v0.8.0
maragu.dev/env v0.2.0
maragu.dev/gomponents v1.0.0
maragu.dev/gomponents-htmx v0.6.1
maragu.dev/httph v0.3.3
maragu.dev/is v0.2.0
)

require github.com/mitchellh/mapstructure v1.5.0 // indirect
18 changes: 18 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/maragudk/is v0.1.0 h1:obq9anZNmOYcaNbeT0LMyjIexdNeYTw/TLAPD/BnZHA=
github.com/maragudk/is v0.1.0/go.mod h1:W/r6+TpnISu+a88OLXQy5JQGCOhXQXXLD2e5b4xMn5c=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
maragu.dev/env v0.2.0 h1:nQKitDEB65ArZsh6E7vxzodOqY9bxEVFdBg+tskS1ys=
maragu.dev/env v0.2.0/go.mod h1:t5CCbaEnjCM5mewiAVVzTS4N+oXTus2+SRnzKQbQVME=
maragu.dev/gomponents v1.0.0 h1:eeLScjq4PqP1l+r5z/GC+xXZhLHXa6RWUWGW7gSfLh4=
maragu.dev/gomponents v1.0.0/go.mod h1:oEDahza2gZoXDoDHhw8jBNgH+3UR5ni7Ur648HORydM=
maragu.dev/gomponents-htmx v0.6.1 h1:vXXOkvqEDKYxSwD1UwqmVp12YwFSuM6u8lsRn7Evyng=
maragu.dev/gomponents-htmx v0.6.1/go.mod h1:51nXX+dTGff3usM7AJvbeOcQjzjpSycod+60CYeEP/M=
maragu.dev/httph v0.3.3 h1:YfOKkqwmAJykOENmxeoCmYY+firwPEpv4aIY7gDCTsc=
maragu.dev/httph v0.3.3/go.mod h1:EaoadbqczoICEGrtKrtlb1KD6gj6m65en3Wt2OchlJ0=
maragu.dev/is v0.2.0 h1:poeuVEA5GG3vrDpGmzo2KjWtIMZmqUyvGnOB0/pemig=
maragu.dev/is v0.2.0/go.mod h1:bviaM5S0fBshCw7wuumFGTju/izopZ/Yvq4g7Klc7y8=
Loading