gitstack

grindlemire/gothem-stack code browser

2.9 KB Go 128 lines 2025-01-11 · 04d4ded raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package main

import (
	"context"
	"io"
	"os"
	"strings"

	"github.com/grindlemire/gothem-stack/magefiles/cmd"
	"github.com/grindlemire/gothem-stack/web/pages/home"

	"github.com/magefile/mage/mg"
	"github.com/pkg/errors"
	"go.uber.org/zap"
)

func build(ctx context.Context) error {
	config, err := GetConfig(ctx)
	if err != nil {
		return err
	}
	zap.S().Infof("mage running with configs: %+v", config)

	// Run dependencies in order
	mg.SerialCtxDeps(ctx, tidy, templ)

	// Ensure dist directory exists
	if err := os.MkdirAll("dist", 0755); err != nil {
		return errors.Wrap(err, "creating dist directory")
	}

	// Clean previous build
	if err := cmd.Run(ctx, cmd.WithCMD("rm", "-f", "dist/server")); err != nil {
		return errors.Wrap(err, "cleaning previous build")
	}

	// Build the server
	err = cmd.Run(ctx,
		cmd.WithCMD(
			"go",
			"build",
			"-o", "dist/server",
			"cmd/main.go",
		),
	)
	if err != nil {
		return errors.Wrap(err, "building server")
	}

	// Copy static assets to dist
	if err := generateStaticAssets(ctx); err != nil {
		return errors.Wrap(err, "handling static assets")
	}

	zap.S().Info("Build completed successfully")
	return nil
}

// generateStaticAssets generates CSS and copies static files to dist
func generateStaticAssets(ctx context.Context) error {
	// Generate CSS using TailwindCSS
	err := cmd.Run(ctx,
		cmd.WithDir("./web"),
		cmd.WithCMD(
			"node_modules/.bin/tailwindcss",
			"-i", "tailwind.css",
			"-o", "public/styles.min.css",
		),
	)
	if err != nil {
		return errors.Wrap(err, "generating CSS")
	}

	// Create dist/public/dist directory
	if err := os.MkdirAll("dist/public/dist", 0755); err != nil {
		return errors.Wrap(err, "creating dist/public/dist directory")
	}

	// Generate the static HTML
	if err := generateHTML("dist/public/index.html"); err != nil {
		return errors.Wrap(err, "generating HTML")
	}

	// Copy static assets
	files := map[string]string{
		"./web/public/favicon.ico":    "dist/public/dist/favicon.ico",
		"./web/public/styles.min.css": "dist/public/dist/styles.min.css",
	}

	for src, dst := range files {
		if err := copyFile(src, dst); err != nil {
			return errors.Wrapf(err, "copying %s to %s", src, dst)
		}
	}

	return nil
}

// generateHTML renders the home page and writes it to the specified path
func generateHTML(outputPath string) error {
	var s strings.Builder
	if err := home.Page().Render(context.Background(), &s); err != nil {
		return errors.Wrap(err, "rendering static page")
	}

	if err := os.WriteFile(outputPath, []byte(s.String()), 0644); err != nil {
		return errors.Wrap(err, "writing HTML to file")
	}

	return nil
}

func copyFile(src, dst string) error {
	source, err := os.Open(src)
	if err != nil {
		return errors.Wrapf(err, "opening source file %s", src)
	}
	defer source.Close()

	destination, err := os.Create(dst)
	if err != nil {
		return errors.Wrapf(err, "creating destination file %s", dst)
	}
	defer destination.Close()

	_, err = io.Copy(destination, source)
	return err
}