Refactor SUI core to load backend scripts for templates

This commit is contained in:
Max 2024-07-25 10:10:54 +08:00
parent 8d375e2222
commit 9418133b32
5 changed files with 152 additions and 13 deletions

View file

@ -4,6 +4,7 @@ import (
"time"
jsoniter "github.com/json-iterator/go"
v8 "github.com/yaoapp/gou/runtime/v8"
"github.com/yaoapp/gou/store"
"github.com/yaoapp/kun/log"
)
@ -20,6 +21,7 @@ type Cache struct {
CacheStore string
CacheTime time.Duration
DataCacheTime time.Duration
Script *v8.Script // the backend script
}
const (

View file

@ -5,6 +5,7 @@ import (
"regexp"
"github.com/PuerkitoBio/goquery"
v8 "github.com/yaoapp/gou/runtime/v8"
"golang.org/x/net/html"
)
@ -38,6 +39,7 @@ type Page struct {
Path string `json:"-"`
Root string `json:"-"`
Codes SourceCodes `json:"-"`
Script *v8.Script `json:"-"` // The backend script name.backend.ts / name.backend.js
Document []byte `json:"-"`
GlobalData []byte `json:"-"`
Attrs map[string]string `json:"-"`
@ -166,17 +168,19 @@ type LayoutItem struct {
// Template is the struct for the template
type Template struct {
Version int `json:"version"` // Yao Builder version
ID string `json:"id"`
Name string `json:"name"`
Descrption string `json:"description"`
Screenshots []string `json:"screenshots"`
Themes []SelectOption `json:"themes"`
Locales []SelectOption `json:"locales"`
Document []byte `json:"-"`
GlobalData []byte `json:"-"`
Scripts *TemplateScirpts `json:"scripts,omitempty"`
Translator string `json:"translator,omitempty"`
Version int `json:"version"` // Yao Builder version
ID string `json:"id"`
Name string `json:"name"`
Descrption string `json:"description"`
Screenshots []string `json:"screenshots"`
Themes []SelectOption `json:"themes"`
Locales []SelectOption `json:"locales"`
Document []byte `json:"-"`
GlobalData []byte `json:"-"`
Scripts *TemplateScirpts `json:"scripts,omitempty"`
Translator string `json:"translator,omitempty"`
BuildScript *v8.Script `json:"-"` // __build.backend.ts / __build.backend.js
GlobalScript *v8.Script `json:"-"` // __global.backend.ts / __global.backend.js
}
// TemplateScirpts is the struct for the template scripts

View file

@ -54,6 +54,12 @@ func (tmpl *Template) Build(option *core.BuildOption) ([]string, error) {
option.AssetRoot = filepath.Join(root, "assets")
}
// Write the global script
err = tmpl.writeGlobalScript(option.Data)
if err != nil {
return warnings, err
}
// Sync the assets
if err = tmpl.SyncAssets(option); err != nil {
return warnings, err
@ -192,6 +198,31 @@ func (tmpl *Template) SyncAssetFile(file string, option *core.BuildOption) error
return copy(sourceFile, targetFile)
}
func (tmpl *Template) writeGlobalScript(data map[string]interface{}) error {
file, source, err := tmpl.backendScriptSource("__global.backend")
if err != nil {
return err
}
if source == nil {
return nil
}
name := filepath.Base(file)
ext := filepath.Ext(name)
root, err := tmpl.local.DSL.PublicRoot(data)
if err != nil {
log.Error("WriteGlobalScript: Get the public root error: %s. use %s", err.Error(), tmpl.local.DSL.Public.Root)
root = tmpl.local.DSL.Public.Root
}
target := filepath.Join(application.App.Root(), "public", root, fmt.Sprintf("__global%s", ext))
dir := filepath.Dir(target)
if exist, _ := os.Stat(dir); exist == nil {
os.MkdirAll(dir, os.ModePerm)
}
return os.WriteFile(target, source, 0644)
}
// SyncAssets sync the assets
func (tmpl *Template) SyncAssets(option *core.BuildOption) error {
@ -333,6 +364,12 @@ func (page *Page) Build(globalCtx *core.GlobalBuildContext, option *core.BuildOp
return warnings, fmt.Errorf("Write the page %s error: %s", page.Route, err.Error())
}
// Save the backend script file
err = page.writeBackendScript(option.Data)
if err != nil {
return warnings, fmt.Errorf("Write the backend script file error: %s", err.Error())
}
// Save the locale files
err = page.writeLocaleFiles(ctx, option.Data)
if err != nil {
@ -604,6 +641,51 @@ func (page *Page) writeLocaleFiles(ctx *core.BuildContext, data map[string]inter
return nil
}
func (page *Page) backendScriptSource() (string, []byte, error) {
backendFile := filepath.Join(page.Path, fmt.Sprintf("%s.backend.ts", page.Name))
if exist, _ := page.tmpl.local.fs.Exists(backendFile); !exist {
backendFile = filepath.Join(page.Path, fmt.Sprintf("%s.backend.js", page.Name))
}
if exist, _ := page.tmpl.local.fs.Exists(backendFile); !exist {
return "", nil, nil
}
source, err := page.tmpl.local.fs.ReadFile(backendFile)
if err != nil {
return "", nil, err
}
return backendFile, source, nil
}
func (page *Page) writeBackendScript(data map[string]interface{}) error {
file, source, err := page.backendScriptSource()
if err != nil {
return err
}
if source == nil {
return nil
}
ext := filepath.Ext(file)
scriptFile := fmt.Sprintf("%s%s", page.publicFile(data), ext)
scriptFileAbs := filepath.Join(application.App.Root(), scriptFile)
dir := filepath.Dir(scriptFileAbs)
if exist, _ := os.Stat(dir); exist == nil {
os.MkdirAll(dir, os.ModePerm)
}
err = os.WriteFile(scriptFileAbs, []byte(source), 0644)
if err != nil {
return err
}
core.RemoveCache(scriptFile)
return nil
}
// writeHTMLTo write the html to file
func (page *Page) writeHTML(html []byte, data map[string]interface{}) error {
htmlFile := fmt.Sprintf("%s.sui", page.publicFile(data))
@ -618,7 +700,6 @@ func (page *Page) writeHTML(html []byte, data map[string]interface{}) error {
}
core.RemoveCache(htmlFile)
log.Trace("The page %s is removed", htmlFile)
return nil
}
@ -635,6 +716,5 @@ func (page *Page) writeJitHTML(html []byte, data map[string]interface{}) error {
return err
}
core.RemoveCache(htmlFile)
log.Trace("The page %s is removed", htmlFile)
return nil
}

View file

@ -7,6 +7,7 @@ import (
"strings"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou/application"
"github.com/yaoapp/gou/fs"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/sui/core"
@ -156,6 +157,12 @@ func (local *Local) getTemplate(id string, path string) (*Template, error) {
tmpl.GlobalData = dataBytes
}
// load the __build.backend.ts / __build.backend.js
err := tmpl.loadBuildScript()
if err != nil {
return nil, err
}
return &tmpl, nil
}
@ -163,3 +170,10 @@ func (local *Local) getTemplate(id string, path string) (*Template, error) {
func (local *Local) getTemplateID(path string) string {
return filepath.Base(path)
}
// AppRoot get the app root
func (local *Local) AppRoot() string {
approot := application.App.Root()
localroot := local.fs.Root()
return strings.TrimPrefix(localroot, approot)
}

View file

@ -12,6 +12,7 @@ import (
"github.com/google/uuid"
"github.com/yaoapp/gou/process"
v8 "github.com/yaoapp/gou/runtime/v8"
"github.com/yaoapp/yao/sui/core"
"golang.org/x/text/language"
)
@ -85,6 +86,44 @@ func (tmpl *Template) Reload() error {
return nil
}
// LoadBuildScript load the build script
func (tmpl *Template) loadBuildScript() error {
file, source, err := tmpl.backendScriptSource("__build.backend")
if err != nil {
return err
}
if file == "" {
return nil
}
approot := tmpl.local.AppRoot()
file = filepath.Join(approot, file)
script, err := v8.MakeScript(source, file, 5*time.Second)
if err != nil {
return err
}
tmpl.BuildScript = script
return nil
}
func (tmpl *Template) backendScriptSource(name string) (string, []byte, error) {
path := filepath.Join(tmpl.Root, fmt.Sprintf("%s.ts", name))
if !tmpl.local.fs.IsFile(path) {
path = filepath.Join(tmpl.Root, fmt.Sprintf("%s.js", name))
}
if !tmpl.local.fs.IsFile(path) {
return "", nil, nil
}
content, err := tmpl.local.fs.ReadFile(path)
if err != nil {
return "", nil, err
}
return path, content, nil
}
// ExecBuildCompleteScripts execute the build complete scripts
func (tmpl *Template) ExecBuildCompleteScripts() []core.TemplateScirptResult {
if tmpl.Scripts == nil || len(tmpl.Scripts.BuildComplete) == 0 {