[add] Support for JIT mode in SUI component imports ( dev )
This commit is contained in:
parent
6fa9eb51ab
commit
28537e2163
12 changed files with 208 additions and 29 deletions
|
|
@ -13,7 +13,7 @@ func TestCompile(t *testing.T) {
|
|||
loadTestSui(t)
|
||||
|
||||
page := testPage(t)
|
||||
html, err := page.Compile(&core.BuildOption{KeepPageTag: false})
|
||||
html, err := page.Compile(nil, &core.BuildOption{KeepPageTag: false})
|
||||
if err != nil {
|
||||
t.Fatalf("Compile error: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1004,7 +1004,7 @@ func BuildPage(process *process.Process) interface{} {
|
|||
}
|
||||
|
||||
data := process.ArgsMap(5, map[string]interface{}{})
|
||||
err = page.Build(&core.BuildOption{SSR: ssr, AssetRoot: assetRoot, Data: data})
|
||||
err = page.Build(nil, &core.BuildOption{SSR: ssr, AssetRoot: assetRoot, Data: data})
|
||||
if err != nil {
|
||||
exception.New(err.Error(), 500).Throw()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,16 +19,6 @@ var cssRe = regexp.MustCompile(`([\.a-z0-9A-Z-:# ]+)\{`)
|
|||
var langFuncRe = regexp.MustCompile(`L\s*\(\s*["'](.*?)["']\s*\)`)
|
||||
var langAttrRe = regexp.MustCompile(`'::(.*?)'`)
|
||||
|
||||
// NewBuildContext create a new build context
|
||||
func NewBuildContext() *BuildContext {
|
||||
return &BuildContext{
|
||||
components: map[string]bool{},
|
||||
sequence: 1,
|
||||
scripts: []string{},
|
||||
styles: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// Build is the struct for the public
|
||||
func (page *Page) Build(ctx *BuildContext, option *BuildOption) (*goquery.Document, []string, error) {
|
||||
|
||||
|
|
@ -148,6 +138,7 @@ func (page *Page) BuildForImport(ctx *BuildContext, option *BuildOption, slots m
|
|||
|
||||
func (page *Page) parse(ctx *BuildContext, doc *goquery.Document, option *BuildOption, warnings []string) error {
|
||||
|
||||
// Find the import pages
|
||||
pages := doc.Find("*").FilterFunction(func(i int, sel *goquery.Selection) bool {
|
||||
|
||||
// Get the translation
|
||||
|
|
@ -164,8 +155,12 @@ func (page *Page) parse(ctx *BuildContext, doc *goquery.Document, option *BuildO
|
|||
return false
|
||||
}
|
||||
|
||||
_, has := sel.Attr("is")
|
||||
return has
|
||||
name, has := sel.Attr("is")
|
||||
_, jit := sel.Attr("s:jit") // Just in time rendering
|
||||
if has && jit {
|
||||
ctx.addJitComponent(name)
|
||||
}
|
||||
return has && !jit
|
||||
})
|
||||
|
||||
sui := SUIs[page.SuiID]
|
||||
|
|
|
|||
|
|
@ -16,9 +16,8 @@ var importAssetsRe = regexp.MustCompile(`import\s*\t*\n*\s*['"]@assets\/([^'"]+)
|
|||
var AssetsRe = regexp.MustCompile(`[` + quoteRe + `]@assets\/([^` + quoteRe + `]+)[` + quoteRe + `]`) // '@assets/foo.js' or "@assets/foo.js" or `@assets/foo`
|
||||
|
||||
// Compile the page
|
||||
func (page *Page) Compile(option *BuildOption) (string, error) {
|
||||
func (page *Page) Compile(ctx *BuildContext, option *BuildOption) (string, error) {
|
||||
|
||||
ctx := NewBuildContext()
|
||||
doc, warnings, err := page.Build(ctx, option)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
|||
54
sui/core/context.go
Normal file
54
sui/core/context.go
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package core
|
||||
|
||||
// NewBuildContext create a new build context
|
||||
func NewBuildContext(global *GlobalBuildContext) *BuildContext {
|
||||
return &BuildContext{
|
||||
components: map[string]bool{},
|
||||
sequence: 1,
|
||||
scripts: []string{},
|
||||
styles: []string{},
|
||||
jitComponents: map[string]bool{},
|
||||
global: global,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGlobalBuildContext create a new global build context
|
||||
func NewGlobalBuildContext() *GlobalBuildContext {
|
||||
return &GlobalBuildContext{
|
||||
jitComponents: map[string]bool{},
|
||||
}
|
||||
}
|
||||
|
||||
// GetJitComponents get the just in time components
|
||||
func (ctx *BuildContext) GetJitComponents() []string {
|
||||
if ctx.jitComponents == nil {
|
||||
return []string{}
|
||||
}
|
||||
jitComponents := []string{}
|
||||
for name := range ctx.jitComponents {
|
||||
jitComponents = append(jitComponents, name)
|
||||
}
|
||||
return jitComponents
|
||||
}
|
||||
|
||||
// GetJitComponents get the just in time components
|
||||
func (globalCtx *GlobalBuildContext) GetJitComponents() []string {
|
||||
if globalCtx.jitComponents == nil {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
jitComponents := []string{}
|
||||
for name := range globalCtx.jitComponents {
|
||||
jitComponents = append(jitComponents, name)
|
||||
}
|
||||
return jitComponents
|
||||
}
|
||||
|
||||
func (ctx *BuildContext) addJitComponent(name string) {
|
||||
name = stmtRe.ReplaceAllString(name, "*")
|
||||
name = propRe.ReplaceAllString(name, "*")
|
||||
ctx.jitComponents[name] = true
|
||||
if ctx.global != nil {
|
||||
ctx.global.jitComponents[name] = true
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ func (page *Page) EditorRender() (*ResponseEditorRender, error) {
|
|||
// Render tools
|
||||
// res.Scripts = append(res.Scripts, filepath.Join("@assets", "__render.js"))
|
||||
// res.Styles = append(res.Styles, filepath.Join("@assets", "__render.css"))
|
||||
ctx := NewBuildContext()
|
||||
ctx := NewBuildContext(nil)
|
||||
doc, warnings, err := page.Build(ctx, &BuildOption{
|
||||
SSR: true,
|
||||
IgnoreAssetRoot: true,
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@ type IPage interface {
|
|||
AssetScript() (*Asset, error)
|
||||
AssetStyle() (*Asset, error)
|
||||
|
||||
Build(option *BuildOption) error
|
||||
Build(globalCtx *GlobalBuildContext, option *BuildOption) error
|
||||
BuildAsComponent(globalCtx *GlobalBuildContext, option *BuildOption) error
|
||||
}
|
||||
|
||||
// IBlock is the interface for the block
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ func (page *Page) PreviewRender(referer string) (string, error) {
|
|||
}
|
||||
|
||||
warnings := []string{}
|
||||
ctx := NewBuildContext()
|
||||
ctx := NewBuildContext(nil)
|
||||
doc, warnings, err := page.Build(ctx, &BuildOption{
|
||||
SSR: true,
|
||||
AssetRoot: fmt.Sprintf("/api/__yao/sui/v1/%s/asset/%s/@assets", page.SuiID, page.TemplateID),
|
||||
|
|
|
|||
|
|
@ -39,16 +39,25 @@ type Page struct {
|
|||
Document []byte `json:"-"`
|
||||
GlobalData []byte `json:"-"`
|
||||
Attrs map[string]string `json:"-"`
|
||||
Translations []Translation `json:"-"`
|
||||
Translations []Translation `json:"-"` // will be deprecated
|
||||
}
|
||||
|
||||
// BuildContext is the struct for the build context
|
||||
type BuildContext struct {
|
||||
components map[string]bool
|
||||
sequence int
|
||||
doc *goquery.Document
|
||||
scripts []string
|
||||
styles []string
|
||||
components map[string]bool
|
||||
jitComponents map[string]bool
|
||||
sequence int
|
||||
doc *goquery.Document
|
||||
scripts []string
|
||||
styles []string
|
||||
global *GlobalBuildContext
|
||||
translations []Translation
|
||||
}
|
||||
|
||||
// GlobalBuildContext is the struct for the global build context
|
||||
type GlobalBuildContext struct {
|
||||
jitComponents map[string]bool
|
||||
tmpl ITemplate
|
||||
}
|
||||
|
||||
// Translation is the struct for the translation
|
||||
|
|
|
|||
|
|
@ -52,11 +52,14 @@ func (tmpl *Template) Build(option *core.BuildOption) error {
|
|||
}
|
||||
|
||||
// Build all pages
|
||||
ctx := core.NewGlobalBuildContext()
|
||||
pages, err := tmpl.Pages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// loaed pages
|
||||
tmpl.loaded = map[string]core.IPage{}
|
||||
for _, page := range pages {
|
||||
perr := page.Load()
|
||||
if err != nil {
|
||||
|
|
@ -64,9 +67,29 @@ func (tmpl *Template) Build(option *core.BuildOption) error {
|
|||
continue
|
||||
}
|
||||
|
||||
perr = page.Build(option)
|
||||
perr = page.Build(ctx, option)
|
||||
if perr != nil {
|
||||
err = multierror.Append(perr)
|
||||
continue
|
||||
}
|
||||
tmpl.loaded[page.Get().Route] = page
|
||||
}
|
||||
|
||||
// Build jit components for the global <route> -> <name>.sui.lib
|
||||
jitComponents, err := tmpl.GlobRoutes(ctx.GetJitComponents(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, route := range jitComponents {
|
||||
page, has := tmpl.loaded[route]
|
||||
if !has {
|
||||
err = multierror.Append(fmt.Errorf("The page %s is not loaded", route))
|
||||
continue
|
||||
}
|
||||
err = page.BuildAsComponent(ctx, option)
|
||||
if err != nil {
|
||||
err = multierror.Append(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,8 +168,9 @@ func (tmpl *Template) SyncAssets(option *core.BuildOption) error {
|
|||
}
|
||||
|
||||
// Build is the struct for the public
|
||||
func (page *Page) Build(option *core.BuildOption) error {
|
||||
func (page *Page) Build(globalCtx *core.GlobalBuildContext, option *core.BuildOption) error {
|
||||
|
||||
ctx := core.NewBuildContext(globalCtx)
|
||||
if option.AssetRoot == "" {
|
||||
root, err := page.tmpl.local.DSL.PublicRoot(option.Data)
|
||||
if err != nil {
|
||||
|
|
@ -157,7 +181,7 @@ func (page *Page) Build(option *core.BuildOption) error {
|
|||
}
|
||||
|
||||
log.Trace("Build the page %s AssetRoot: %s", page.Route, option.AssetRoot)
|
||||
html, err := page.Page.Compile(option)
|
||||
html, err := page.Page.Compile(ctx, option)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -169,7 +193,43 @@ func (page *Page) Build(option *core.BuildOption) error {
|
|||
}
|
||||
|
||||
// Save the locale files
|
||||
return page.writeLocaleFiles(option.Data)
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
// BuildAsComponent build the page as component
|
||||
func (page *Page) BuildAsComponent(globalCtx *core.GlobalBuildContext, option *core.BuildOption) error {
|
||||
return page.writeJitHTML([]byte("<div>"+page.Route+"<div>"), option.Data)
|
||||
}
|
||||
|
||||
func (page *Page) publicFile(data map[string]interface{}) string {
|
||||
|
|
@ -354,3 +414,20 @@ func (page *Page) writeHTML(html []byte, data map[string]interface{}) error {
|
|||
log.Trace("The page %s is removed", htmlFile)
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeHTMLTo write the html to file
|
||||
func (page *Page) writeJitHTML(html []byte, data map[string]interface{}) error {
|
||||
htmlFile := fmt.Sprintf("%s.jit", page.publicFile(data))
|
||||
htmlFileAbs := filepath.Join(application.App.Root(), htmlFile)
|
||||
dir := filepath.Dir(htmlFileAbs)
|
||||
if exist, _ := os.Stat(dir); exist == nil {
|
||||
os.MkdirAll(dir, os.ModePerm)
|
||||
}
|
||||
err := os.WriteFile(htmlFileAbs, html, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
core.RemoveCache(htmlFile)
|
||||
log.Trace("The page %s is removed", htmlFile)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,49 @@ func (tmpl *Template) GetRoot() string {
|
|||
return tmpl.Root
|
||||
}
|
||||
|
||||
// Glob the files
|
||||
func (tmpl *Template) Glob(pattern string) ([]string, error) {
|
||||
path := filepath.Join(tmpl.Root, pattern)
|
||||
paths, err := tmpl.local.fs.Glob(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
routes := []string{}
|
||||
for _, p := range paths {
|
||||
routes = append(routes, strings.TrimPrefix(p, tmpl.Root))
|
||||
}
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
// GlobRoutes the files
|
||||
func (tmpl *Template) GlobRoutes(patterns []string, unique ...bool) ([]string, error) {
|
||||
routes := []string{}
|
||||
for _, pattern := range patterns {
|
||||
paths, err := tmpl.Glob(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routes = append(routes, paths...)
|
||||
}
|
||||
|
||||
// Unique
|
||||
if len(unique) > 0 && unique[0] {
|
||||
mapRoutes := map[string]bool{}
|
||||
for _, route := range routes {
|
||||
mapRoutes[route] = true
|
||||
}
|
||||
|
||||
routes = []string{}
|
||||
for route := range mapRoutes {
|
||||
routes = append(routes, route)
|
||||
}
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
// Reload the template
|
||||
func (tmpl *Template) Reload() error {
|
||||
newTmpl, err := tmpl.local.getTemplateFrom(tmpl.Root)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ type Template struct {
|
|||
Root string `json:"-"`
|
||||
local *Local
|
||||
locales []core.SelectOption
|
||||
loaded map[string]core.IPage
|
||||
*core.Template
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue