Merge pull request #656 from trheyi/main
refactor: Update build process to include SUI CompileAsComponent supp…
This commit is contained in:
commit
6f49ae307b
5 changed files with 214 additions and 83 deletions
|
|
@ -86,88 +86,16 @@ func (r *Request) Render() (string, int, error) {
|
||||||
|
|
||||||
if c == nil {
|
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())
|
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 fmt.Println(color.YellowString(message))
|
||||||
go log.Warn(message)
|
go log.Warn(message)
|
||||||
|
|
||||||
// Read the file
|
var status int
|
||||||
content, err := application.App.Read(r.File)
|
var err error
|
||||||
|
c, status, err = r.MakeCache()
|
||||||
if err != nil {
|
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)
|
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
|
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
|
// Guard the page
|
||||||
func (r *Request) Guard(c *core.Cache) (int, error) {
|
func (r *Request) Guard(c *core.Cache) (int, error) {
|
||||||
|
|
||||||
|
|
|
||||||
100
sui/api/request_test.go
Normal file
100
sui/api/request_test.go
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -31,6 +31,16 @@ func prepare(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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() {
|
func clean() {
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,11 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume
|
||||||
doc.Selection.Find("body").AppendHtml("\n" + `<script src="` + script + `"></script>` + "\n")
|
doc.Selection.Find("body").AppendHtml("\n" + `<script src="` + script + `"></script>` + "\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
doc.Selection.Find("body").AppendHtml(fmt.Sprintf("\n"+`<script type="text/javascript">`+"\n%s\n"+`</script>`+"\n%s\n", strings.Join(ctx.scripts, "\n"), code))
|
componentScripts := ""
|
||||||
|
if len(ctx.scripts) > 0 {
|
||||||
|
componentScripts = fmt.Sprintf("\n"+`<script type="text/javascript" name="components">`+"\n%s\n"+`</script>`+"\n", strings.Join(ctx.scripts, "\n"))
|
||||||
|
}
|
||||||
|
doc.Selection.Find("body").AppendHtml(fmt.Sprintf("\n%s\n%s\n", componentScripts, code))
|
||||||
return doc, warnings, nil
|
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 the script is a component and not the first import
|
||||||
if option.ComponentName != "" && ctx.components[option.ComponentName] {
|
if option.ComponentName != "" && ctx.components[option.ComponentName] {
|
||||||
ctx.scripts = append(ctx.scripts, instanceCode)
|
ctx.scripts = append(ctx.scripts, instanceCode)
|
||||||
return fmt.Sprintf("<script type=\"text/javascript\">\n%s\n</script>\n", instanceCode), []string{}, nil
|
return fmt.Sprintf("<script type=\"text/javascript\" name=\"%s\">\n%s\n</script>\n", option.ComponentName, instanceCode), []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeScript
|
// TypeScript
|
||||||
|
|
@ -402,12 +406,15 @@ func (page *Page) BuildScript(ctx *BuildContext, option *BuildOption, namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.Namespace == "" {
|
if option.Namespace == "" {
|
||||||
return fmt.Sprintf("<script type=\"text/javascript\">\n%s\n</script>\n", code), scripts, nil
|
if strings.TrimSpace(string(code)) == "" {
|
||||||
|
return "", scripts, nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("<script type=\"text/javascript\" name=\"page\">\n%s\n</script>\n", code), scripts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
componentCode := fmt.Sprintf("function %s(){\n%s\n}\n%s\n", option.ComponentName, addTabToEachLine(string(code)), instanceCode)
|
componentCode := fmt.Sprintf("function %s(){\n%s\n}\n%s\n", option.ComponentName, addTabToEachLine(string(code)), instanceCode)
|
||||||
ctx.scripts = append(ctx.scripts, componentCode)
|
ctx.scripts = append(ctx.scripts, componentCode)
|
||||||
return fmt.Sprintf("<script type=\"text/javascript\">%s</script>\n", componentCode), scripts, nil
|
return fmt.Sprintf("<script type=\"text/javascript\" name=\"%s\">%s</script>\n", option.ComponentName, componentCode), scripts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// JavaScript
|
// JavaScript
|
||||||
|
|
@ -434,12 +441,15 @@ func (page *Page) BuildScript(ctx *BuildContext, option *BuildOption, namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.Namespace == "" {
|
if option.Namespace == "" {
|
||||||
return fmt.Sprintf("<script type=\"text/javascript\">\n%s\n</script>\n", code), scripts, nil
|
if strings.TrimSpace(string(code)) == "" {
|
||||||
|
return "", scripts, nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("<script type=\"text/javascript\" name=\"page\">\n%s\n</script>\n", code), scripts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
componentCode := fmt.Sprintf("function %s(){\n%s\n}\n%s\n", option.ComponentName, addTabToEachLine(string(code)), instanceCode)
|
componentCode := fmt.Sprintf("function %s(){\n%s\n}\n%s\n", option.ComponentName, addTabToEachLine(string(code)), instanceCode)
|
||||||
ctx.scripts = append(ctx.scripts, componentCode)
|
ctx.scripts = append(ctx.scripts, componentCode)
|
||||||
return fmt.Sprintf("<script type=\"text/javascript\">%s</script>\n", componentCode), scripts, nil
|
return fmt.Sprintf("<script type=\"text/javascript\" name=\"%s\" >%s</script>\n", option.ComponentName, componentCode), scripts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addTabToEachLine(input string, prefix ...string) string {
|
func addTabToEachLine(input string, prefix ...string) string {
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
package core
|
|
||||||
Loading…
Add table
Reference in a new issue