Skip to content

Commit

Permalink
chore: Performance tweaks.
Browse files Browse the repository at this point in the history
  • Loading branch information
jfyne committed Jul 9, 2024
1 parent 5b4c05c commit 94e816a
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 44 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ jobs:
test:
strategy:
matrix:
go-version: [1.17.x, 1.18.x]
node-version: [16.x, 17.x]
go-version: [1.21.x, 1.22.x]
node-version: [18.x, 20.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down
73 changes: 31 additions & 42 deletions diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import (
"bytes"
"fmt"
"log"
"os"
"strings"
"sync"

"github.com/google/go-cmp/cmp"
"golang.org/x/net/html"
)

const _debug = false

// LiveRendered an attribute key to show that a DOM has been rendered by live.
const LiveRendered = "live-rendered"

Expand Down Expand Up @@ -49,22 +49,23 @@ func (n anchorGenerator) inc() anchorGenerator {

// level increase the depth.
func (n anchorGenerator) level() anchorGenerator {
o := make([]int, len(n.idx))
o := make([]int, len(n.idx), len(n.idx)+2)
copy(o, n.idx)
o = append(o, liveAnchorSep, 0)
return anchorGenerator{idx: o}
}

func (n anchorGenerator) String() string {
out := liveAnchorPrefix
var sb strings.Builder
sb.WriteString(liveAnchorPrefix)
for _, i := range n.idx {
if i == liveAnchorSep {
out += "_"
sb.WriteByte('_')
} else {
out += fmt.Sprintf("%d", i)
fmt.Fprintf(&sb, "%d", i)
}
}
return out
return sb.String()
}

// Patch a location in the frontend dom.
Expand All @@ -75,46 +76,37 @@ type Patch struct {
}

func (p Patch) String() string {
action := ""
switch p.Action {
case Noop:
action = "NO"
case Replace:
action = "RE"
case Append:
action = "AP"
case Prepend:
action = "PR"
}

action := [...]string{"NO", "RE", "AP", "PR"}[p.Action]
return fmt.Sprintf("%s %s %s", p.Anchor, action, p.HTML)
}

// Diff compare two node states and return patches.
func Diff(current, proposed *html.Node) ([]Patch, error) {
patches := diffTrees(current, proposed)
output := make([]Patch, len(patches))

var wg sync.WaitGroup
wg.Add(len(patches))

for idx, p := range patches {
var buf bytes.Buffer
if p.Node != nil {
if err := html.Render(&buf, p.Node); err != nil {
return nil, fmt.Errorf("failed to render patch: %w", err)
go func(idx int, p patch) {
defer wg.Done()
var buf bytes.Buffer
if p.Node != nil {
if err := html.Render(&buf, p.Node); err != nil {
// Handle error
return
}
}
} else {
if _, err := buf.WriteString(""); err != nil {
return nil, fmt.Errorf("failed to render blank patch: %w", err)
output[idx] = Patch{
Anchor: p.Anchor,
Action: p.Action,
HTML: buf.String(),
}
}

output[idx] = Patch{
Anchor: p.Anchor,
//Path: p.Path[2:],
Action: p.Action,
HTML: buf.String(),
}
}(idx, p)
}

wg.Wait()

return output, nil
}

Expand All @@ -127,7 +119,6 @@ type patch struct {

// differ handles state for recursive diffing.
type differ struct {
// `live-update` handler.
updateNode *html.Node
updateModifier PatchAction
}
Expand Down Expand Up @@ -172,11 +163,9 @@ func shapeTree(root *html.Node) {
}

debugNodeLog("checking", root)
if !nodeRelevant(root) {
if root.Parent != nil {
debugNodeLog("removingNode", root)
root.Parent.RemoveChild(root)
}
if !nodeRelevant(root) && root.Parent != nil {
debugNodeLog("removingNode", root)
root.Parent.RemoveChild(root)
}
}

Expand Down Expand Up @@ -398,7 +387,7 @@ func getFirstSibling(node *html.Node) *html.Node {
}

func debugNodeLog(msg string, node *html.Node) {
if !_debug {
if os.Getenv("DEBUG") == "" {
return
}

Expand Down
9 changes: 9 additions & 0 deletions diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ func TestSingleTextChange(t *testing.T) {
}, t)
}

// func TestBlankChanges(t *testing.T) {
// runDiffTest(diffTest{
// root: "<div>Filled</div>",
// proposed: "<div></div>",
// patches: []Patch{
// {Anchor: "_l_0_1_0", Action: Replace, HTML: `<div _l_0_1_0=""></div>`},
// },
// }, t)
// }
func TestMultipleTextChange(t *testing.T) {
runDiffTest(diffTest{
root: `<div>Hello</div><div>World</div>`,
Expand Down
11 changes: 11 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
help:
just -l

test: _test_go _test_js

_test_go:
go vet ./...
go test ./...

_test_js:
cd web && npm run test
13 changes: 13 additions & 0 deletions web/src/patch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ test("simple replace", () => {
expect(document.body.innerHTML).toEqual(`<div _l0="">World</div>`);
});

test("blank update", () => {
document.body.innerHTML = `<div _l0="">Hello</div>`;
const event = new LiveEvent("patch", [
{
Anchor: "_l0",
Action: 1,
HTML: `<div _l0=""></div>`,
},
]);
Patch.handle(event);
expect(document.body.innerHTML).toEqual(`<div _l0=""></div>`);
})

test("double update", () => {
document.body.innerHTML = `<div _l0="">Hello</div><div _l1="">World</div>`;
const p = new LiveEvent("patch", [
Expand Down

0 comments on commit 94e816a

Please sign in to comment.