gen code for assets (#68)

* gen code for assets

* fix

* test
This commit is contained in:
maddalax 2024-11-01 06:10:35 -05:00 committed by GitHub
parent 4c6187e18d
commit 2c4ac8b286
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 136 additions and 26 deletions

View file

@ -9,10 +9,12 @@ import (
"go/parser"
"go/token"
"golang.org/x/mod/modfile"
"io/fs"
"os"
"path/filepath"
"slices"
"strings"
"unicode"
)
type Page struct {
@ -37,6 +39,32 @@ const ModuleName = "github.com/maddalax/htmgo/framework/h"
var PackageName = fmt.Sprintf("package %s", GeneratedDirName)
var GeneratedFileLine = fmt.Sprintf("// Package %s THIS FILE IS GENERATED. DO NOT EDIT.", GeneratedDirName)
func toPascaleCase(input string) string {
words := strings.Split(input, "_")
for i := range words {
words[i] = strings.Title(strings.ToLower(words[i]))
}
return strings.Join(words, "")
}
func isValidGoVariableName(name string) bool {
// Variable name must not be empty
if name == "" {
return false
}
// First character must be a letter or underscore
if !unicode.IsLetter(rune(name[0])) && name[0] != '_' {
return false
}
// Remaining characters must be letters, digits, or underscores
for _, char := range name[1:] {
if !unicode.IsLetter(char) && !unicode.IsDigit(char) && char != '_' {
return false
}
}
return true
}
func normalizePath(path string) string {
return strings.ReplaceAll(path, `\`, "/")
}
@ -390,6 +418,63 @@ func writePagesFile() {
})
}
func writeAssetsFile() {
cwd := process.GetWorkingDir()
config := dirutil.GetConfig()
distAssets := filepath.Join(cwd, "assets", "dist")
hasAssets := false
builder := strings.Builder{}
builder.WriteString(`package assets`)
builder.WriteString("\n")
filepath.WalkDir(distAssets, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
if strings.HasPrefix(d.Name(), ".") {
return nil
}
path = strings.ReplaceAll(path, distAssets, "")
httpUrl := fmt.Sprintf("%s%s", config.PublicAssetPath, path)
path = normalizePath(path)
path = strings.ReplaceAll(path, "/", "_")
path = strings.ReplaceAll(path, "//", "_")
name := strings.ReplaceAll(path, ".", "_")
name = strings.ReplaceAll(name, "-", "_")
name = toPascaleCase(name)
if isValidGoVariableName(name) {
builder.WriteString(fmt.Sprintf(`const %s = "%s"`, name, httpUrl))
builder.WriteString("\n")
hasAssets = true
}
return nil
})
builder.WriteString("\n")
str := builder.String()
if hasAssets {
WriteFile(filepath.Join(GeneratedDirName, "assets", "assets-generated.go"), func(content *ast.File) string {
return str
})
}
}
func GetModuleName() string {
wd := process.GetWorkingDir()
modPath := filepath.Join(wd, "go.mod")
@ -411,6 +496,7 @@ func GenAst(flags ...process.RunFlag) error {
}
writePartialsFile()
writePagesFile()
writeAssetsFile()
WriteFile("__htmgo/setup-generated.go", func(content *ast.File) string {

View file

@ -14,6 +14,7 @@ type ProjectConfig struct {
WatchFiles []string `yaml:"watch_files"`
AutomaticPageRoutingIgnore []string `yaml:"automatic_page_routing_ignore"`
AutomaticPartialRoutingIgnore []string `yaml:"automatic_partial_routing_ignore"`
PublicAssetPath string `yaml:"public_asset_path"`
}
func DefaultProjectConfig() *ProjectConfig {
@ -25,6 +26,7 @@ func DefaultProjectConfig() *ProjectConfig {
WatchFiles: []string{
"**/*.go", "**/*.html", "**/*.css", "**/*.js", "**/*.json", "**/*.yaml", "**/*.yml", "**/*.md",
},
PublicAssetPath: "/public",
}
}
@ -57,9 +59,22 @@ func (cfg *ProjectConfig) Enhance() *ProjectConfig {
}
}
if cfg.PublicAssetPath == "" {
cfg.PublicAssetPath = "/public"
}
return cfg
}
func Get() *ProjectConfig {
cwd, err := os.Getwd()
if err != nil {
return DefaultProjectConfig()
}
config := FromConfigFile(cwd)
return config
}
func FromConfigFile(workingDir string) *ProjectConfig {
defaultCfg := DefaultProjectConfig()
names := []string{"htmgo.yaml", "htmgo.yml", "_htmgo.yaml", "_htmgo.yml"}

View file

@ -73,6 +73,21 @@ func TestShouldPrefixAutomaticPartialRoutingIgnore_1(t *testing.T) {
assert.Equal(t, []string{"partials/somefile/*"}, cfg.AutomaticPartialRoutingIgnore)
}
func TestPublicAssetPath(t *testing.T) {
t.Parallel()
cfg := DefaultProjectConfig()
assert.Equal(t, "/public", cfg.PublicAssetPath)
cfg.PublicAssetPath = "/assets"
assert.Equal(t, "/assets", cfg.PublicAssetPath)
}
func TestConfigGet(t *testing.T) {
t.Parallel()
cfg := Get()
assert.Equal(t, "/public", cfg.PublicAssetPath)
}
func writeConfigFile(t *testing.T, content string) string {
temp := os.TempDir()
os.Mkdir(temp, 0755)

View file

@ -3,6 +3,7 @@ package base
import (
"github.com/google/uuid"
"github.com/maddalax/htmgo/framework/h"
"htmgo-site/__htmgo/assets"
"htmgo-site/partials"
)
@ -43,8 +44,8 @@ func ConfigurableRootPage(ctx *h.RequestContext, props RootPageProps) *h.Page {
h.Title(
h.Text(title),
),
h.Link("/public/favicon.ico", "icon"),
h.Link("/public/apple-touch-icon.png", "apple-touch-icon"),
h.Link(assets.FaviconIco, "icon"),
h.Link(assets.AppleTouchIconPng, "apple-touch-icon"),
h.Meta("charset", "utf-8"),
h.Meta("author", "htmgo"),
h.Meta("description", description),
@ -53,8 +54,8 @@ func ConfigurableRootPage(ctx *h.RequestContext, props RootPageProps) *h.Page {
h.Link("canonical", canonical),
h.Link("https://cdn.jsdelivr.net/npm/@docsearch/css@3", "stylesheet"),
h.Meta("og:description", description),
h.LinkWithVersion("/public/main.css", "stylesheet", Version),
h.ScriptWithVersion("/public/htmgo.js", Version),
h.LinkWithVersion(assets.MainCss, "stylesheet", Version),
h.ScriptWithVersion(assets.HtmgoJs, Version),
h.Style(`
html {
scroll-behavior: smooth;

View file

@ -61,20 +61,3 @@ h.JoinExtensions(
h.HxExtension("my-extension"),
)
`
const htmxExtensions = `
h.HxOnLoad
h.HxOnAfterSwap
h.OnClick
h.OnSubmit
h.HxBeforeSseMessage
h.HxAfterSseMessage
h.OnClick
h.OnSubmit
h.HxOnSseError
h.HxOnSseClose
h.HxOnSseConnecting
h.HxOnSseOpen
h.HxAfterRequest
h.HxOnMutationError
`

View file

@ -16,3 +16,6 @@ automatic_page_routing_ignore: ["root.go"]
# files or directories to ignore when automatically registering routes for partials
# supports glob patterns through https://github.com/bmatcuk/doublestar
automatic_partial_routing_ignore: []
# url path of where the public assets are located
public_asset_path: "/public"

View file

@ -1,6 +1,8 @@
package main
import (
"fmt"
"github.com/maddalax/htmgo/framework/config"
"github.com/maddalax/htmgo/framework/h"
"github.com/maddalax/htmgo/framework/service"
"io/fs"
@ -10,6 +12,7 @@ import (
func main() {
locator := service.NewLocator()
cfg := config.Get()
h.Start(h.AppOpts{
ServiceLocator: locator,
@ -23,7 +26,10 @@ func main() {
http.FileServerFS(sub)
app.Router.Handle("/public/*", http.StripPrefix("/public", http.FileServerFS(sub)))
// change this in htmgo.yml (public_asset_path)
app.Router.Handle(fmt.Sprintf("%s/*", cfg.PublicAssetPath),
http.StripPrefix(cfg.PublicAssetPath, http.FileServerFS(sub)))
__htmgo.Register(app.Router)
},
})

View file

@ -2,6 +2,7 @@ package pages
import (
"github.com/maddalax/htmgo/framework/h"
"starter-template/__htmgo/assets"
)
func RootPage(children ...h.Ren) *h.Page {
@ -20,8 +21,8 @@ func RootPage(children ...h.Ren) *h.Page {
h.Text(title),
),
h.Meta("viewport", "width=device-width, initial-scale=1"),
h.Link("/public/favicon.ico", "icon"),
h.Link("/public/apple-touch-icon.png", "apple-touch-icon"),
h.Link(assets.FaviconIco, "icon"),
h.Link(assets.AppleTouchIconPng, "apple-touch-icon"),
h.Meta("title", title),
h.Meta("charset", "utf-8"),
h.Meta("author", author),
@ -30,8 +31,8 @@ func RootPage(children ...h.Ren) *h.Page {
h.Meta("og:url", url),
h.Link("canonical", url),
h.Meta("og:description", description),
h.Link("/public/main.css", "stylesheet"),
h.Script("/public/htmgo.js"),
h.Link(assets.MainCss, "stylesheet"),
h.Script(assets.HtmgoJs),
),
h.Body(
h.Div(