cleaning up logging, speed up live reload using tailwind watch
This commit is contained in:
parent
f0a38379c3
commit
b610aefa36
20 changed files with 158 additions and 95 deletions
|
|
@ -3,12 +3,13 @@ package main
|
|||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getLogLevel() slog.Level {
|
||||
// Get the log level from the environment variable
|
||||
logLevel := os.Getenv("LOG_LEVEL")
|
||||
switch logLevel {
|
||||
switch strings.ToUpper(logLevel) {
|
||||
case "DEBUG":
|
||||
return slog.LevelDebug
|
||||
case "INFO":
|
||||
|
|
|
|||
|
|
@ -51,18 +51,21 @@ func main() {
|
|||
|
||||
taskName := os.Args[1]
|
||||
|
||||
slog.Debug("Running task: %s", taskName)
|
||||
slog.Debug("working dir %s", process.GetWorkingDir())
|
||||
slog.Debug("Running task:", slog.String("task", taskName))
|
||||
slog.Debug("working dir:", slog.String("dir", process.GetWorkingDir()))
|
||||
|
||||
if taskName == "watch" {
|
||||
os.Setenv("ENV", "development")
|
||||
os.Setenv("WATCH_MODE", "true")
|
||||
copyassets.CopyAssets()
|
||||
astgen.GenAst(true)
|
||||
css.GenerateCss(true)
|
||||
astgen.GenAst(process.ExitOnError)
|
||||
css.GenerateCss(process.ExitOnError, process.Silent)
|
||||
run.EntGenerate()
|
||||
go func() {
|
||||
_ = run.Server(true)
|
||||
css.GenerateCssWatch(process.ExitOnError)
|
||||
}()
|
||||
go func() {
|
||||
_ = run.Server(process.ExitOnError)
|
||||
}()
|
||||
startWatcher(reloader.OnFileChange)
|
||||
} else {
|
||||
|
|
@ -75,18 +78,18 @@ func main() {
|
|||
}
|
||||
if taskName == "generate" {
|
||||
run.EntGenerate()
|
||||
astgen.GenAst(true)
|
||||
astgen.GenAst(process.ExitOnError)
|
||||
}
|
||||
if taskName == "setup" {
|
||||
run.Setup()
|
||||
} else if taskName == "css" {
|
||||
_ = css.GenerateCss(true)
|
||||
_ = css.GenerateCss(process.ExitOnError)
|
||||
} else if taskName == "ast" {
|
||||
_ = astgen.GenAst(true)
|
||||
_ = astgen.GenAst(process.ExitOnError)
|
||||
} else if taskName == "run" {
|
||||
_ = astgen.GenAst(true)
|
||||
_ = css.GenerateCss(true)
|
||||
_ = run.Server(true)
|
||||
_ = astgen.GenAst(process.ExitOnError)
|
||||
_ = css.GenerateCss(process.ExitOnError)
|
||||
_ = run.Server(process.ExitOnError)
|
||||
} else if taskName == "template" {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print("What would you like to call your new app?: ")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"golang.org/x/mod/modfile"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -354,9 +355,9 @@ func GetModuleName() string {
|
|||
return modName
|
||||
}
|
||||
|
||||
func GenAst(exitOnError bool) error {
|
||||
func GenAst(flags ...process.RunFlag) error {
|
||||
if GetModuleName() == "" {
|
||||
if exitOnError {
|
||||
if slices.Contains(flags, process.ExitOnError) {
|
||||
os.Exit(1)
|
||||
}
|
||||
return fmt.Errorf("error getting module name")
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"golang.org/x/mod/modfile"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
|
@ -122,5 +123,5 @@ func CopyAssets() {
|
|||
log.Fatalf("Error: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("successfully copied assets to %s\n", destDir)
|
||||
slog.Debug("successfully copied assets to %s\n", destDir)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,15 @@ package css
|
|||
|
||||
import "github.com/maddalax/htmgo/cli/tasks/process"
|
||||
|
||||
func GenerateCss(exitOnError bool) error {
|
||||
func GenerateCss(flags ...process.RunFlag) error {
|
||||
return process.RunMany([]string{
|
||||
"chmod +x ./assets/css/tailwindcss",
|
||||
"./assets/css/tailwindcss -i ./assets/css/input.css -o ./assets/dist/main.css -c ./assets/css/tailwind.config.js",
|
||||
}, exitOnError)
|
||||
}, append(flags, process.Silent)...)
|
||||
}
|
||||
|
||||
func GenerateCssWatch(flags ...process.RunFlag) error {
|
||||
return process.RunMany([]string{
|
||||
"./assets/css/tailwindcss -i ./assets/css/input.css -o ./assets/dist/main.css -c ./assets/css/tailwind.config.js --watch=always",
|
||||
}, append(flags, process.DontTrack, process.Silent)...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ package process
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
|
@ -17,7 +17,7 @@ var workingDir string
|
|||
var commands = make([]*exec.Cmd, 0)
|
||||
|
||||
func AppendRunning(cmd *exec.Cmd) {
|
||||
slog.Info("running", slog.String("command", strings.Join(cmd.Args, " ")))
|
||||
slog.Debug("running", slog.String("command", strings.Join(cmd.Args, " ")))
|
||||
commands = append(commands, cmd)
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ func KillAll() {
|
|||
|
||||
if tries > 50 {
|
||||
args := strings.Join(cmd.Args, " ")
|
||||
log.Printf("process %v is not running after 50 tries, breaking.\n", args)
|
||||
slog.Debug("process %v is not running after 50 tries, breaking.\n", args)
|
||||
allFinished = true
|
||||
break
|
||||
} else {
|
||||
|
|
@ -90,13 +90,13 @@ func KillAll() {
|
|||
if finished {
|
||||
break
|
||||
} else {
|
||||
fmt.Printf("waiting for all processes to exit\n")
|
||||
slog.Debug("waiting for all processes to exit\n")
|
||||
time.Sleep(time.Millisecond * 5)
|
||||
}
|
||||
}
|
||||
|
||||
commands = make([]*exec.Cmd, 0)
|
||||
fmt.Printf("all processes killed\n")
|
||||
slog.Debug("all processes killed\n")
|
||||
}
|
||||
|
||||
func PidExists(pid int32) (bool, error) {
|
||||
|
|
@ -129,14 +129,22 @@ func PidExists(pid int32) (bool, error) {
|
|||
}
|
||||
|
||||
func RunOrExit(command string) {
|
||||
_ = Run(command, true)
|
||||
_ = Run(command, ExitOnError)
|
||||
}
|
||||
|
||||
func RunMany(commands []string, exitOnError bool) error {
|
||||
type RunFlag int
|
||||
|
||||
const (
|
||||
ExitOnError RunFlag = iota
|
||||
Silent
|
||||
DontTrack
|
||||
)
|
||||
|
||||
func RunMany(commands []string, flags ...RunFlag) error {
|
||||
for _, command := range commands {
|
||||
err := Run(command, false)
|
||||
err := Run(command, flags...)
|
||||
if err != nil {
|
||||
if exitOnError {
|
||||
if slices.Contains(flags, ExitOnError) {
|
||||
os.Exit(1)
|
||||
}
|
||||
return err
|
||||
|
|
@ -145,17 +153,26 @@ func RunMany(commands []string, exitOnError bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func Run(command string, exitOnError bool) error {
|
||||
cmd := exec.Command("bash", "-c", command)
|
||||
func Run(command string, flags ...RunFlag) error {
|
||||
parts := strings.Fields(command)
|
||||
cmd := exec.Command(parts[0], parts[1:]...)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if slices.Contains(flags, Silent) {
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
} else {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
|
||||
if workingDir != "" {
|
||||
cmd.Dir = workingDir
|
||||
}
|
||||
|
||||
AppendRunning(cmd)
|
||||
if !slices.Contains(flags, DontTrack) {
|
||||
AppendRunning(cmd)
|
||||
}
|
||||
err := cmd.Run()
|
||||
|
||||
if err == nil {
|
||||
|
|
@ -166,8 +183,10 @@ func Run(command string, exitOnError bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
if exitOnError {
|
||||
log.Println(fmt.Sprintf("error: %v", err))
|
||||
if slices.Contains(flags, ExitOnError) {
|
||||
slog.Error("Error running command: ",
|
||||
slog.String("error", err.Error()),
|
||||
slog.String("command", command))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,20 +4,22 @@ import (
|
|||
"fmt"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/maddalax/htmgo/cli/tasks/astgen"
|
||||
"github.com/maddalax/htmgo/cli/tasks/css"
|
||||
"github.com/maddalax/htmgo/cli/tasks/process"
|
||||
"github.com/maddalax/htmgo/cli/tasks/run"
|
||||
"github.com/maddalax/htmgo/cli/tasks/util"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Change struct {
|
||||
name string
|
||||
op fsnotify.Op
|
||||
}
|
||||
|
||||
func NewChange(name string) *Change {
|
||||
return &Change{name: name}
|
||||
func NewChange(event *fsnotify.Event) *Change {
|
||||
return &Change{name: event.Name, op: event.Op}
|
||||
}
|
||||
|
||||
func (c *Change) Name() string {
|
||||
|
|
@ -46,60 +48,70 @@ func (c *Change) IsGenerated() bool {
|
|||
return c.HasAnySuffix("generated.go")
|
||||
}
|
||||
|
||||
func (c *Change) IsWrite() bool {
|
||||
return c.op == fsnotify.Write
|
||||
}
|
||||
|
||||
func (c *Change) IsGo() bool {
|
||||
return c.HasAnySuffix(".go")
|
||||
}
|
||||
|
||||
type Tasks struct {
|
||||
AstGen bool
|
||||
Css bool
|
||||
Run bool
|
||||
Ent bool
|
||||
}
|
||||
|
||||
func OnFileChange(events []*fsnotify.Event) {
|
||||
now := time.Now()
|
||||
|
||||
tasks := Tasks{}
|
||||
|
||||
for _, event := range events {
|
||||
c := NewChange(event.Name)
|
||||
|
||||
slog.Debug("file changed", slog.String("file", c.Name()))
|
||||
c := NewChange(event)
|
||||
|
||||
if c.IsGenerated() {
|
||||
continue
|
||||
}
|
||||
|
||||
slog.Debug("file changed", slog.String("file", c.Name()))
|
||||
|
||||
if c.IsGo() && c.HasAnyPrefix("pages/", "partials/") {
|
||||
tasks.AstGen = true
|
||||
}
|
||||
|
||||
if c.IsGo() {
|
||||
tasks.Css = true
|
||||
tasks.Run = true
|
||||
}
|
||||
|
||||
if c.HasAnySuffix("tailwind.config.js", ".css") {
|
||||
tasks.Css = true
|
||||
tasks.Run = true
|
||||
}
|
||||
|
||||
if c.HasAnyPrefix("ent/schema") {
|
||||
tasks.Ent = true
|
||||
}
|
||||
|
||||
slog.Info("file changed", slog.String("file", c.Name()))
|
||||
}
|
||||
|
||||
deps := make([]func() any, 0)
|
||||
|
||||
if tasks.AstGen {
|
||||
deps = append(deps, func() any {
|
||||
return astgen.GenAst(false)
|
||||
return util.Trace("generate ast", func() any {
|
||||
astgen.GenAst()
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if tasks.Ent {
|
||||
deps = append(deps, func() any {
|
||||
run.EntGenerate()
|
||||
return nil
|
||||
return util.Trace("generate ent", func() any {
|
||||
run.EntGenerate()
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -119,14 +131,16 @@ func OnFileChange(events []*fsnotify.Event) {
|
|||
wg.Wait()
|
||||
|
||||
if tasks.Run {
|
||||
process.KillAll()
|
||||
}
|
||||
|
||||
if tasks.Css {
|
||||
go css.GenerateCss(false)
|
||||
util.Trace("kill all processes", func() any {
|
||||
process.KillAll()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if tasks.Run {
|
||||
_ = run.Server(false)
|
||||
go run.Server()
|
||||
}
|
||||
|
||||
slog.Info("reloaded in", slog.Duration("duration", time.Since(now)))
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import (
|
|||
)
|
||||
|
||||
func Build() {
|
||||
astgen.GenAst(true)
|
||||
css.GenerateCss(true)
|
||||
astgen.GenAst(process.ExitOnError)
|
||||
css.GenerateCss(process.ExitOnError)
|
||||
process.RunOrExit("rm -rf ./dist")
|
||||
process.RunOrExit("mkdir -p ./dist/assets/dist")
|
||||
process.RunOrExit("cp -r ./assets/dist/* ./dist/assets/dist/")
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package run
|
|||
import "github.com/maddalax/htmgo/cli/tasks/process"
|
||||
|
||||
func EntNewSchema(name string) {
|
||||
process.RunOrExit("GOWORK=off go run -mod=mod entgo.io/ent/cmd/ent new " + name)
|
||||
process.RunOrExit("bash -c GOWORK=off go run -mod=mod entgo.io/ent/cmd/ent new " + name)
|
||||
}
|
||||
|
||||
func EntGenerate() {
|
||||
process.RunOrExit("GOWORK=off go generate ./ent")
|
||||
process.RunOrExit("bash -c GOWORK=off go generate ./ent")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ package run
|
|||
|
||||
import "github.com/maddalax/htmgo/cli/tasks/process"
|
||||
|
||||
func Server(exitOnError bool) error {
|
||||
return process.Run("go run .", exitOnError)
|
||||
func Server(flags ...process.RunFlag) error {
|
||||
return process.Run("go run .", flags...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ func Setup() {
|
|||
process.RunOrExit("go mod download")
|
||||
process.RunOrExit("go mod tidy")
|
||||
copyassets.CopyAssets()
|
||||
_ = astgen.GenAst(true)
|
||||
_ = css.GenerateCss(true)
|
||||
_ = astgen.GenAst(process.ExitOnError)
|
||||
_ = css.GenerateCss(process.ExitOnError)
|
||||
EntGenerate()
|
||||
}
|
||||
|
|
|
|||
13
cli/tasks/util/trace.go
Normal file
13
cli/tasks/util/trace.go
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Trace(name string, cb func() any) any {
|
||||
now := time.Now()
|
||||
result := cb()
|
||||
slog.Debug("trace", slog.String("name", name), slog.Duration("duration", time.Since(now)))
|
||||
return result
|
||||
}
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ignoredDirs = []string{".git", ".idea", "node_modules", "vendor"}
|
||||
|
||||
func startWatcher(cb func(file []*fsnotify.Event)) {
|
||||
events := make([]*fsnotify.Event, 0)
|
||||
debouncer := NewDebouncer(100 * time.Millisecond)
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Println("Recovered from fatal error:", r)
|
||||
// You can log the error here or take other corrective actions
|
||||
slog.Debug("Recovered from fatal error:", slog.String("error", r.(error).Error()))
|
||||
}
|
||||
}()
|
||||
// Create new watcher.
|
||||
|
|
@ -36,8 +36,10 @@ func startWatcher(cb func(file []*fsnotify.Event)) {
|
|||
}
|
||||
if event.Has(fsnotify.Write) || event.Has(fsnotify.Remove) || event.Has(fsnotify.Rename) {
|
||||
events = append(events, &event)
|
||||
go cb(events)
|
||||
events = make([]*fsnotify.Event, 0)
|
||||
debouncer.Do(func() {
|
||||
cb(events)
|
||||
events = make([]*fsnotify.Event, 0)
|
||||
})
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
|
|
@ -64,9 +66,9 @@ func startWatcher(cb func(file []*fsnotify.Event)) {
|
|||
if info.IsDir() {
|
||||
err = watcher.Add(path)
|
||||
if err != nil {
|
||||
log.Println("Error adding directory to watcher:", err)
|
||||
slog.Error("Error adding directory to watcher:", err)
|
||||
} else {
|
||||
log.Println("Watching directory:", path)
|
||||
slog.Debug("Watching directory:", slog.String("path", path))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ type InputProps struct {
|
|||
Type string
|
||||
DefaultValue string
|
||||
ValidationPath string
|
||||
Childen []h.Renderable
|
||||
Children []h.Renderable
|
||||
}
|
||||
|
||||
func Input(props InputProps) h.Renderable {
|
||||
|
|
@ -27,7 +27,7 @@ func Input(props InputProps) h.Renderable {
|
|||
h.Class("border p-2 rounded"),
|
||||
h.If(props.Id != "", h.Id(props.Id)),
|
||||
h.If(props.Name != "", h.Name(props.Name)),
|
||||
h.If(props.Childen != nil, h.Children(props.Childen...)),
|
||||
h.If(props.Children != nil, h.Children(props.Children...)),
|
||||
h.If(props.DefaultValue != "", h.Attribute("value", props.DefaultValue)),
|
||||
validation,
|
||||
)
|
||||
|
|
|
|||
2
framework/assets/dist/htmgo.js
vendored
2
framework/assets/dist/htmgo.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -33,14 +33,15 @@ htmx.defineExtension("livereload", {
|
|||
});
|
||||
|
||||
function reload() {
|
||||
fetch(window.location.href).then(response => {
|
||||
return response.text();
|
||||
}).then(html => {
|
||||
document.open();
|
||||
document.write(html);
|
||||
document.close();
|
||||
}).catch(err => {
|
||||
console.log('failed to fetch live reload', err)
|
||||
setTimeout(reload, 100)
|
||||
})
|
||||
window.location.reload()
|
||||
// fetch(window.location.href).then(response => {
|
||||
// return response.text();
|
||||
// }).then(html => {
|
||||
// document.open();
|
||||
// document.write(html);
|
||||
// document.close();
|
||||
// }).catch(err => {
|
||||
// console.log('failed to fetch live reload', err)
|
||||
// setTimeout(reload, 100)
|
||||
// })
|
||||
}
|
||||
|
|
@ -10,16 +10,8 @@ type WsOpts = {
|
|||
export function createWebSocketClient(opts: WsOpts) {
|
||||
let socket: WebSocket | null = null;
|
||||
const connect = (tries: number) => {
|
||||
|
||||
if(tries > 50) {
|
||||
console.error('failed to connect to websocket after 50 tries, please reload the page');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('connecting to ws', opts.url, 'attempt', tries)
|
||||
socket = new WebSocket(opts.url);
|
||||
// Handle connection open
|
||||
socket.onopen = () => {
|
||||
};
|
||||
// Handle incoming messages
|
||||
socket.onmessage = (event) => {
|
||||
opts.onMessage(event.data)
|
||||
|
|
@ -31,12 +23,14 @@ export function createWebSocketClient(opts: WsOpts) {
|
|||
} catch(ex) {
|
||||
// noop
|
||||
}
|
||||
let interval = tries * (opts.reconnectInterval || 100);
|
||||
socket = null
|
||||
let interval = tries * (opts.reconnectInterval || 1000);
|
||||
setTimeout(() => connect(tries + 1), interval);
|
||||
};
|
||||
// Handle connection close and attempt reconnection
|
||||
socket.onclose = () => {
|
||||
let interval = tries * (opts.reconnectInterval || 100);
|
||||
socket = null;
|
||||
let interval = tries * (opts.reconnectInterval || 1000);
|
||||
setTimeout(() => connect(tries + 1), interval);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -318,6 +318,10 @@ func NewHeaders(headers ...string) *Headers {
|
|||
return &m
|
||||
}
|
||||
|
||||
func Checkbox(children ...Renderable) Renderable {
|
||||
return Input("checkbox", children...)
|
||||
}
|
||||
|
||||
func Input(inputType string, children ...Renderable) Renderable {
|
||||
return &Node{
|
||||
tag: "input",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import "github.com/maddalax/htmgo/framework/h"
|
|||
|
||||
func RegisterPages(f *echo.Echo) {
|
||||
f.GET("/", func(ctx echo.Context) error {
|
||||
return h.HtmlView(ctx, IndexPage(ctx))
|
||||
cc := ctx.(*h.RequestContext)
|
||||
return h.HtmlView(ctx, IndexPage(cc))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,18 @@ import "github.com/labstack/echo/v4"
|
|||
import "starter-template/partials"
|
||||
|
||||
func GetPartialFromContext(ctx echo.Context) *h.Partial {
|
||||
path := ctx.Path()
|
||||
path := ctx.Request().URL.Path
|
||||
if path == "SamplePartial" || path == "/starter-template/partials.SamplePartial" {
|
||||
return partials.SamplePartial(ctx)
|
||||
cc := ctx.(*h.RequestContext)
|
||||
return partials.SamplePartial(cc)
|
||||
}
|
||||
if path == "NewPartial" || path == "/starter-template/partials.NewPartial" {
|
||||
return partials.NewPartial(ctx)
|
||||
cc := ctx.(*h.RequestContext)
|
||||
return partials.NewPartial(cc)
|
||||
}
|
||||
if path == "NewPartial2" || path == "/starter-template/partials.NewPartial2" {
|
||||
return partials.NewPartial2(ctx)
|
||||
cc := ctx.(*h.RequestContext)
|
||||
return partials.NewPartial2(cc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue