Skip to content

Commit

Permalink
Merge pull request #639 from trheyi/main
Browse files Browse the repository at this point in the history
[add] Support for JIT mode in SUI component imports ( dev )
  • Loading branch information
trheyi committed Jul 2, 2024
2 parents f93e964 + 28537e2 commit ad5bf84
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 29 deletions.
2 changes: 1 addition & 1 deletion sui/api/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion sui/api/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
19 changes: 7 additions & 12 deletions sui/core/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Expand Down Expand Up @@ -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
Expand All @@ -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]
Expand Down
3 changes: 1 addition & 2 deletions sui/core/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 54 additions & 0 deletions sui/core/context.go
Original file line number Diff line number Diff line change
@@ -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
}
}
2 changes: 1 addition & 1 deletion sui/core/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion sui/core/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion sui/core/preview.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
21 changes: 15 additions & 6 deletions sui/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
85 changes: 81 additions & 4 deletions sui/storages/local/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,44 @@ 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 {
err = multierror.Append(perr)
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)
}
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
43 changes: 43 additions & 0 deletions sui/storages/local/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions sui/storages/local/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Template struct {
Root string `json:"-"`
local *Local
locales []core.SelectOption
loaded map[string]core.IPage
*core.Template
}

Expand Down

0 comments on commit ad5bf84

Please sign in to comment.