fix: issue #3 slow rendering

This commit is contained in:
2026-07-05 10:26:21 +02:00
parent 1917043c10
commit fcc574428c
11 changed files with 896 additions and 234 deletions

View File

@@ -8,13 +8,19 @@ defmodule BDS.Rendering.TemplateSelection do
alias BDS.Projects
alias BDS.Rendering.FileSystem
alias BDS.Rendering.Filters
alias BDS.Rendering.RenderContext
alias BDS.Repo
alias BDS.StarterTemplates
alias BDS.Tags.Tag
alias BDS.Templates.Template
@spec resolve_post_template_slug(String.t(), [String.t()], [String.t()]) ::
@spec resolve_post_template_slug(RenderContext.t() | String.t(), [String.t()], [String.t()]) ::
String.t() | nil
def resolve_post_template_slug(%RenderContext{} = ctx, tag_names, category_names) do
Enum.find_value(tag_names, &Map.get(ctx.tag_template_slug_by_name, &1)) ||
resolve_from_category_settings(ctx.metadata.category_settings || %{}, category_names)
end
def resolve_post_template_slug(project_id, tag_names, category_names) do
resolve_from_tags(project_id, tag_names) ||
resolve_from_categories(project_id, category_names)
@@ -40,8 +46,12 @@ defmodule BDS.Rendering.TemplateSelection do
defp resolve_from_categories(project_id, category_names) do
{:ok, state} = Metadata.get_project_metadata(project_id)
settings = state.category_settings || %{}
resolve_from_category_settings(state.category_settings || %{}, category_names)
end
defp resolve_from_category_settings(_settings, []), do: nil
defp resolve_from_category_settings(settings, category_names) do
Enum.find_value(category_names, fn cat_name ->
case Map.get(settings, cat_name) do
%{"post_template_slug" => slug} when is_binary(slug) and slug != "" -> slug
@@ -50,14 +60,22 @@ defmodule BDS.Rendering.TemplateSelection do
end)
end
@spec load_template_source(String.t(), atom(), String.t() | nil) ::
@spec load_template_source(RenderContext.t() | String.t(), atom(), String.t() | nil) ::
{:ok, String.t()} | {:error, term()}
def load_template_source(project_id, kind, slug) do
project = Projects.get_project!(project_id)
def load_template_source(%RenderContext{} = ctx, kind, slug) do
RenderContext.memoize(ctx, {:template_source, kind, slug}, fn ->
do_load_template_source(ctx.project, ctx.project_id, kind, slug)
end)
end
def load_template_source(project_id, kind, slug) when is_binary(project_id) do
do_load_template_source(Projects.get_project!(project_id), project_id, kind, slug)
end
defp do_load_template_source(project, project_id, kind, slug) do
case select_template(project_id, kind, slug) do
%Template{} = template ->
case published_template_body(template) do
case published_template_body(project, template) do
{:ok, _source} = ok ->
ok
@@ -105,11 +123,10 @@ defmodule BDS.Rendering.TemplateSelection do
limit: 1
end
defp published_template_body(%Template{content: content}) when is_binary(content),
defp published_template_body(_project, %Template{content: content}) when is_binary(content),
do: {:ok, content}
defp published_template_body(%Template{} = template) do
project = Projects.get_project!(template.project_id)
defp published_template_body(project, %Template{} = template) do
full_path = Path.join(Projects.project_data_dir(project), template.file_path)
case File.read(full_path) do
@@ -124,11 +141,16 @@ defmodule BDS.Rendering.TemplateSelection do
end
end
@spec render_template(String.t(), String.t(), map()) ::
@spec render_template(RenderContext.t() | String.t(), String.t(), map()) ::
{:ok, String.t()} | {:error, String.t()}
def render_template(project_id, source, assigns) do
with {:ok, template_ast} <- Liquex.parse(source, BDS.Rendering.LiquidParser),
{:ok, _rendered} = ok <- safe_liquex_render(template_ast, project_id, assigns) do
def render_template(%RenderContext{} = ctx, source, assigns) do
parse_result =
RenderContext.memoize(ctx, {:template_ast, :erlang.md5(source)}, fn ->
Liquex.parse(source, BDS.Rendering.LiquidParser)
end)
with {:ok, template_ast} <- parse_result,
{:ok, _rendered} = ok <- safe_liquex_render(template_ast, ctx.file_system, assigns) do
ok
else
{:error, reason, line} when is_integer(line) -> {:error, "#{reason} at line #{line}"}
@@ -136,14 +158,25 @@ defmodule BDS.Rendering.TemplateSelection do
end
end
defp safe_liquex_render(template_ast, project_id, assigns) do
def render_template(project_id, source, assigns) when is_binary(project_id) do
project = Projects.get_project!(project_id)
file_system = FileSystem.new(StarterTemplates.template_roots(project))
with {:ok, template_ast} <- Liquex.parse(source, BDS.Rendering.LiquidParser),
{:ok, _rendered} = ok <- safe_liquex_render(template_ast, file_system, assigns) do
ok
else
{:error, reason, line} when is_integer(line) -> {:error, "#{reason} at line #{line}"}
{:error, _message} = error -> error
end
end
defp safe_liquex_render(template_ast, file_system, assigns) do
context =
Liquex.Context.new(assigns,
static_environment: assigns,
filter_module: Filters,
file_system: FileSystem.new(StarterTemplates.template_roots(project))
file_system: file_system
)
{result, _context} = Liquex.render!(template_ast, context)
@@ -183,7 +216,10 @@ defmodule BDS.Rendering.TemplateSelection do
defp bundled_template_slug(_kind, slug) when is_binary(slug) and slug != "", do: slug
defp bundled_template_slug(kind, _slug), do: StarterTemplates.default_slug(kind)
@spec template_render_context(String.t()) :: Liquex.Context.t()
@spec template_render_context(RenderContext.t() | String.t()) :: Liquex.Context.t()
def template_render_context(%RenderContext{template_context: template_context}),
do: template_context
def template_render_context(project_id) do
project = Projects.get_project!(project_id)