I did some benchmarking to see how much slower eval_string would be. Here is the code that used mdex, solid, benchee.
It’s a simple output for the eex_html and eex_eval_string examples. eval_string seems to be 1507x slower than ~H. Maybe its still good enough since its ~167 us average per call.
defmodule Benchmarks.SolidEEX do
use MotiveWeb, :live_view
def eex_html(assigns) do
~H"""
<div>
<h1>Solid</h1>
</div>
"""
end
def eex_eval_string(assigns) do
template = """
<div>
<h1>Solid</h1>
</div>
"""
rendered =
EEx.eval_string(template, [assigns: assigns],
engine: Phoenix.LiveView.TagEngine,
file: __ENV__.file,
line: __ENV__.line + 1,
caller: __ENV__,
source: template,
tag_handler: Phoenix.LiveView.HTMLEngine
)
case rendered do
%Phoenix.LiveView.Rendered{} = already_rendered ->
# If EEx returns a Rendered struct (which happens with components), return it directly
already_rendered
other ->
# For static content, wrap it in a Rendered struct
%Phoenix.LiveView.Rendered{
static: [other],
dynamic: [],
fingerprint: nil
}
end
end
def md_solid_html_eex(markdown, assigns) do
template =
md_solid_html(markdown, assigns)
|> to_string()
rendered =
EEx.eval_string(template, [assigns: assigns],
engine: Phoenix.LiveView.TagEngine,
file: __ENV__.file,
line: __ENV__.line + 1,
caller: __ENV__,
source: template,
tag_handler: Phoenix.LiveView.HTMLEngine
)
case rendered do
%Phoenix.LiveView.Rendered{} = already_rendered ->
# If EEx returns a Rendered struct (which happens with components), return it directly
already_rendered
other ->
# For static content, wrap it in a Rendered struct
%Phoenix.LiveView.Rendered{
static: [other],
dynamic: [],
fingerprint: nil
}
end
end
def md_solid_html(markdown, assigns) do
html =
markdown
|> MDEx.parse_document!()
|> MDEx.traverse_and_update(fn
# render each text as liquid template
{node, attrs, children} ->
children =
Enum.reduce(children, [], fn
child, acc when is_binary(child) ->
with {:ok, template} <- Solid.parse(child),
{:ok, rendered} <- Solid.render(template, assigns) do
[to_string(rendered) | acc]
else
_ -> [child | acc]
end
child, acc ->
[child | acc]
end)
|> Enum.reverse()
{node, attrs, children}
end)
|> MDEx.to_html!()
html
end
def run do
markdown = """
# [Liquid](https://shopify.github.io/liquid/) Example
{{ lang.name | split: " " | last }}
"""
assigns = %{"lang" => %{"name" => "dan was here"}}
Benchee.run(
%{
"eex_html" => fn ->
eex_html(assigns)
end,
"eex_eval_string" => fn ->
eex_eval_string(assigns)
end,
"md_solid_html" => fn ->
md_solid_html(markdown, assigns)
end,
"md_solid_html_eex" => fn ->
md_solid_html_eex(markdown, assigns)
end
},
time: 10,
memory_time: 2,
formatters: [
{Benchee.Formatters.Console, extended_statistics: true}
# {Benchee.Formatters.HTML, file: "bench/output/solid_benchmark.html"}
]
)
end
end
# Run the benchmark
Benchmarks.SolidEEX.run()
Results are:
❯ mix run test/benchmarks/solideex_benchmark.exs
Operating System: macOS
CPU Information: Apple M4 Max
Number of Available Cores: 16
Available memory: 128 GB
Elixir 1.16.2
Erlang 25.3.2.10
JIT enabled: false
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 10 s
memory time: 2 s
reduction time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 56 s
Benchmarking eex_eval_string ...
Benchmarking eex_html ...
Benchmarking md_solid_html ...
Benchmarking md_solid_html_eex ...
Calculating statistics...
Formatting results...
Name ips average deviation median 99th %
eex_html 9016.84 K 0.111 μs ±35352.12% 0.0420 μs 0.0840 μs
md_solid_html 27.47 K 36.41 μs ±31.58% 34.88 μs 55.58 μs
md_solid_html_eex 6.35 K 157.56 μs ±9.52% 156.38 μs 197.50 μs
eex_eval_string 5.98 K 167.16 μs ±246.33% 104.04 μs 1467.03 μs
Comparison:
eex_html 9016.84 K
md_solid_html 27.47 K - 328.30x slower +36.30 μs
md_solid_html_eex 6.35 K - 1420.66x slower +157.45 μs
eex_eval_string 5.98 K - 1507.21x slower +167.04 μs
Extended statistics:
Name minimum maximum sample size mode
eex_html 0 μs 101692.83 μs 32.90 M 0.0420 μs
md_solid_html 20.38 μs 3270.46 μs 270.36 K 33.25 μs
md_solid_html_eex 118.92 μs 1653.54 μs 63.08 K 150 μs
eex_eval_string 86.33 μs 13359.33 μs 59.44 K 99 μs
Memory usage statistics:
Name Memory usage
eex_html 0.172 KB
md_solid_html 40.16 KB - 233.64x memory usage +39.98 KB
md_solid_html_eex 119.13 KB - 693.14x memory usage +118.96 KB
eex_eval_string 69.38 KB - 403.64x memory usage +69.20 KB
**All measurements for memory usage were the same**```