[feat] Sharing the Constants variable between frontend and backend scripts
This commit is contained in:
parent
9418133b32
commit
58ca39a32b
9 changed files with 287 additions and 19 deletions
|
|
@ -167,6 +167,7 @@ func (r *Request) Render() (string, int, error) {
|
|||
DisableCache: r.Request.DisableCache(),
|
||||
Route: r.Request.URL.Path,
|
||||
Root: c.Root,
|
||||
Script: c.Script,
|
||||
Request: true,
|
||||
}
|
||||
|
||||
|
|
@ -254,6 +255,12 @@ func (r *Request) MakeCache() (*core.Cache, int, error) {
|
|||
return nil, 500, fmt.Errorf("parse error, please re-complie the page %s", err.Error())
|
||||
}
|
||||
|
||||
// Backend script
|
||||
script, err := core.LoadScript(r.File)
|
||||
if err != nil {
|
||||
return nil, 500, fmt.Errorf("script error, please re-complie the page %s", err.Error())
|
||||
}
|
||||
|
||||
// Save to The Cache
|
||||
cache := &core.Cache{
|
||||
Data: dataText,
|
||||
|
|
@ -266,6 +273,7 @@ func (r *Request) MakeCache() (*core.Cache, int, error) {
|
|||
Root: root,
|
||||
CacheTime: time.Duration(cacheTime) * time.Second,
|
||||
DataCacheTime: time.Duration(dataCacheTime) * time.Second,
|
||||
Script: script,
|
||||
}
|
||||
|
||||
go core.SetCache(r.File, cache)
|
||||
|
|
|
|||
|
|
@ -589,6 +589,16 @@ func (page *Page) BuildScripts(ctx *BuildContext, option *BuildOption, component
|
|||
}
|
||||
injectScript := componentInitScript(arguments)
|
||||
|
||||
// Get the Constants and Helpers
|
||||
var err error = nil
|
||||
constants := ""
|
||||
if page.Script != nil {
|
||||
constants, err = page.Script.ConstantsToString()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
scripts := []ScriptNode{}
|
||||
if page.Codes.JS.Code == "" && page.Codes.TS.Code == "" {
|
||||
return scripts, nil
|
||||
|
|
@ -599,7 +609,6 @@ func (page *Page) BuildScripts(ctx *BuildContext, option *BuildOption, component
|
|||
|
||||
ctx.scriptUnique[component] = true
|
||||
|
||||
var err error = nil
|
||||
var imports []string = nil
|
||||
var source []byte = nil
|
||||
if page.Codes.TS.Code != "" {
|
||||
|
|
@ -639,6 +648,10 @@ func (page *Page) BuildScripts(ctx *BuildContext, option *BuildOption, component
|
|||
})
|
||||
|
||||
code := string(source)
|
||||
if constants != "" {
|
||||
code = fmt.Sprintf("this.Constants = %s\n%s", constants, code)
|
||||
}
|
||||
|
||||
parent := "body"
|
||||
if !ispage {
|
||||
parent = "head"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ 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"
|
||||
)
|
||||
|
|
@ -21,7 +20,7 @@ type Cache struct {
|
|||
CacheStore string
|
||||
CacheTime time.Duration
|
||||
DataCacheTime time.Duration
|
||||
Script *v8.Script // the backend script
|
||||
Script *Script
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
@ -73,6 +72,7 @@ func GetCache(file string) *Cache {
|
|||
// RemoveCache remove the cache
|
||||
func RemoveCache(file string) {
|
||||
ch <- &cacheData{file, nil, removeCache}
|
||||
chScript <- &scriptData{file, nil, removeScript}
|
||||
}
|
||||
|
||||
// CleanCache clean the cache
|
||||
|
|
|
|||
|
|
@ -186,6 +186,26 @@ const componentInitScriptTmpl = `
|
|||
this.store = new __sui_store(this.root);
|
||||
`
|
||||
|
||||
// Inject code
|
||||
const backendScriptTmpl = `
|
||||
this.__sui_page = '%s';
|
||||
this.__sui_constants = {};
|
||||
this.__sui_helpers = [];
|
||||
this.__sui_hooks = null;
|
||||
|
||||
if (typeof Helpers === 'object') {
|
||||
this.__sui_helpers = Object.keys(Helpers);
|
||||
}
|
||||
|
||||
if (typeof Hooks === 'function') {
|
||||
this.__sui_hooks = new Hooks();
|
||||
}
|
||||
|
||||
if (typeof Constants === 'object') {
|
||||
this.__sui_constants = Constants;
|
||||
}
|
||||
`
|
||||
|
||||
func bodyInjectionScript(jsonRaw string, debug bool) string {
|
||||
jsPrintData := ""
|
||||
if debug {
|
||||
|
|
@ -209,3 +229,8 @@ func compEventInjectScript(eventID, eventName, component, dataKeys, jsonKeys, ha
|
|||
func componentInitScript(root string) string {
|
||||
return fmt.Sprintf(componentInitScriptTmpl, root)
|
||||
}
|
||||
|
||||
// BackendScript inject the backend script
|
||||
func BackendScript(route string) string {
|
||||
return fmt.Sprintf(backendScriptTmpl, route)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,16 +40,17 @@ type Mapping struct {
|
|||
|
||||
// ParserOption parser option
|
||||
type ParserOption struct {
|
||||
Component bool `json:"component,omitempty"`
|
||||
Editor bool `json:"editor,omitempty"`
|
||||
Preview bool `json:"preview,omitempty"`
|
||||
Debug bool `json:"debug,omitempty"`
|
||||
DisableCache bool `json:"disableCache,omitempty"`
|
||||
Request bool `json:"request,omitempty"`
|
||||
Route string `json:"route,omitempty"`
|
||||
Theme any `json:"theme,omitempty"`
|
||||
Locale any `json:"locale,omitempty"`
|
||||
Root string `json:"root,omitempty"`
|
||||
Component bool `json:"component,omitempty"`
|
||||
Editor bool `json:"editor,omitempty"`
|
||||
Preview bool `json:"preview,omitempty"`
|
||||
Debug bool `json:"debug,omitempty"`
|
||||
DisableCache bool `json:"disableCache,omitempty"`
|
||||
Request bool `json:"request,omitempty"`
|
||||
Route string `json:"route,omitempty"`
|
||||
Theme any `json:"theme,omitempty"`
|
||||
Locale any `json:"locale,omitempty"`
|
||||
Root string `json:"root,omitempty"`
|
||||
Script *Script `json:"-"` // backend script
|
||||
}
|
||||
|
||||
var keepWords = map[string]bool{
|
||||
|
|
|
|||
191
sui/core/script.go
Normal file
191
sui/core/script.go
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/yaoapp/gou/application"
|
||||
v8 "github.com/yaoapp/gou/runtime/v8"
|
||||
"github.com/yaoapp/gou/runtime/v8/bridge"
|
||||
)
|
||||
|
||||
// Scripts loaded scripts
|
||||
var Scripts = map[string]*Script{}
|
||||
|
||||
const (
|
||||
saveScript uint8 = iota
|
||||
removeScript
|
||||
)
|
||||
|
||||
// Script the script
|
||||
type Script struct {
|
||||
*v8.Script
|
||||
}
|
||||
|
||||
type scriptData struct {
|
||||
file string
|
||||
script *Script
|
||||
cmd uint8
|
||||
}
|
||||
|
||||
var chScript = make(chan *scriptData, 1)
|
||||
|
||||
func init() {
|
||||
go scriptWriter()
|
||||
}
|
||||
|
||||
func scriptWriter() {
|
||||
for {
|
||||
select {
|
||||
case data := <-chScript:
|
||||
switch data.cmd {
|
||||
case saveScript:
|
||||
Scripts[data.file] = data.script
|
||||
case removeScript:
|
||||
delete(Scripts, data.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LoadScript load the script
|
||||
func LoadScript(file string) (*Script, error) {
|
||||
|
||||
if script, has := Scripts[file]; has {
|
||||
return script, nil
|
||||
}
|
||||
|
||||
base := strings.TrimSuffix(file, ".sui")
|
||||
file = base + ".ts"
|
||||
if exist, _ := application.App.Exists(file); !exist {
|
||||
file = base + ".js"
|
||||
}
|
||||
|
||||
if exist, _ := application.App.Exists(file); !exist {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
source, err := application.App.Read(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v8script, err := v8.MakeScript(source, file, 5*time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
script := &Script{Script: v8script}
|
||||
chScript <- &scriptData{file, script, saveScript}
|
||||
return script, nil
|
||||
}
|
||||
|
||||
// Call the script method
|
||||
// This will be refactored to improve the performance
|
||||
func (script *Script) Call(r *Request, method string, args ...any) (interface{}, error) {
|
||||
ctx, err := script.NewContext(r.Sid, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ctx.Close()
|
||||
|
||||
res, err := ctx.Call(method, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ConstantsToString get the constants from the script
|
||||
func (script *Script) ConstantsToString() (string, error) {
|
||||
constants, err := script.Constants()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
raw, err := jsoniter.MarshalToString(constants)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// Constants get the constants from the script
|
||||
// This will be refactored to improve the performance
|
||||
func (script *Script) Constants() (map[string]interface{}, error) {
|
||||
uuid := uuid.New().String()
|
||||
ctx, err := script.NewContext(uuid, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ctx.Close()
|
||||
|
||||
global := ctx.Global()
|
||||
if global == nil {
|
||||
return nil, fmt.Errorf("global is nil")
|
||||
}
|
||||
|
||||
if !global.Has("__sui_constants") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
res, err := global.Get("__sui_constants")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Release()
|
||||
|
||||
goValues, err := bridge.GoValue(res, ctx.Context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if constants, ok := goValues.(map[string]interface{}); ok {
|
||||
return constants, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("constants is %v should be Record<string, any>", goValues)
|
||||
}
|
||||
|
||||
// Helpers get the helpers from the script
|
||||
// This will be refactored to improve the performance
|
||||
func (script *Script) Helpers() ([]string, error) {
|
||||
uuid := uuid.New().String()
|
||||
ctx, err := script.NewContext(uuid, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ctx.Close()
|
||||
|
||||
global := ctx.Global()
|
||||
if global == nil {
|
||||
return nil, fmt.Errorf("global is nil")
|
||||
}
|
||||
|
||||
if !global.Has("__sui_helpers") {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
res, err := global.Get("__sui_helpers")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Release()
|
||||
|
||||
goValues, err := bridge.GoValue(res, ctx.Context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if helpers, ok := goValues.([]interface{}); ok {
|
||||
methods := []string{}
|
||||
for _, key := range helpers {
|
||||
methods = append(methods, fmt.Sprintf("%v", key))
|
||||
}
|
||||
return methods, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("helpers is %v should be []string", goValues)
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"regexp"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
v8 "github.com/yaoapp/gou/runtime/v8"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
|
|
@ -39,7 +38,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
|
||||
Script *Script `json:"-"` // The backend script name.backend.ts / name.backend.js
|
||||
Document []byte `json:"-"`
|
||||
GlobalData []byte `json:"-"`
|
||||
Attrs map[string]string `json:"-"`
|
||||
|
|
@ -179,8 +178,8 @@ type Template struct {
|
|||
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
|
||||
BuildScript *Script `json:"-"` // __build.backend.ts / __build.backend.js
|
||||
GlobalScript *Script `json:"-"` // __global.backend.ts / __global.backend.js
|
||||
}
|
||||
|
||||
// TemplateScirpts is the struct for the template scripts
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/yaoapp/gou/application"
|
||||
"github.com/yaoapp/gou/process"
|
||||
v8 "github.com/yaoapp/gou/runtime/v8"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/yao/sui/core"
|
||||
"golang.org/x/text/language"
|
||||
|
|
@ -338,7 +340,6 @@ func (tmpl *Template) getLocale(name string, route string, pageOnly ...bool) cor
|
|||
func (page *Page) Build(globalCtx *core.GlobalBuildContext, option *core.BuildOption) ([]string, error) {
|
||||
|
||||
ctx := core.NewBuildContext(globalCtx)
|
||||
|
||||
var err error = nil
|
||||
root := option.PublicRoot
|
||||
if root == "" {
|
||||
|
|
@ -353,6 +354,11 @@ func (page *Page) Build(globalCtx *core.GlobalBuildContext, option *core.BuildOp
|
|||
}
|
||||
page.Root = root
|
||||
|
||||
err = page.loadBackendScript()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
html, warnings, err := page.Page.Compile(ctx, option)
|
||||
if err != nil {
|
||||
return warnings, fmt.Errorf("Compile the page %s error: %s", page.Route, err.Error())
|
||||
|
|
@ -425,6 +431,11 @@ func (page *Page) BuildAsComponent(globalCtx *core.GlobalBuildContext, option *c
|
|||
option.AssetRoot = filepath.Join(root, "assets")
|
||||
}
|
||||
|
||||
err := page.loadBackendScript()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
html, messages, err := page.Page.CompileAsComponent(ctx, option)
|
||||
if err != nil {
|
||||
return warnings, err
|
||||
|
|
@ -656,9 +667,29 @@ func (page *Page) backendScriptSource() (string, []byte, error) {
|
|||
return "", nil, err
|
||||
}
|
||||
|
||||
source = []byte(fmt.Sprintf("%s\n%s", source, core.BackendScript(page.Route)))
|
||||
return backendFile, source, nil
|
||||
}
|
||||
|
||||
func (page *Page) loadBackendScript() error {
|
||||
file, source, err := page.backendScriptSource()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if source == nil {
|
||||
return nil
|
||||
}
|
||||
approot := page.tmpl.local.AppRoot()
|
||||
file = filepath.Join(approot, file)
|
||||
script, err := v8.MakeScript(source, file, 5*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
page.Script = &core.Script{Script: script}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (page *Page) writeBackendScript(data map[string]interface{}) error {
|
||||
|
||||
file, source, err := page.backendScriptSource()
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ func (tmpl *Template) loadBuildScript() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpl.BuildScript = script
|
||||
tmpl.BuildScript = &core.Script{Script: script}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue