Merge pull request #669 from trheyi/main
refactor: Update parsing logic for JIT components
This commit is contained in:
commit
b989194236
7 changed files with 251 additions and 60 deletions
|
|
@ -40,7 +40,7 @@ func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Docume
|
||||||
|
|
||||||
ctx.sequence++
|
ctx.sequence++
|
||||||
|
|
||||||
namespace := Namespace(page.Name, ctx.sequence, option.ScriptMinify)
|
namespace := Namespace(page.Route, ctx.sequence, option.ScriptMinify)
|
||||||
page.namespace = namespace
|
page.namespace = namespace
|
||||||
|
|
||||||
html, err := page.BuildHTML(option)
|
html, err := page.BuildHTML(option)
|
||||||
|
|
@ -367,6 +367,11 @@ func (page *Page) BuildStyles(ctx *BuildContext, option *BuildOption, component
|
||||||
// BuildScripts build the scripts for the page
|
// BuildScripts build the scripts for the page
|
||||||
func (page *Page) BuildScripts(ctx *BuildContext, option *BuildOption, component string, namespace string) ([]ScriptNode, error) {
|
func (page *Page) BuildScripts(ctx *BuildContext, option *BuildOption, component string, namespace string) ([]ScriptNode, error) {
|
||||||
|
|
||||||
|
ispage := component == "__page"
|
||||||
|
if ispage {
|
||||||
|
component = ComponentName(page.Route, option.ScriptMinify)
|
||||||
|
}
|
||||||
|
|
||||||
scripts := []ScriptNode{}
|
scripts := []ScriptNode{}
|
||||||
if page.Codes.JS.Code == "" && page.Codes.TS.Code == "" {
|
if page.Codes.JS.Code == "" && page.Codes.TS.Code == "" {
|
||||||
return scripts, nil
|
return scripts, nil
|
||||||
|
|
@ -416,7 +421,7 @@ func (page *Page) BuildScripts(ctx *BuildContext, option *BuildOption, component
|
||||||
|
|
||||||
code := string(source)
|
code := string(source)
|
||||||
parent := "body"
|
parent := "body"
|
||||||
if component != "__page" {
|
if !ispage {
|
||||||
parent = "head"
|
parent = "head"
|
||||||
code = fmt.Sprintf("function %s(){\n%s\n}\n", component, addTabToEachLine(code))
|
code = fmt.Sprintf("function %s(){\n%s\n}\n", component, addTabToEachLine(code))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/evanw/esbuild/pkg/api"
|
"github.com/evanw/esbuild/pkg/api"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/yaoapp/gou/runtime/transform"
|
"github.com/yaoapp/gou/runtime/transform"
|
||||||
"github.com/yaoapp/kun/log"
|
"github.com/yaoapp/kun/log"
|
||||||
)
|
)
|
||||||
|
|
@ -93,44 +95,6 @@ func (page *Page) Compile(ctx *BuildContext, option *BuildOption) (string, error
|
||||||
return html, nil
|
return html, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTML return the html of the script
|
|
||||||
func (script ScriptNode) HTML() string {
|
|
||||||
|
|
||||||
attrs := []string{
|
|
||||||
"s:ns=\"" + script.Namespace + "\"",
|
|
||||||
"s:cn=\"" + script.Component + "\"",
|
|
||||||
}
|
|
||||||
if script.Attrs != nil {
|
|
||||||
for _, attr := range script.Attrs {
|
|
||||||
attrs = append(attrs, attr.Key+"=\""+attr.Val+"\"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Inline Script
|
|
||||||
if script.Source == "" {
|
|
||||||
return "<script " + strings.Join(attrs, " ") + "></script>"
|
|
||||||
}
|
|
||||||
return "<script " + strings.Join(attrs, " ") + ">\n" + script.Source + "\n</script>"
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTML return the html of the style node
|
|
||||||
func (style StyleNode) HTML() string {
|
|
||||||
attrs := []string{
|
|
||||||
"s:ns=\"" + style.Namespace + "\"",
|
|
||||||
"s:cn=\"" + style.Component + "\"",
|
|
||||||
}
|
|
||||||
if style.Attrs != nil {
|
|
||||||
for _, attr := range style.Attrs {
|
|
||||||
attrs = append(attrs, attr.Key+"=\""+attr.Val+"\"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Inline Style
|
|
||||||
if style.Source == "" {
|
|
||||||
return "<link " + strings.Join(attrs, " ") + "></link>"
|
|
||||||
}
|
|
||||||
return "<style " + strings.Join(attrs, " ") + ">\n" + style.Source + "\n</style>"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompileAsComponent compile the page as component
|
// CompileAsComponent compile the page as component
|
||||||
func (page *Page) CompileAsComponent(ctx *BuildContext, option *BuildOption) (string, error) {
|
func (page *Page) CompileAsComponent(ctx *BuildContext, option *BuildOption) (string, error) {
|
||||||
|
|
||||||
|
|
@ -148,8 +112,34 @@ func (page *Page) CompileAsComponent(ctx *BuildContext, option *BuildOption) (st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
page.ReplaceDocument(doc)
|
body := doc.Find("body")
|
||||||
return doc.Find("body").Html()
|
rawScripts, err := jsoniter.MarshalToString(ctx.scripts)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawStyles, err := jsoniter.MarshalToString(ctx.styles)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawOption, err := jsoniter.MarshalToString(option)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if body.Children().Length() == 0 {
|
||||||
|
return "", fmt.Errorf("page %s as component should have one root element", page.Route)
|
||||||
|
}
|
||||||
|
|
||||||
|
if body.Children().Length() > 1 {
|
||||||
|
return "", fmt.Errorf("page %s as component should have only one root element", page.Route)
|
||||||
|
}
|
||||||
|
|
||||||
|
body.Children().First().AppendHtml(fmt.Sprintf(`<script name="scripts" type="json">%s</script>`+"\n", rawScripts))
|
||||||
|
body.Children().First().AppendHtml(fmt.Sprintf(`<script name="styles" type="json">%s</script>`+"\n", rawStyles))
|
||||||
|
body.Children().First().AppendHtml(fmt.Sprintf(`<script name="option" type="json">%s</script>`+"\n", rawOption))
|
||||||
|
return body.Html()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompileJS compile the javascript
|
// CompileJS compile the javascript
|
||||||
|
|
@ -212,3 +202,62 @@ func (page *Page) CompileCSS(source []byte, minify bool) ([]byte, error) {
|
||||||
func (page *Page) CompileHTML(source []byte, minify bool) ([]byte, error) {
|
func (page *Page) CompileHTML(source []byte, minify bool) ([]byte, error) {
|
||||||
return source, nil
|
return source, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTML return the html of the script
|
||||||
|
func (script ScriptNode) HTML() string {
|
||||||
|
|
||||||
|
attrs := []string{
|
||||||
|
"s:ns=\"" + script.Namespace + "\"",
|
||||||
|
"s:cn=\"" + script.Component + "\"",
|
||||||
|
}
|
||||||
|
if script.Attrs != nil {
|
||||||
|
for _, attr := range script.Attrs {
|
||||||
|
attrs = append(attrs, attr.Key+"=\""+attr.Val+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Inline Script
|
||||||
|
if script.Source == "" {
|
||||||
|
return "<script " + strings.Join(attrs, " ") + "></script>"
|
||||||
|
}
|
||||||
|
return "<script " + strings.Join(attrs, " ") + ">\n" + script.Source + "\n</script>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComponentHTML return the html of the script
|
||||||
|
func (script ScriptNode) ComponentHTML(ns string) string {
|
||||||
|
|
||||||
|
attrs := []string{
|
||||||
|
"s:ns=\"" + ns + "\"",
|
||||||
|
"s:cn=\"" + script.Component + "\"",
|
||||||
|
}
|
||||||
|
if script.Attrs != nil {
|
||||||
|
for _, attr := range script.Attrs {
|
||||||
|
attrs = append(attrs, attr.Key+"=\""+attr.Val+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Inline Script
|
||||||
|
if script.Source == "" {
|
||||||
|
return "<script " + strings.Join(attrs, " ") + "></script>"
|
||||||
|
}
|
||||||
|
|
||||||
|
source := fmt.Sprintf(`function %s(){%s};`, script.Component, script.Source)
|
||||||
|
return "<script " + strings.Join(attrs, " ") + ">\n" + source + "\n</script>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTML return the html of the style node
|
||||||
|
func (style StyleNode) HTML() string {
|
||||||
|
attrs := []string{
|
||||||
|
"s:ns=\"" + style.Namespace + "\"",
|
||||||
|
"s:cn=\"" + style.Component + "\"",
|
||||||
|
}
|
||||||
|
if style.Attrs != nil {
|
||||||
|
for _, attr := range style.Attrs {
|
||||||
|
attrs = append(attrs, attr.Key+"=\""+attr.Val+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Inline Style
|
||||||
|
if style.Source == "" {
|
||||||
|
return "<link " + strings.Join(attrs, " ") + "></link>"
|
||||||
|
}
|
||||||
|
return "<style " + strings.Join(attrs, " ") + ">\n" + style.Source + "\n</style>"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
144
sui/core/jit.go
144
sui/core/jit.go
|
|
@ -4,18 +4,23 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/yaoapp/gou/application"
|
"github.com/yaoapp/gou/application"
|
||||||
)
|
)
|
||||||
|
|
||||||
// JitComponent component
|
// JitComponent component
|
||||||
type JitComponent struct {
|
type JitComponent struct {
|
||||||
html string
|
file string
|
||||||
scripts []ScriptNode
|
route string
|
||||||
styles []StyleNode
|
html string
|
||||||
|
scripts []ScriptNode
|
||||||
|
styles []StyleNode
|
||||||
|
buildOption *BuildOption
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -32,6 +37,9 @@ type componentData struct {
|
||||||
// Components loaded JIT components
|
// Components loaded JIT components
|
||||||
var Components = map[string]*JitComponent{}
|
var Components = map[string]*JitComponent{}
|
||||||
var chComp = make(chan *componentData, 1)
|
var chComp = make(chan *componentData, 1)
|
||||||
|
var reScripts = regexp.MustCompile(`<script[^>]*name="scripts"[^>]*>(.*?)</script>`)
|
||||||
|
var reStyles = regexp.MustCompile(`<script[^>]*name="styles"[^>]*>(.*?)</script>`)
|
||||||
|
var reOption = regexp.MustCompile(`<script[^>]*name="option"[^>]*>(.*?)</script>`)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
go componentWriter()
|
go componentWriter()
|
||||||
|
|
@ -47,17 +55,18 @@ func (parser *TemplateParser) parseComponent(sel *goquery.Selection) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
html, err := parser.RenderComponent(comp, props, slots)
|
html, _, err := parser.RenderComponent(comp, props, slots)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
parser.errors = append(parser.errors, err)
|
parser.errors = append(parser.errors, err)
|
||||||
setError(sel, err)
|
setError(sel, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sel.SetHtml(html)
|
sel.SetHtml(html)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderComponent render the component
|
// RenderComponent render the component
|
||||||
func (parser *TemplateParser) RenderComponent(comp *JitComponent, props map[string]interface{}, slots *goquery.Selection) (string, error) {
|
func (parser *TemplateParser) RenderComponent(comp *JitComponent, props map[string]interface{}, slots *goquery.Selection) (string, string, error) {
|
||||||
html := comp.html
|
html := comp.html
|
||||||
randvar := fmt.Sprintf("__%s_$props", time.Now().Format("20060102150405"))
|
randvar := fmt.Sprintf("__%s_$props", time.Now().Format("20060102150405"))
|
||||||
html = slotRe.ReplaceAllStringFunc(html, func(exp string) string {
|
html = slotRe.ReplaceAllStringFunc(html, func(exp string) string {
|
||||||
|
|
@ -77,7 +86,7 @@ func (parser *TemplateParser) RenderComponent(comp *JitComponent, props map[stri
|
||||||
|
|
||||||
sel, err := NewDocumentString(`<body>` + html + `</body>`)
|
sel, err := NewDocumentString(`<body>` + html + `</body>`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
root := sel.Find("body")
|
root := sel.Find("body")
|
||||||
|
|
@ -103,15 +112,65 @@ func (parser *TemplateParser) RenderComponent(comp *JitComponent, props map[stri
|
||||||
compParser := NewTemplateParser(data, &option)
|
compParser := NewTemplateParser(data, &option)
|
||||||
|
|
||||||
// Parse the node
|
// Parse the node
|
||||||
|
ns := Namespace(comp.route, compParser.sequence, comp.buildOption.ScriptMinify)
|
||||||
|
cn := ComponentName(comp.route, comp.buildOption.ScriptMinify)
|
||||||
compParser.parseNode(root.Get(0))
|
compParser.parseNode(root.Get(0))
|
||||||
for sel, nodes := range compParser.replace {
|
for sel, nodes := range compParser.replace {
|
||||||
sel.ReplaceWithNodes(nodes...)
|
sel.ReplaceWithNodes(nodes...)
|
||||||
delete(parser.replace, sel)
|
delete(parser.replace, sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if comp.scripts != nil {
|
||||||
|
for _, script := range comp.scripts {
|
||||||
|
script.Namespace = ns
|
||||||
|
parser.scripts = append(parser.scripts, script)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if comp.styles != nil {
|
||||||
|
for _, style := range comp.styles {
|
||||||
|
style.Namespace = ns
|
||||||
|
parser.styles = append(parser.styles, style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update sequence
|
// Update sequence
|
||||||
parser.sequence = compParser.sequence + parser.sequence
|
parser.sequence = compParser.sequence + parser.sequence
|
||||||
return root.Html()
|
first := root.Children().First()
|
||||||
|
first.SetAttr("s:ns", ns)
|
||||||
|
first.SetAttr("s:cn", cn)
|
||||||
|
first.SetAttr("s:ready", cn+"()")
|
||||||
|
html, err = root.Html()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return html, ns, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (parser *TemplateParser) addScripts(sel *goquery.Selection, scripts []ScriptNode) {
|
||||||
|
if scripts == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, script := range scripts {
|
||||||
|
query := fmt.Sprintf(`script[s\:cn="%s"]`, script.Component)
|
||||||
|
if sel.Find(query).Length() > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sel.AppendHtml(script.ComponentHTML(script.Namespace))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (parser *TemplateParser) addStyles(sel *goquery.Selection, styles []StyleNode) {
|
||||||
|
if styles == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, style := range styles {
|
||||||
|
query := fmt.Sprintf(`style[s\:cn="%s"]`, style.Component)
|
||||||
|
if sel.Find(query).Length() > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sel.Append(style.HTML())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *TemplateParser) getComponent(sel *goquery.Selection) (*JitComponent, map[string]interface{}, *goquery.Selection, error) {
|
func (parser *TemplateParser) getComponent(sel *goquery.Selection) (*JitComponent, map[string]interface{}, *goquery.Selection, error) {
|
||||||
|
|
@ -123,12 +182,12 @@ func (parser *TemplateParser) getComponent(sel *goquery.Selection) (*JitComponen
|
||||||
return nil, nil, slots, err
|
return nil, nil, slots, err
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := parser.componentFile(sel, props)
|
file, route, err := parser.componentFile(sel, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, props, slots, err
|
return nil, props, slots, err
|
||||||
}
|
}
|
||||||
|
|
||||||
comp, err := getComponent(file, parser.disableCache())
|
comp, err := getComponent(route, file, parser.disableCache())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, props, slots, err
|
return nil, props, slots, err
|
||||||
}
|
}
|
||||||
|
|
@ -225,10 +284,10 @@ func (parser *TemplateParser) parseComponentProps(props map[string]string) (map[
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *TemplateParser) componentFile(sel *goquery.Selection, props map[string]interface{}) (string, error) {
|
func (parser *TemplateParser) componentFile(sel *goquery.Selection, props map[string]interface{}) (string, string, error) {
|
||||||
route := sel.AttrOr("is", "")
|
route := sel.AttrOr("is", "")
|
||||||
if route == "" {
|
if route == "" {
|
||||||
return "", fmt.Errorf("Component route is required")
|
return "", "", fmt.Errorf("Component route is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
data := Data{"$props": props}
|
data := Data{"$props": props}
|
||||||
|
|
@ -236,7 +295,7 @@ func (parser *TemplateParser) componentFile(sel *goquery.Selection, props map[st
|
||||||
route, _ = parser.data.Replace(route)
|
route, _ = parser.data.Replace(route)
|
||||||
root := sel.AttrOr("s:root", "/")
|
root := sel.AttrOr("s:root", "/")
|
||||||
file := filepath.Join(string(os.PathSeparator), "public", root, route+".jit")
|
file := filepath.Join(string(os.PathSeparator), "public", root, route+".jit")
|
||||||
return file, nil
|
return file, route, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func componentWriter() {
|
func componentWriter() {
|
||||||
|
|
@ -253,7 +312,7 @@ func componentWriter() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getComponent(file string, disableCache ...bool) (*JitComponent, error) {
|
func getComponent(route string, file string, disableCache ...bool) (*JitComponent, error) {
|
||||||
|
|
||||||
noCache := false
|
noCache := false
|
||||||
if len(disableCache) > 0 && disableCache[0] {
|
if len(disableCache) > 0 && disableCache[0] {
|
||||||
|
|
@ -264,7 +323,7 @@ func getComponent(file string, disableCache ...bool) (*JitComponent, error) {
|
||||||
return comp, nil
|
return comp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
comp, err := readComponent(file)
|
comp, err := readComponent(route, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -275,10 +334,63 @@ func getComponent(file string, disableCache ...bool) (*JitComponent, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// readComponent read the JIT component
|
// readComponent read the JIT component
|
||||||
func readComponent(file string) (*JitComponent, error) {
|
func readComponent(route string, file string) (*JitComponent, error) {
|
||||||
content, err := application.App.Read(file)
|
content, err := application.App.Read(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &JitComponent{html: string(content)}, nil
|
|
||||||
|
// Get the scripts
|
||||||
|
html := string(content)
|
||||||
|
rawScripts := ""
|
||||||
|
rawStyles := ""
|
||||||
|
rawOption := ""
|
||||||
|
html = reScripts.ReplaceAllStringFunc(html, func(exp string) string {
|
||||||
|
rawScripts = reScripts.ReplaceAllString(exp, "$1")
|
||||||
|
return ""
|
||||||
|
})
|
||||||
|
|
||||||
|
html = reStyles.ReplaceAllStringFunc(html, func(exp string) string {
|
||||||
|
rawStyles = reStyles.ReplaceAllString(exp, "$1")
|
||||||
|
return ""
|
||||||
|
})
|
||||||
|
|
||||||
|
html = reOption.ReplaceAllStringFunc(html, func(exp string) string {
|
||||||
|
rawOption = reOption.ReplaceAllString(exp, "$1")
|
||||||
|
return ""
|
||||||
|
})
|
||||||
|
|
||||||
|
scripts := []ScriptNode{}
|
||||||
|
styles := []StyleNode{}
|
||||||
|
buildOption := BuildOption{}
|
||||||
|
|
||||||
|
if rawScripts != "" {
|
||||||
|
err := jsoniter.UnmarshalFromString(rawScripts, &scripts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rawStyles != "" {
|
||||||
|
err := jsoniter.UnmarshalFromString(rawStyles, &styles)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rawOption != "" {
|
||||||
|
err := jsoniter.UnmarshalFromString(rawOption, &buildOption)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &JitComponent{
|
||||||
|
file: file,
|
||||||
|
route: route,
|
||||||
|
html: html,
|
||||||
|
scripts: scripts,
|
||||||
|
styles: styles,
|
||||||
|
buildOption: &buildOption,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ type TemplateParser struct {
|
||||||
option *ParserOption // parser option
|
option *ParserOption // parser option
|
||||||
locale *Locale // locale
|
locale *Locale // locale
|
||||||
context *ParserContext // parser context
|
context *ParserContext // parser context
|
||||||
|
scripts []ScriptNode // scripts
|
||||||
|
styles []StyleNode // styles
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParserContext parser context for the template
|
// ParserContext parser context for the template
|
||||||
|
|
@ -171,6 +173,8 @@ func NewTemplateParser(data Data, option *ParserOption) *TemplateParser {
|
||||||
errors: []error{},
|
errors: []error{},
|
||||||
replace: map[*goquery.Selection][]*html.Node{},
|
replace: map[*goquery.Selection][]*html.Node{},
|
||||||
option: option,
|
option: option,
|
||||||
|
scripts: []ScriptNode{},
|
||||||
|
styles: []StyleNode{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,6 +206,8 @@ func (parser *TemplateParser) Render(html string) (string, error) {
|
||||||
head := doc.Find("head")
|
head := doc.Find("head")
|
||||||
if head.Length() > 0 {
|
if head.Length() > 0 {
|
||||||
head.AppendHtml(headInjectionScript())
|
head.AppendHtml(headInjectionScript())
|
||||||
|
parser.addScripts(head, parser.scripts)
|
||||||
|
parser.addStyles(head, parser.styles)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the data to the body
|
// Append the data to the body
|
||||||
|
|
|
||||||
|
|
@ -191,8 +191,9 @@ type Template struct {
|
||||||
|
|
||||||
// TemplateScirpts is the struct for the template scripts
|
// TemplateScirpts is the struct for the template scripts
|
||||||
type TemplateScirpts struct {
|
type TemplateScirpts struct {
|
||||||
BeforeBuild []*TemplateScript `json:"before:build,omitempty"` // Run before build
|
BeforeBuild []*TemplateScript `json:"before:build,omitempty"` // Run before build
|
||||||
AfterBuild []*TemplateScript `json:"after:build,omitempty"` // Run after build
|
AfterBuild []*TemplateScript `json:"after:build,omitempty"` // Run after build
|
||||||
|
BuildComplete []*TemplateScript `json:"build:complete,omitempty"` // Run build complete
|
||||||
}
|
}
|
||||||
|
|
||||||
// TemplateScript is the struct for the template script
|
// TemplateScript is the struct for the template script
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ import (
|
||||||
// Build the template
|
// Build the template
|
||||||
func (tmpl *Template) Build(option *core.BuildOption) error {
|
func (tmpl *Template) Build(option *core.BuildOption) error {
|
||||||
var err error
|
var err error
|
||||||
|
defer func() {
|
||||||
|
if option.ExecScripts {
|
||||||
|
tmpl.ExecBuildCompleteScripts()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Execute the build before hook
|
// Execute the build before hook
|
||||||
if option.ExecScripts {
|
if option.ExecScripts {
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,14 @@ func (tmpl *Template) Reload() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecBuildCompleteScripts execute the build complete scripts
|
||||||
|
func (tmpl *Template) ExecBuildCompleteScripts() []core.TemplateScirptResult {
|
||||||
|
if tmpl.Scripts == nil || len(tmpl.Scripts.BuildComplete) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return tmpl.ExecScripts(tmpl.Scripts.BuildComplete)
|
||||||
|
}
|
||||||
|
|
||||||
// ExecBeforeBuildScripts execute the before build scripts
|
// ExecBeforeBuildScripts execute the before build scripts
|
||||||
func (tmpl *Template) ExecBeforeBuildScripts() []core.TemplateScirptResult {
|
func (tmpl *Template) ExecBeforeBuildScripts() []core.TemplateScirptResult {
|
||||||
if tmpl.Scripts == nil || len(tmpl.Scripts.BeforeBuild) == 0 {
|
if tmpl.Scripts == nil || len(tmpl.Scripts.BeforeBuild) == 0 {
|
||||||
|
|
@ -97,7 +105,12 @@ func (tmpl *Template) ExecAfterBuildScripts() []core.TemplateScirptResult {
|
||||||
|
|
||||||
// ExecScripts execute the scripts
|
// ExecScripts execute the scripts
|
||||||
func (tmpl *Template) ExecScripts(scripts []*core.TemplateScript) []core.TemplateScirptResult {
|
func (tmpl *Template) ExecScripts(scripts []*core.TemplateScript) []core.TemplateScirptResult {
|
||||||
|
|
||||||
results := []core.TemplateScirptResult{}
|
results := []core.TemplateScirptResult{}
|
||||||
|
if scripts == nil {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
switch script.Type {
|
switch script.Type {
|
||||||
case "command":
|
case "command":
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue