Skip to content

Commit 81d1b29

Browse files
committed
Optimize LazyHTML.Tree.to_html on large files
1 parent b1d8f05 commit 81d1b29

2 files changed

Lines changed: 21 additions & 17 deletions

File tree

lib/lazy_html.ex

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,10 @@ defmodule LazyHTML do
498498
"""
499499
@spec html_escape(String.t()) :: String.t()
500500
def html_escape(string) when is_binary(string) do
501-
LazyHTML.Tree.append_escaped(string, "")
501+
string
502+
|> LazyHTML.Tree.append_escaped([])
503+
|> Enum.reverse()
504+
|> IO.iodata_to_binary()
502505
end
503506

504507
# Access

lib/lazy_html/tree.ex

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ defmodule LazyHTML.Tree do
5555
def to_html(tree, opts \\ []) when is_list(tree) and is_list(opts) do
5656
opts = Keyword.validate!(opts, skip_whitespace_nodes: false)
5757

58-
# We build the html by continuously appending to a result binary.
59-
# Appending to a binary is optimised by the runtime, so this
60-
# approach is memory efficient.
61-
6258
ctx = %{skip_whitespace_nodes: opts[:skip_whitespace_nodes], escape: true}
63-
to_html(tree, ctx, <<>>)
59+
60+
tree
61+
|> to_html(ctx, [])
62+
|> Enum.reverse()
63+
|> IO.iodata_to_binary()
6464
end
6565

6666
@void_tags ~w(
@@ -73,17 +73,17 @@ defmodule LazyHTML.Tree do
7373
defp to_html([], _ctx, html), do: html
7474

7575
defp to_html([{tag, attrs, children} | tree], ctx, html) do
76-
html = <<html::binary, "<", tag::binary>>
76+
html = [tag, ?< | html]
7777
html = append_attrs(attrs, html)
7878

7979
if tag in @void_tags do
80-
html = <<html::binary, "/>">>
80+
html = ["/>" | html]
8181
to_html(tree, ctx, html)
8282
else
83-
html = <<html::binary, ">">>
83+
html = [?> | html]
8484
escape_children = tag not in @no_escape_tags
8585
html = to_html(children, %{ctx | escape: escape_children}, html)
86-
html = <<html::binary, "</", tag::binary, ">">>
86+
html = [?>, tag, "</" | html]
8787
to_html(tree, ctx, html)
8888
end
8989
end
@@ -94,15 +94,16 @@ defmodule LazyHTML.Tree do
9494
end
9595

9696
defp to_html([{:comment, content} | tree], ctx, html) do
97-
to_html(tree, ctx, <<html::binary, "<!--", content::binary, "-->">>)
97+
html = ["-->", content, "<!--" | html]
98+
to_html(tree, ctx, html)
9899
end
99100

100101
defp append_attrs([], html), do: html
101102

102103
defp append_attrs([{name, value} | attrs], html) do
103-
html = <<html::binary, " ", name::binary, ~S/="/>>
104+
html = [~S/="/, name, ?\s | html]
104105
html = append_escaped(value, html)
105-
html = <<html::binary, ~S/"/>>
106+
html = [?" | html]
106107
append_attrs(attrs, html)
107108
end
108109

@@ -116,7 +117,7 @@ defmodule LazyHTML.Tree do
116117

117118
defp append_text(<<_rest::binary>>, text, _whitespace_size, ctx, html)
118119
when not ctx.escape,
119-
do: <<html::binary, text::binary>>
120+
do: [text | html]
120121

121122
defp append_text(<<rest::binary>>, text, whitespace_size, ctx, html)
122123
when ctx.escape,
@@ -141,12 +142,12 @@ defmodule LazyHTML.Tree do
141142
defp append_escaped(<<>>, text, 0 = _offset, _size, html) do
142143
# We scanned the whole text and there were no characters to escape,
143144
# so we append the whole text.
144-
<<html::binary, text::binary>>
145+
[text | html]
145146
end
146147

147148
defp append_escaped(<<>>, text, offset, size, html) do
148149
chunk = binary_part(text, offset, size)
149-
<<html::binary, chunk::binary>>
150+
[chunk | html]
150151
end
151152

152153
escapes = [
@@ -160,7 +161,7 @@ defmodule LazyHTML.Tree do
160161
for {char, escaped} <- escapes do
161162
defp append_escaped(<<unquote(char), rest::binary>>, text, offset, size, html) do
162163
chunk = binary_part(text, offset, size)
163-
html = <<html::binary, chunk::binary, unquote(escaped)>>
164+
html = [unquote(escaped), chunk | html]
164165
append_escaped(rest, text, offset + size + 1, 0, html)
165166
end
166167
end

0 commit comments

Comments
 (0)