optimize the SUI compiler & add http server gzip support
This commit is contained in:
parent
536621d72e
commit
e4c8eeb180
11 changed files with 169 additions and 44 deletions
|
|
@ -81,13 +81,25 @@ var BuildCmd = &cobra.Command{
|
||||||
|
|
||||||
// Timecost
|
// Timecost
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
err = tmpl.Build(&core.BuildOption{SSR: true, AssetRoot: assetRoot, ExecScripts: true})
|
minify := true
|
||||||
|
mode := "production"
|
||||||
|
if debug {
|
||||||
|
minify = false
|
||||||
|
mode = "development"
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tmpl.Build(&core.BuildOption{SSR: true, AssetRoot: assetRoot, ExecScripts: true, ScriptMinify: minify, StyleMinify: minify})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, color.RedString(err.Error()))
|
fmt.Fprintln(os.Stderr, color.RedString(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
end := time.Now()
|
end := time.Now()
|
||||||
timecost := end.Sub(start).Truncate(time.Millisecond)
|
timecost := end.Sub(start).Truncate(time.Millisecond)
|
||||||
fmt.Println(color.GreenString("Build success in %s", timecost))
|
if debug {
|
||||||
|
fmt.Println(color.YellowString("Build succeeded for %s in %s", mode, timecost))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(color.GreenString("Build succeeded for %s in %s", mode, timecost))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
package sui
|
package sui
|
||||||
|
|
||||||
|
var data string
|
||||||
|
var debug bool
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
WatchCmd.PersistentFlags().StringVarP(&data, "data", "d", "::{}", L("Session Data"))
|
WatchCmd.PersistentFlags().StringVarP(&data, "data", "d", "::{}", L("Session Data"))
|
||||||
BuildCmd.PersistentFlags().StringVarP(&data, "data", "d", "::{}", L("Session Data"))
|
BuildCmd.PersistentFlags().StringVarP(&data, "data", "d", "::{}", L("Session Data"))
|
||||||
|
BuildCmd.PersistentFlags().BoolVarP(&debug, "debug", "D", false, L("Debug mode"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ import (
|
||||||
"github.com/yaoapp/yao/sui/core"
|
"github.com/yaoapp/yao/sui/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
var data string
|
|
||||||
|
|
||||||
var watched sync.Map
|
var watched sync.Map
|
||||||
|
|
||||||
// WatchCmd command
|
// WatchCmd command
|
||||||
|
|
|
||||||
8
go.mod
8
go.mod
|
|
@ -3,7 +3,7 @@ module github.com/yaoapp/yao
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PuerkitoBio/goquery v1.8.1
|
github.com/PuerkitoBio/goquery v1.9.2
|
||||||
github.com/blang/semver v3.5.1+incompatible
|
github.com/blang/semver v3.5.1+incompatible
|
||||||
github.com/caarlos0/env/v6 v6.10.1
|
github.com/caarlos0/env/v6 v6.10.1
|
||||||
github.com/dchest/captcha v1.0.0
|
github.com/dchest/captcha v1.0.0
|
||||||
|
|
@ -26,8 +26,8 @@ require (
|
||||||
github.com/yaoapp/gou v0.10.3
|
github.com/yaoapp/gou v0.10.3
|
||||||
github.com/yaoapp/kun v0.9.0
|
github.com/yaoapp/kun v0.9.0
|
||||||
github.com/yaoapp/xun v0.9.0
|
github.com/yaoapp/xun v0.9.0
|
||||||
golang.org/x/crypto v0.23.0
|
golang.org/x/crypto v0.25.0
|
||||||
golang.org/x/net v0.25.0
|
golang.org/x/net v0.27.0
|
||||||
golang.org/x/text v0.16.0
|
golang.org/x/text v0.16.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
|
@ -113,7 +113,7 @@ require (
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
golang.org/x/mod v0.17.0 // indirect
|
||||||
golang.org/x/oauth2 v0.14.0 // indirect
|
golang.org/x/oauth2 v0.14.0 // indirect
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
golang.org/x/sys v0.20.0 // indirect
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||||
google.golang.org/appengine v1.6.8 // indirect
|
google.golang.org/appengine v1.6.8 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
|
||||||
|
|
|
||||||
8
go.sum
8
go.sum
|
|
@ -1,5 +1,7 @@
|
||||||
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
||||||
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
||||||
|
github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE=
|
||||||
|
github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
|
||||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
|
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
|
||||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
|
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
|
||||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
||||||
|
|
@ -261,6 +263,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
|
||||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||||
|
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||||
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
||||||
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
|
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
|
||||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||||
|
|
@ -284,6 +288,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||||
|
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
|
golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
|
||||||
|
|
@ -317,6 +323,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
|
|
||||||
46
service/gzip.go
Normal file
46
service/gzip.go
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// gzipHandler
|
||||||
|
func gzipHandler(h http.Handler) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Encoding", "gzip")
|
||||||
|
gz := gzip.NewWriter(w)
|
||||||
|
defer gz.Close()
|
||||||
|
|
||||||
|
gzWriter := gzipResponseWriter{ResponseWriter: w, Writer: gz}
|
||||||
|
h.ServeHTTP(gzWriter, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type gzipResponseWriter struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
*gzip.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w gzipResponseWriter) WriteHeader(code int) {
|
||||||
|
w.ResponseWriter.Header().Del("Content-Length")
|
||||||
|
w.ResponseWriter.WriteHeader(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w gzipResponseWriter) Write(b []byte) (int, error) {
|
||||||
|
return w.Writer.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w gzipResponseWriter) Flush() {
|
||||||
|
w.Writer.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w gzipResponseWriter) Header() http.Header {
|
||||||
|
return w.ResponseWriter.Header()
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -42,15 +45,6 @@ func withStaticFileServer(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yao Builder
|
|
||||||
// URL /yao/builder
|
|
||||||
if length >= 12 && c.Request.URL.Path[0:12] == "/yao/builder" {
|
|
||||||
c.Request.URL.Path = strings.TrimPrefix(c.Request.URL.Path, "/yao/builder")
|
|
||||||
BuilderFileServer.ServeHTTP(c.Writer, c.Request)
|
|
||||||
c.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rewrite
|
// Rewrite
|
||||||
for _, rewrite := range rewriteRules {
|
for _, rewrite := range rewriteRules {
|
||||||
// log.Debug("Rewrite: %s => %s", c.Request.URL.Path, rewrite.Replacement)
|
// log.Debug("Rewrite: %s => %s", c.Request.URL.Path, rewrite.Replacement)
|
||||||
|
|
@ -67,8 +61,6 @@ func withStaticFileServer(c *gin.Context) {
|
||||||
// Sui file server
|
// Sui file server
|
||||||
if strings.HasSuffix(c.Request.URL.Path, ".sui") {
|
if strings.HasSuffix(c.Request.URL.Path, ".sui") {
|
||||||
|
|
||||||
log.Debug("Sui File: %s", c.Request.URL.Path)
|
|
||||||
|
|
||||||
// Default index.sui
|
// Default index.sui
|
||||||
if filepath.Base(c.Request.URL.Path) == ".sui" {
|
if filepath.Base(c.Request.URL.Path) == ".sui" {
|
||||||
c.Request.URL.Path = strings.TrimSuffix(c.Request.URL.Path, ".sui") + "index.sui"
|
c.Request.URL.Path = strings.TrimSuffix(c.Request.URL.Path, ".sui") + "index.sui"
|
||||||
|
|
@ -96,9 +88,30 @@ func withStaticFileServer(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gzip Compression
|
||||||
|
if strings.Contains(c.GetHeader("Accept-Encoding"), "gzip") {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
gz := gzip.NewWriter(&buf)
|
||||||
|
if _, err := gz.Write([]byte(html)); err != nil {
|
||||||
|
log.Error("GZIP Compression Error: %s", err.Error())
|
||||||
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := gz.Close(); err != nil {
|
||||||
|
log.Error("GZIP Close Error: %s", err.Error())
|
||||||
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||||
|
c.Header("Content-Encoding", "gzip")
|
||||||
|
c.Data(http.StatusOK, "text/html", buf.Bytes())
|
||||||
|
c.Done()
|
||||||
|
}
|
||||||
|
|
||||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||||
c.String(200, html)
|
c.String(200, html)
|
||||||
c.Done()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ type rewriteRule struct {
|
||||||
func SetupStatic() error {
|
func SetupStatic() error {
|
||||||
setupAdminRoot()
|
setupAdminRoot()
|
||||||
setupRewrite()
|
setupRewrite()
|
||||||
AppFileServer = http.FileServer(fs.Dir("public"))
|
AppFileServer = gzipHandler(http.FileServer(fs.Dir("public")))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scripts
|
// Scripts
|
||||||
namespace := Namespace(page.Name, ctx.sequence)
|
namespace := Namespace(page.Name, ctx.sequence, option.ScriptMinify)
|
||||||
scripts, err := page.BuildScripts(ctx, option, "__page", namespace)
|
scripts, err := page.BuildScripts(ctx, option, "__page", namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ctx.warnings, err
|
return nil, ctx.warnings, err
|
||||||
|
|
@ -99,8 +99,8 @@ func (page *Page) BuildAsComponent(sel *goquery.Selection, ctx *BuildContext, op
|
||||||
return "", fmt.Errorf("The component tag must have an is attribute")
|
return "", fmt.Errorf("The component tag must have an is attribute")
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace := Namespace(name, ctx.sequence)
|
namespace := Namespace(name, ctx.sequence, option.ScriptMinify)
|
||||||
component := ComponentName(name)
|
component := ComponentName(name, option.ScriptMinify)
|
||||||
attrs := []html.Attribute{
|
attrs := []html.Attribute{
|
||||||
{Key: "s:ns", Val: namespace},
|
{Key: "s:ns", Val: namespace},
|
||||||
{Key: "s:cn", Val: component},
|
{Key: "s:cn", Val: component},
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,13 @@ var keepWords = map[string]bool{
|
||||||
"s:bind": true,
|
"s:bind": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var keepAttrs = map[string]bool{
|
||||||
|
"s:ns": true,
|
||||||
|
"s:cn": true,
|
||||||
|
"s:ready": true,
|
||||||
|
"s:click": true,
|
||||||
|
}
|
||||||
|
|
||||||
// Locales the locales
|
// Locales the locales
|
||||||
var Locales = map[string]map[string]*Locale{}
|
var Locales = map[string]map[string]*Locale{}
|
||||||
|
|
||||||
|
|
@ -229,8 +236,6 @@ func (parser *TemplateParser) Render(html string) (string, error) {
|
||||||
if parser.option != nil && (parser.option.Request || parser.option.Preview) {
|
if parser.option != nil && (parser.option.Request || parser.option.Preview) {
|
||||||
// Remove the sui-hide attribute
|
// Remove the sui-hide attribute
|
||||||
doc.Find("[sui-hide]").Remove()
|
doc.Find("[sui-hide]").Remove()
|
||||||
|
|
||||||
// Remove All comments and used nodes
|
|
||||||
parser.tidy(doc.Selection)
|
parser.tidy(doc.Selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -271,6 +276,8 @@ func (parser *TemplateParser) parseNode(node *html.Node) {
|
||||||
|
|
||||||
func (parser *TemplateParser) parseElementNode(sel *goquery.Selection) {
|
func (parser *TemplateParser) parseElementNode(sel *goquery.Selection) {
|
||||||
|
|
||||||
|
node := sel.Get(0)
|
||||||
|
|
||||||
if _, exist := sel.Attr("s:for"); exist {
|
if _, exist := sel.Attr("s:for"); exist {
|
||||||
parser.forStatementNode(sel)
|
parser.forStatementNode(sel)
|
||||||
}
|
}
|
||||||
|
|
@ -279,7 +286,7 @@ func (parser *TemplateParser) parseElementNode(sel *goquery.Selection) {
|
||||||
parser.ifStatementNode(sel)
|
parser.ifStatementNode(sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exist := sel.Attr("s:set"); exist || sel.Get(0).Data == "s:set" {
|
if _, exist := sel.Attr("s:set"); exist || node.Data == "s:set" {
|
||||||
parser.setStatementNode(sel)
|
parser.setStatementNode(sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -288,6 +295,11 @@ func (parser *TemplateParser) parseElementNode(sel *goquery.Selection) {
|
||||||
parser.parseJitElementNode(sel)
|
parser.parseJitElementNode(sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Slot Node
|
||||||
|
if node.Data == "slot" {
|
||||||
|
parser.slotNode(sel)
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the attributes
|
// Parse the attributes
|
||||||
parser.parseElementAttrs(sel)
|
parser.parseElementAttrs(sel)
|
||||||
|
|
||||||
|
|
@ -361,6 +373,16 @@ func (parser *TemplateParser) transElementNode(sel *goquery.Selection) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the slot tag and replace it with the children
|
||||||
|
func (parser *TemplateParser) slotNode(sel *goquery.Selection) {
|
||||||
|
children := sel.Children()
|
||||||
|
if children.Length() == 0 {
|
||||||
|
sel.Remove()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sel.ReplaceWithSelection(children)
|
||||||
|
}
|
||||||
|
|
||||||
func (parser *TemplateParser) setStatementNode(sel *goquery.Selection) {
|
func (parser *TemplateParser) setStatementNode(sel *goquery.Selection) {
|
||||||
|
|
||||||
sel.SetAttr("parsed", "true")
|
sel.SetAttr("parsed", "true")
|
||||||
|
|
@ -396,6 +418,12 @@ func (parser *TemplateParser) parseElementAttrs(sel *goquery.Selection) {
|
||||||
|
|
||||||
attrs := sel.Nodes[0].Attr
|
attrs := sel.Nodes[0].Attr
|
||||||
for _, attr := range attrs {
|
for _, attr := range attrs {
|
||||||
|
|
||||||
|
// Ignore the s: attributes
|
||||||
|
if strings.HasPrefix(attr.Key, "s:") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
parser.sequence = parser.sequence + 1
|
parser.sequence = parser.sequence + 1
|
||||||
res, hasStmt := parser.data.Replace(attr.Val)
|
res, hasStmt := parser.data.Replace(attr.Val)
|
||||||
if hasStmt {
|
if hasStmt {
|
||||||
|
|
@ -672,30 +700,33 @@ func (parser *TemplateParser) show(sel *goquery.Selection) {
|
||||||
// sel.SetAttr("style", style)
|
// sel.SetAttr("style", style)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *TemplateParser) tidy(selection *goquery.Selection) {
|
func (parser *TemplateParser) tidy(s *goquery.Selection) {
|
||||||
selection.Contents().Each(func(i int, s *goquery.Selection) {
|
|
||||||
|
|
||||||
if s.Nodes[0].Type == html.CommentNode {
|
s.Contents().Each(func(i int, child *goquery.Selection) {
|
||||||
s.Remove()
|
|
||||||
|
node := child.Get(0)
|
||||||
|
if node.Type == html.CommentNode {
|
||||||
|
child = child.Remove()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the s:key-* attributes
|
// Remove the parsed attribute
|
||||||
if s.Nodes[0].Type == html.ElementNode {
|
attrs := []html.Attribute{}
|
||||||
for _, attr := range s.Nodes[0].Attr {
|
for _, attr := range node.Attr {
|
||||||
if attr.Key == "parsed" || keepWords[attr.Key] || strings.HasPrefix(attr.Key, "s:key") || strings.HasPrefix(attr.Key, "s:bind") {
|
if strings.HasPrefix(attr.Key, "s:") && !keepAttrs[attr.Key] {
|
||||||
s.RemoveAttr(attr.Key)
|
continue
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Nodes[0].Data == "s:set" {
|
if attr.Key == "parsed" || attr.Key == "is" || strings.HasPrefix(attr.Key, "...") {
|
||||||
s.Remove()
|
continue
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
attrs = append(attrs, attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.tidy(s)
|
node.Attr = attrs
|
||||||
|
parser.tidy(child)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *TemplateParser) key(prefix string, sel *goquery.Selection) string {
|
func (parser *TemplateParser) key(prefix string, sel *goquery.Selection) string {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package core
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"hash/fnv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
|
|
@ -50,17 +51,29 @@ func NewDocumentStringWithWrapper(htmlContent string) (*goquery.Document, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Namespace convert the name to namespace
|
// Namespace convert the name to namespace
|
||||||
func Namespace(name string, idx int) string {
|
func Namespace(name string, idx int, hash ...bool) string {
|
||||||
name = strings.ReplaceAll(name, "/", "_")
|
name = strings.ReplaceAll(name, "/", "_")
|
||||||
name = strings.ReplaceAll(name, "[", "_")
|
name = strings.ReplaceAll(name, "[", "_")
|
||||||
name = strings.ReplaceAll(name, "]", "_")
|
name = strings.ReplaceAll(name, "]", "_")
|
||||||
|
ns := fmt.Sprintf("__namespace_%s", name)
|
||||||
|
if len(hash) > 0 && hash[0] {
|
||||||
|
h := fnv.New64a()
|
||||||
|
h.Write([]byte(ns))
|
||||||
|
return fmt.Sprintf("ns_%x", h.Sum64())
|
||||||
|
}
|
||||||
return fmt.Sprintf("__page_%s_%d", name, idx)
|
return fmt.Sprintf("__page_%s_%d", name, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComponentName convert the name to component name
|
// ComponentName convert the name to component name
|
||||||
func ComponentName(name string) string {
|
func ComponentName(name string, hash ...bool) string {
|
||||||
name = strings.ReplaceAll(name, "/", "_")
|
name = strings.ReplaceAll(name, "/", "_")
|
||||||
name = strings.ReplaceAll(name, "[", "_")
|
name = strings.ReplaceAll(name, "[", "_")
|
||||||
name = strings.ReplaceAll(name, "]", "_")
|
name = strings.ReplaceAll(name, "]", "_")
|
||||||
return fmt.Sprintf("__component_%s", name)
|
cn := fmt.Sprintf("__component_%s", name)
|
||||||
|
if len(hash) > 0 && hash[0] {
|
||||||
|
h := fnv.New64a()
|
||||||
|
h.Write([]byte(cn))
|
||||||
|
return fmt.Sprintf("cn_%x", h.Sum64())
|
||||||
|
}
|
||||||
|
return cn
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue