Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tailwind parser #376

Merged
merged 3 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/beacon/lifecycle/template.ex
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ defmodule Beacon.Lifecycle.Template do
@spec render_template(Beacon.Content.Page.t(), module(), map(), Macro.Env.t()) :: Beacon.Template.t()
def render_template(page, page_module, assigns, env) do
template =
case page_module.render(assigns) do
case Beacon.Template.render(page_module, assigns) do
%Phoenix.LiveView.Rendered{} = rendered -> rendered
:not_loaded -> Beacon.Loader.load_page_template(page, page_module, assigns)
end
Expand Down
50 changes: 28 additions & 22 deletions lib/beacon/loader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ defmodule Beacon.Loader do

defp load_site_from_db(site) do
with :ok <- Beacon.RuntimeJS.load!(),
:ok <- load_runtime_css(site),
:ok <- load_stylesheets(site),
:ok <- load_components(site),
:ok <- load_snippet_helpers(site),
:ok <- load_layouts(site),
:ok <- load_pages(site),
:ok <- load_error_pages(site) do
:ok <- load_error_pages(site),
:ok <- load_stylesheets(site),
:ok <- load_runtime_css(site) do
:ok
else
_ -> raise Beacon.LoaderError, message: "failed to load resources for site #{site}"
Expand Down Expand Up @@ -199,12 +199,15 @@ defmodule Beacon.Loader do

# too slow to run the css compiler on every test
if Code.ensure_loaded?(Mix.Project) and Mix.env() == :test do
defp load_runtime_css(_site), do: :ok
@doc false
def load_runtime_css(_site), do: :ok
else
defp load_runtime_css(site), do: Beacon.RuntimeCSS.load!(site)
@doc false
def load_runtime_css(site), do: Beacon.RuntimeCSS.load!(site)
end

defp load_stylesheets(site) do
@doc false
def load_stylesheets(site) do
StylesheetModuleLoader.load_stylesheets(site, Content.list_stylesheets(site))
:ok
end
Expand All @@ -222,7 +225,8 @@ defmodule Beacon.Loader do
:ok
end

defp load_layouts(site) do
@doc false
def load_layouts(site) do
site
|> Content.list_published_layouts()
|> Enum.map(fn layout ->
Expand All @@ -236,7 +240,8 @@ defmodule Beacon.Loader do
:ok
end

defp load_pages(site) do
@doc false
def load_pages(site) do
site
|> Content.list_published_pages()
|> Enum.map(fn page ->
Expand Down Expand Up @@ -360,8 +365,9 @@ defmodule Beacon.Loader do

@doc false
def handle_call({:load_page, page}, _from, config) do
result = do_load_page!(page)
:ok = load_runtime_css(page.site)
{:reply, do_load_page(page), config}
{:reply, result, config}
end

def handle_call({:load_page_template, page, page_module, assigns}, _from, config) do
Expand All @@ -379,14 +385,14 @@ defmodule Beacon.Loader do
def handle_info({:layout_published, %{site: site, id: id}}, state) do
layout = Content.get_published_layout(site, id)

with :ok <- load_runtime_css(site),
# TODO: load only used components, depends on https://github.com/BeaconCMS/beacon/issues/84
:ok <- load_components(site),
# TODO: load only used components, depends on https://github.com/BeaconCMS/beacon/issues/84
with :ok <- load_components(site),
# TODO: load only used snippet helpers
:ok <- load_snippet_helpers(site),
:ok <- load_stylesheets(site),
{:ok, _module, _ast} <- Beacon.Loader.LayoutModuleLoader.load_layout!(layout),
:ok <- maybe_reload_error_pages(layout) do
:ok <- maybe_reload_error_pages(layout),
:ok <- load_runtime_css(site),
:ok <- load_stylesheets(site) do
:ok
else
_ -> raise Beacon.LoaderError, message: "failed to load resources for layout #{layout.title} of site #{layout.site}"
Expand All @@ -397,25 +403,25 @@ defmodule Beacon.Loader do

@doc false
def handle_info({:page_published, %{site: site, id: id}}, state) do
:ok = load_runtime_css(site)

site
|> Content.get_published_page(id)
|> do_load_page()
|> do_load_page!()

:ok = load_runtime_css(site)

{:noreply, state}
end

@doc false
def handle_info({:pages_published, site, pages}, state) do
:ok = load_runtime_css(site)

for page <- pages do
site
|> Content.get_published_page(page.id)
|> do_load_page()
|> do_load_page!()
end

:ok = load_runtime_css(site)

{:noreply, state}
end

Expand Down Expand Up @@ -449,9 +455,9 @@ defmodule Beacon.Loader do
{:noreply, state}
end

defp do_load_page(page) when is_nil(page), do: nil
defp do_load_page!(page) when is_nil(page), do: nil

defp do_load_page(page) do
defp do_load_page!(page) do
layout = Content.get_published_layout(page.site, page.layout_id)

# TODO: load only used components, depends on https://github.com/BeaconCMS/beacon/issues/84
Expand Down
2 changes: 1 addition & 1 deletion lib/beacon/loader/page_module_loader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ defmodule Beacon.Loader.PageModuleLoader do

with %Content.Page{} = page <- Beacon.Content.get_published_page(page.site, page.id),
{:ok, ^page_module, _ast} <- do_load_page!(page, :request),
%Phoenix.LiveView.Rendered{} = rendered <- page_module.render(assigns) do
%Phoenix.LiveView.Rendered{} = rendered <- Beacon.Template.render(assigns) do
rendered
else
_ ->
Expand Down
4 changes: 3 additions & 1 deletion lib/beacon/media_library.ex
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,16 @@ defmodule Beacon.MediaLibrary do
|> Enum.map(&get_url_for(&1, asset))
end

def srcset_for_image(asset, sources) do
def srcset_for_image(%Asset{} = asset, sources) do
asset = Repo.preload(asset, :assets)

asset.assets
|> filter_sources(sources)
|> build_srcset()
end

def srcset_for_image(_asset, _sources), do: []

defp filter_sources(assets, sources) do
Enum.filter(
assets,
Expand Down
24 changes: 20 additions & 4 deletions lib/beacon/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,26 @@ defmodule Beacon.Router do

@doc false
def dump_pages do
case :ets.match(@ets_table, :"$1") do
[] -> []
[pages] -> pages
end
@ets_table |> :ets.match(:"$1") |> List.flatten()
end

@doc false
def dump_pages(site) do
match = {{site, :_}, :_}
guards = []
body = [:"$_"]

@ets_table
|> :ets.select([{match, guards, body}])
|> List.flatten()
end

def dump_page_modules(site, fun \\ &Function.identity/1) do
site
|> dump_pages()
|> Enum.map(fn {{^site, _path} = key, {_page_id, _layout_id, _format, page_module, _component_module}} ->
fun.(Tuple.append(key, page_module))
end)
end

@doc false
Expand Down
31 changes: 21 additions & 10 deletions lib/beacon/tailwind_compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,6 @@ defmodule Beacon.TailwindCompiler do

defp generate_template_files!(tmp_dir, site) do
[
Task.async(fn ->
Enum.map(Content.list_layouts(site, per_page: :infinity), fn layout ->
layout_path = Path.join(tmp_dir, "#{site}_layout_#{remove_special_chars(layout.title)}.template")
File.write!(layout_path, layout.template)
layout_path
end)
end),
Task.async(fn ->
Enum.map(Beacon.Content.list_components(site, per_page: :infinity), fn component ->
component_path = Path.join(tmp_dir, "#{site}_component_#{remove_special_chars(component.name)}.template")
Expand All @@ -159,9 +152,24 @@ defmodule Beacon.TailwindCompiler do
end)
end),
Task.async(fn ->
Enum.map(Content.list_pages(site, per_page: :infinity), fn page ->
page_path = Path.join(tmp_dir, "#{site}_page_#{remove_special_chars(page.path)}.template")
File.write!(page_path, page.template)
Enum.map(Content.list_layouts(site, per_page: :infinity), fn layout ->
layout_path = Path.join(tmp_dir, "#{site}_layout_#{remove_special_chars(layout.title)}.template")
File.write!(layout_path, layout.template)
layout_path
end)
end),
Task.async(fn ->
# parse from laoded pages (ETS) so it can fetch callback transformations
# thay may include additoinal stylesheet classes as the markdown parser does
Beacon.Router.dump_page_modules(site, fn {_site, path, page_module} ->
template =
page_module
|> Beacon.Template.render()
|> fetch_static()
|> List.to_string()

page_path = Path.join(tmp_dir, "#{site}_page_#{remove_special_chars(path)}.template")
File.write!(page_path, template)
page_path
end)
end),
Expand All @@ -177,6 +185,9 @@ defmodule Beacon.TailwindCompiler do
|> List.flatten()
end

defp fetch_static(%{static: static}), do: static
defp fetch_static(_), do: []

# import app css into input css used by tailwind-cli to load tailwind functions and directives
defp generate_input_css_file!(tmp_dir, site) do
beacon_tailwind_css_path = Path.join([Application.app_dir(:beacon), "priv", "beacon_tailwind.css"])
Expand Down
9 changes: 8 additions & 1 deletion lib/beacon/template.ex
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ defmodule Beacon.Template do
# it is NOT supposed to be used to render templates
def __render__(site, path_list) when is_list(path_list) do
case Beacon.Router.lookup_path(site, path_list) do
{{site, path}, {page_id, _layout_id, format, page_module, component_module}} ->
{{^site, path}, {page_id, _layout_id, format, page_module, component_module}} ->
assigns = %{__changed__: %{}, __live_path__: [], __beacon_page_module__: page_module, __beacon_component_module__: component_module}
page = %Beacon.Content.Page{id: page_id, site: site, path: path, format: format}
Beacon.Lifecycle.Template.render_template(page, page_module, assigns, BeaconWeb.PageLive.make_env())
Expand All @@ -59,6 +59,13 @@ defmodule Beacon.Template do
end
end

@doc false
def render(page_module, assigns \\ %{}) when is_atom(page_module) and is_map(assigns) do
%{__changed__: %{}, __live_path__: [], beacon_path_params: %{}, beacon_live_data: %{}}
|> Map.merge(assigns)
|> page_module.render()
end

@doc false
def choose_template([primary]), do: primary
def choose_template([primary | variants]), do: choose_template(variants, Enum.random(1..100), primary)
Expand Down
38 changes: 35 additions & 3 deletions test/beacon/tailwind_compiler_test.exs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
defmodule Beacon.TailwindCompilerTest do
use Beacon.DataCase, async: true
use Beacon.DataCase, async: false

import ExUnit.CaptureIO
import Beacon.Fixtures
alias Beacon.TailwindCompiler

@site :my_site

setup_all do
start_supervised!({Beacon.Loader, Beacon.Config.fetch!(:my_site)})
:ok
end

defp create_page(_) do
stylesheet_fixture()

Expand All @@ -17,15 +24,16 @@ defmodule Beacon.TailwindCompilerTest do
)

layout =
layout_fixture(
published_layout_fixture(
template: """
<header class="text-gray-100">Page header</header>
<%= @inner_content %>
"""
)

page_fixture(
published_page_fixture(
layout_id: layout.id,
path: "/a",
template: """
<main>
<h2 class="text-gray-200">Some Values:</h2>
Expand All @@ -36,6 +44,22 @@ defmodule Beacon.TailwindCompilerTest do
"""
)

page_fixture(
layout_id: layout.id,
path: "/b",
template: """
<main>
<h2 class="text-gray-300">Some Values:</h2>
</main>
"""
)

Beacon.Loader.load_stylesheets(@site)
Beacon.Loader.load_components(@site)
Beacon.Loader.load_layouts(@site)
Beacon.Loader.load_pages(@site)
Beacon.Loader.load_runtime_css(@site)

:ok
end

Expand All @@ -56,5 +80,13 @@ defmodule Beacon.TailwindCompilerTest do
assert output =~ "text-gray-200"
end)
end

test "do not include classes from unpublished pages" do
capture_io(fn ->
assert {:ok, output} = TailwindCompiler.compile(:my_site)

refute output =~ "text-gray-300"
end)
end
end
end
Loading