diff --git a/sui/api/request.go b/sui/api/request.go
index 2cac757ed..2ad2d7249 100644
--- a/sui/api/request.go
+++ b/sui/api/request.go
@@ -86,88 +86,16 @@ func (r *Request) Render() (string, int, error) {
if c == nil {
- // The page is not cached
message := fmt.Sprintf("[SUI] The page %s is not cached. file=%s DisableCache=%v", r.Request.URL.Path, r.File, r.Request.DisableCache())
go fmt.Println(color.YellowString(message))
go log.Warn(message)
- // Read the file
- content, err := application.App.Read(r.File)
+ var status int
+ var err error
+ c, status, err = r.MakeCache()
if err != nil {
- return "", 404, err
+ return "", status, err
}
-
- doc, err := core.NewDocument(content)
- if err != nil {
- return "", 500, err
- }
-
- guard := ""
- guardRedirect := ""
- configText := ""
- cacheStore := ""
- cacheTime := 0
- dateCacheTime := 0
-
- configSel := doc.Find("script[name=config]")
- if configSel != nil && configSel.Length() > 0 {
- configText = configSel.Text()
- configSel.Remove()
-
- var conf core.PageConfig
- err := jsoniter.UnmarshalFromString(configText, &conf)
- if err != nil {
- return "", 500, fmt.Errorf("config error, please re-complie the page %s", err.Error())
- }
-
- // Redirect the page (should refector before release)
- // guard=cookie-jwt:redirect-url redirect to the url if not authorized
- // guard=cookie-jwt return {code: 403, message: "Not Authorized"}
- guard = conf.Guard
- if strings.Contains(conf.Guard, ":") {
- parts := strings.Split(conf.Guard, ":")
- guard = parts[0]
- guardRedirect = parts[1]
- }
-
- // Cache store
- cacheStore = conf.CacheStore
- cacheTime = conf.Cache
- dateCacheTime = conf.DataCache
- }
-
- dataText := ""
- dataSel := doc.Find("script[name=data]")
- if dataSel != nil && dataSel.Length() > 0 {
- dataText = dataSel.Text()
- dataSel.Remove()
- }
-
- globalDataText := ""
- globalDataSel := doc.Find("script[name=global]")
- if globalDataSel != nil && globalDataSel.Length() > 0 {
- globalDataText = globalDataSel.Text()
- globalDataSel.Remove()
- }
-
- html, err := doc.Html()
- if err != nil {
- return "", 500, fmt.Errorf("parse error, please re-complie the page %s", err.Error())
- }
-
- // Save to The Cache
- c = &core.Cache{
- Data: dataText,
- Global: globalDataText,
- HTML: html,
- Guard: guard,
- GuardRedirect: guardRedirect,
- Config: configText,
- CacheStore: cacheStore,
- CacheTime: time.Duration(cacheTime) * time.Second,
- DataCacheTime: time.Duration(dateCacheTime) * time.Second,
- }
- go core.SetCache(r.File, c)
go log.Trace("[SUI] The page %s is cached file=%s", r.Request.URL.Path, r.File)
}
@@ -249,6 +177,90 @@ func (r *Request) Render() (string, int, error) {
return html, 200, nil
}
+// MakeCache is the cache for the page API.
+func (r *Request) MakeCache() (*core.Cache, int, error) {
+
+ // Read the file
+ content, err := application.App.Read(r.File)
+ if err != nil {
+ return nil, 404, err
+ }
+
+ doc, err := core.NewDocument(content)
+ if err != nil {
+ return nil, 500, err
+ }
+
+ guard := ""
+ guardRedirect := ""
+ configText := ""
+ cacheStore := ""
+ cacheTime := 0
+ dateCacheTime := 0
+
+ configSel := doc.Find("script[name=config]")
+ if configSel != nil && configSel.Length() > 0 {
+ configText = configSel.Text()
+ configSel.Remove()
+
+ var conf core.PageConfig
+ err := jsoniter.UnmarshalFromString(configText, &conf)
+ if err != nil {
+ return nil, 500, fmt.Errorf("config error, please re-complie the page %s", err.Error())
+ }
+
+ // Redirect the page (should refector before release)
+ // guard=cookie-jwt:redirect-url redirect to the url if not authorized
+ // guard=cookie-jwt return {code: 403, message: "Not Authorized"}
+ guard = conf.Guard
+ if strings.Contains(conf.Guard, ":") {
+ parts := strings.Split(conf.Guard, ":")
+ guard = parts[0]
+ guardRedirect = parts[1]
+ }
+
+ // Cache store
+ cacheStore = conf.CacheStore
+ cacheTime = conf.Cache
+ dateCacheTime = conf.DataCache
+ }
+
+ dataText := ""
+ dataSel := doc.Find("script[name=data]")
+ if dataSel != nil && dataSel.Length() > 0 {
+ dataText = dataSel.Text()
+ dataSel.Remove()
+ }
+
+ globalDataText := ""
+ globalDataSel := doc.Find("script[name=global]")
+ if globalDataSel != nil && globalDataSel.Length() > 0 {
+ globalDataText = globalDataSel.Text()
+ globalDataSel.Remove()
+ }
+
+ html, err := doc.Html()
+ if err != nil {
+ return nil, 500, fmt.Errorf("parse error, please re-complie the page %s", err.Error())
+ }
+
+ // Save to The Cache
+ cache := &core.Cache{
+ Data: dataText,
+ Global: globalDataText,
+ HTML: html,
+ Guard: guard,
+ GuardRedirect: guardRedirect,
+ Config: configText,
+ CacheStore: cacheStore,
+ CacheTime: time.Duration(cacheTime) * time.Second,
+ DataCacheTime: time.Duration(dateCacheTime) * time.Second,
+ }
+
+ go core.SetCache(r.File, cache)
+ return cache, 200, nil
+}
+
// Guard the page
func (r *Request) Guard(c *core.Cache) (int, error) {
diff --git a/sui/api/request_test.go b/sui/api/request_test.go
new file mode 100644
index 000000000..ea8e09365
--- /dev/null
+++ b/sui/api/request_test.go
@@ -0,0 +1,100 @@
+package api
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/gin-gonic/gin"
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/yao/sui/core"
+)
+
+func TestMakeCache(t *testing.T) {
+ prepare(t)
+ defer clean()
+ r := makeRequest("/unit-test/index.sui", t)
+ c, status, err := r.MakeCache()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assert.Equal(t, http.StatusOK, status)
+ assert.Contains(t, c.HTML, "The advanced test cases")
+}
+
+func TestRender(t *testing.T) {
+ prepare(t)
+ defer clean()
+
+ parser, html, data := makeParser("/unit-test/index.sui", t)
+ result, err := parser.Render(html)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assert.Contains(t, result, "The advanced test cases")
+ assert.NotNil(t, data["$global"])
+ assert.NotNil(t, data["foo"])
+ assert.NotNil(t, data["items"])
+
+ // fmt.Println(result)
+}
+
+func makeParser(route string, t *testing.T) (*core.TemplateParser, string, core.Data) {
+ r := makeRequest(route, t)
+ c, _, err := r.MakeCache()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ data := r.Request.NewData()
+ if c.Data != "" {
+ err = r.Request.ExecStringMerge(data, c.Data)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ if c.Global != "" {
+ global, err := r.Request.ExecString(c.Global)
+ if err != nil {
+ t.Fatal(err)
+ }
+ data["$global"] = global
+ }
+
+ // Set the page request data
+ option := core.ParserOption{
+ Theme: r.Request.Theme,
+ Locale: r.Request.Locale,
+ Debug: r.Request.DebugMode(),
+ DisableCache: r.Request.DisableCache(),
+ Route: r.Request.URL.Path,
+ Request: true,
+ }
+
+ // Parse the template
+ return core.NewTemplateParser(data, &option), c.HTML, data
+}
+
+func makeRequest(path string, t *testing.T) *Request {
+ req, err := http.NewRequest(http.MethodGet, path, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ w := httptest.NewRecorder()
+ c, _ := gin.CreateTestContext(w)
+ c.Request = req
+
+ r, status, err := NewRequestContext(c)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if status != http.StatusOK {
+ t.Fatalf("Status: %d", status)
+ }
+ return r
+}
diff --git a/sui/api/sui_test.go b/sui/api/sui_test.go
index 318d8dda2..66b804677 100644
--- a/sui/api/sui_test.go
+++ b/sui/api/sui_test.go
@@ -31,6 +31,16 @@ func prepare(t *testing.T) {
if err != nil {
t.Fatal(err)
}
+
+ advanced, err := core.SUIs["test"].GetTemplate("advanced")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = advanced.Build(&core.BuildOption{SSR: true})
+ if err != nil {
+ t.Fatal(err)
+ }
}
func clean() {
diff --git a/sui/core/build.go b/sui/core/build.go
index 8dfbf19f5..ec8523c3d 100644
--- a/sui/core/build.go
+++ b/sui/core/build.go
@@ -62,7 +62,11 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume
doc.Selection.Find("body").AppendHtml("\n" + `` + "\n")
}
}
- doc.Selection.Find("body").AppendHtml(fmt.Sprintf("\n"+``+"\n%s\n", strings.Join(ctx.scripts, "\n"), code))
+ componentScripts := ""
+ if len(ctx.scripts) > 0 {
+ componentScripts = fmt.Sprintf("\n"+``+"\n", strings.Join(ctx.scripts, "\n"))
+ }
+ doc.Selection.Find("body").AppendHtml(fmt.Sprintf("\n%s\n%s\n", componentScripts, code))
return doc, warnings, nil
}
@@ -373,7 +377,7 @@ func (page *Page) BuildScript(ctx *BuildContext, option *BuildOption, namespace
// if the script is a component and not the first import
if option.ComponentName != "" && ctx.components[option.ComponentName] {
ctx.scripts = append(ctx.scripts, instanceCode)
- return fmt.Sprintf("\n", instanceCode), []string{}, nil
+ return fmt.Sprintf("\n", option.ComponentName, instanceCode), []string{}, nil
}
// TypeScript
@@ -402,12 +406,15 @@ func (page *Page) BuildScript(ctx *BuildContext, option *BuildOption, namespace
}
if option.Namespace == "" {
- return fmt.Sprintf("\n", code), scripts, nil
+ if strings.TrimSpace(string(code)) == "" {
+ return "", scripts, nil
+ }
+ return fmt.Sprintf("\n", code), scripts, nil
}
componentCode := fmt.Sprintf("function %s(){\n%s\n}\n%s\n", option.ComponentName, addTabToEachLine(string(code)), instanceCode)
ctx.scripts = append(ctx.scripts, componentCode)
- return fmt.Sprintf("\n", componentCode), scripts, nil
+ return fmt.Sprintf("\n", option.ComponentName, componentCode), scripts, nil
}
// JavaScript
@@ -434,12 +441,15 @@ func (page *Page) BuildScript(ctx *BuildContext, option *BuildOption, namespace
}
if option.Namespace == "" {
- return fmt.Sprintf("\n", code), scripts, nil
+ if strings.TrimSpace(string(code)) == "" {
+ return "", scripts, nil
+ }
+ return fmt.Sprintf("\n", code), scripts, nil
}
componentCode := fmt.Sprintf("function %s(){\n%s\n}\n%s\n", option.ComponentName, addTabToEachLine(string(code)), instanceCode)
ctx.scripts = append(ctx.scripts, componentCode)
- return fmt.Sprintf("\n", componentCode), scripts, nil
+ return fmt.Sprintf("\n", option.ComponentName, componentCode), scripts, nil
}
func addTabToEachLine(input string, prefix ...string) string {
diff --git a/sui/core/fs_test.go b/sui/core/fs_test.go
deleted file mode 100644
index 9a8bc9592..000000000
--- a/sui/core/fs_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package core