Merge pull request #653 from trheyi/main
feat: Add and optimize SUI CompileAsComponent support
This commit is contained in:
commit
a39c6285f2
5 changed files with 155 additions and 19 deletions
|
|
@ -160,6 +160,18 @@ func (page *Page) parse(ctx *BuildContext, doc *goquery.Document, option *BuildO
|
||||||
page.Translations = append(page.Translations, translations...)
|
page.Translations = append(page.Translations, translations...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name, has := sel.Attr("is")
|
||||||
|
if has {
|
||||||
|
// Check if Just-In-Time Component ( "is" has variable )
|
||||||
|
if ctx.isJitComponent(name) {
|
||||||
|
sel.SetAttr("s:jit", "true")
|
||||||
|
sel.SetAttr("s:root", public.Root)
|
||||||
|
ctx.addJitComponent(name)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
tagName := sel.Get(0).Data
|
tagName := sel.Get(0).Data
|
||||||
if tagName == "page" {
|
if tagName == "page" {
|
||||||
return true
|
return true
|
||||||
|
|
@ -169,16 +181,6 @@ func (page *Page) parse(ctx *BuildContext, doc *goquery.Document, option *BuildO
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
name, has := sel.Attr("is")
|
|
||||||
if has {
|
|
||||||
// Just in time component
|
|
||||||
if ctx.isJitComponent(name) {
|
|
||||||
sel.SetAttr("s:jit", "true")
|
|
||||||
sel.SetAttr("s:root", public.Root)
|
|
||||||
ctx.addJitComponent(name)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return has
|
return has
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,27 @@ func (page *Page) Compile(ctx *BuildContext, option *BuildOption) (string, error
|
||||||
return html, nil
|
return html, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CompileAsComponent compile the page as component
|
||||||
|
func (page *Page) CompileAsComponent(ctx *BuildContext, option *BuildOption) (string, error) {
|
||||||
|
|
||||||
|
opt := *option
|
||||||
|
opt.IgnoreDocument = true
|
||||||
|
opt.WithWrapper = true
|
||||||
|
doc, warnings, err := page.Build(ctx, &opt)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if warnings != nil && len(warnings) > 0 {
|
||||||
|
for _, warning := range warnings {
|
||||||
|
log.Warn("Compile page %s/%s/%s: %s", page.SuiID, page.TemplateID, page.Route, warning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
page.ReplaceDocument(doc)
|
||||||
|
return doc.Find("body").Html()
|
||||||
|
}
|
||||||
|
|
||||||
// CompileJS compile the javascript
|
// CompileJS compile the javascript
|
||||||
func (page *Page) CompileJS(source []byte, minify bool) ([]byte, []string, error) {
|
func (page *Page) CompileJS(source []byte, minify bool) ([]byte, []string, error) {
|
||||||
scripts := []string{}
|
scripts := []string{}
|
||||||
|
|
|
||||||
|
|
@ -61,16 +61,14 @@ func (tmpl *Template) Build(option *core.BuildOption) error {
|
||||||
// loaed pages
|
// loaed pages
|
||||||
tmpl.loaded = map[string]core.IPage{}
|
tmpl.loaded = map[string]core.IPage{}
|
||||||
for _, page := range pages {
|
for _, page := range pages {
|
||||||
perr := page.Load()
|
err := page.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = multierror.Append(perr)
|
return err
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
perr = page.Build(ctx, option)
|
err = page.Build(ctx, option)
|
||||||
if perr != nil {
|
if err != nil {
|
||||||
err = multierror.Append(perr)
|
return err
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
tmpl.loaded[page.Get().Route] = page
|
tmpl.loaded[page.Get().Route] = page
|
||||||
}
|
}
|
||||||
|
|
@ -180,7 +178,6 @@ func (page *Page) Build(globalCtx *core.GlobalBuildContext, option *core.BuildOp
|
||||||
option.AssetRoot = filepath.Join(root, "assets")
|
option.AssetRoot = filepath.Join(root, "assets")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace("Build the page %s AssetRoot: %s", page.Route, option.AssetRoot)
|
|
||||||
html, err := page.Page.Compile(ctx, option)
|
html, err := page.Page.Compile(ctx, option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -229,7 +226,60 @@ func (page *Page) Build(globalCtx *core.GlobalBuildContext, option *core.BuildOp
|
||||||
|
|
||||||
// BuildAsComponent build the page as component
|
// BuildAsComponent build the page as component
|
||||||
func (page *Page) BuildAsComponent(globalCtx *core.GlobalBuildContext, option *core.BuildOption) error {
|
func (page *Page) BuildAsComponent(globalCtx *core.GlobalBuildContext, option *core.BuildOption) error {
|
||||||
return page.writeJitHTML([]byte("<div>"+page.Route+" {{ type }} {{ bind }} </div>"), option.Data)
|
|
||||||
|
ctx := core.NewBuildContext(globalCtx)
|
||||||
|
if option.AssetRoot == "" {
|
||||||
|
root, err := page.tmpl.local.DSL.PublicRoot(option.Data)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("SyncAssets: Get the public root error: %s. use %s", err.Error(), page.tmpl.local.DSL.Public.Root)
|
||||||
|
root = page.tmpl.local.DSL.Public.Root
|
||||||
|
}
|
||||||
|
option.AssetRoot = filepath.Join(root, "assets")
|
||||||
|
}
|
||||||
|
|
||||||
|
html, err := page.Page.CompileAsComponent(ctx, option)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the html
|
||||||
|
err = page.writeJitHTML([]byte(html), option.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the locale files
|
||||||
|
err = page.writeLocaleFiles(option.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jit Components
|
||||||
|
if globalCtx == nil {
|
||||||
|
jitComponents, err := page.tmpl.GlobRoutes(ctx.GetJitComponents(), true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, route := range jitComponents {
|
||||||
|
var err error
|
||||||
|
p := page.tmpl.loaded[route]
|
||||||
|
if p == nil {
|
||||||
|
p, err = page.tmpl.Page(route)
|
||||||
|
if err != nil {
|
||||||
|
err = multierror.Append(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = p.BuildAsComponent(globalCtx, option)
|
||||||
|
if err != nil {
|
||||||
|
err = multierror.Append(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (page *Page) publicFile(data map[string]interface{}) string {
|
func (page *Page) publicFile(data map[string]interface{}) string {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yaoapp/gou/application"
|
||||||
"github.com/yaoapp/yao/sui/core"
|
"github.com/yaoapp/yao/sui/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -19,4 +23,61 @@ func TestTemplateBuild(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Components error: %v", err)
|
t.Fatalf("Components error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index := "/index.sui"
|
||||||
|
|
||||||
|
// Check SUI
|
||||||
|
root := application.App.Root()
|
||||||
|
public := tmpl.(*Template).local.GetPublic()
|
||||||
|
path := filepath.Join(root, "public", public.Root)
|
||||||
|
assert.FileExists(t, filepath.Join(path, index))
|
||||||
|
|
||||||
|
content, err := os.ReadFile(filepath.Join(path, index))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReadFile error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Contains(t, string(content), "body")
|
||||||
|
assert.Contains(t, string(content), `<script src="/unit-test/assets/js/import.js"></script>`)
|
||||||
|
assert.Contains(t, string(content), `<script name="config" type="json">`)
|
||||||
|
assert.Contains(t, string(content), `<script name="data" type="json">`)
|
||||||
|
assert.Contains(t, string(content), `<script name="global" type="json">`)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTemplateBuildAsComponent(t *testing.T) {
|
||||||
|
tests := prepare(t)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
|
tmpl, err := tests.Web.GetTemplate("default")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetTemplate error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tmpl.Build(&core.BuildOption{SSR: true})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Components error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cselect := "/flowbite/components/edit/select.jit"
|
||||||
|
cinput := "/flowbite/components/edit/input.jit"
|
||||||
|
|
||||||
|
// Check JIT
|
||||||
|
root := application.App.Root()
|
||||||
|
public := tmpl.(*Template).local.GetPublic()
|
||||||
|
path := filepath.Join(root, "public", public.Root)
|
||||||
|
assert.FileExists(t, filepath.Join(path, cselect))
|
||||||
|
assert.FileExists(t, filepath.Join(path, cinput))
|
||||||
|
|
||||||
|
content, err := os.ReadFile(filepath.Join(path, cselect))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReadFile error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NotContains(t, string(content), "body")
|
||||||
|
assert.NotContains(t, string(content), `<script name="config" type="json">`)
|
||||||
|
assert.NotContains(t, string(content), `<script name="data" type="json">`)
|
||||||
|
assert.NotContains(t, string(content), `<script name="global" type="json">`)
|
||||||
|
assert.Contains(t, string(content), "function Init()")
|
||||||
|
assert.Contains(t, string(content), `type="flowbite-edit-select"`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ func prepare(t *testing.T) TestCase {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("New error: %v", err)
|
t.Fatalf("New error: %v", err)
|
||||||
}
|
}
|
||||||
|
core.SUIs["web"] = web
|
||||||
|
|
||||||
testDSL, err := core.Load("/suis/test.sui.yao", "test")
|
testDSL, err := core.Load("/suis/test.sui.yao", "test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -108,6 +109,7 @@ func prepare(t *testing.T) TestCase {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("New error: %v", err)
|
t.Fatalf("New error: %v", err)
|
||||||
}
|
}
|
||||||
|
core.SUIs["test"] = test
|
||||||
return TestCase{
|
return TestCase{
|
||||||
Test: test,
|
Test: test,
|
||||||
Web: web,
|
Web: web,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue