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

Changes on the svg folder are not passed on @library #3

Open
quentin-bettoum opened this issue Aug 1, 2022 · 5 comments
Open

Changes on the svg folder are not passed on @library #3

quentin-bettoum opened this issue Aug 1, 2022 · 5 comments

Comments

@quentin-bettoum
Copy link

Whenever I add/update/delete an svg in the specified folder, the app reloads but the library is not updated.
Even when I stop and restart the server it won't update the library (map of SVGs).

If, in the render() function, I replace the library() function by the @library attribute, it forces recompile once.

I made a repo with a fresh phoenix app to test it.
Here is the commit where I add and configure adept_svg

I'd be glad if you could take a look and tell me if you see something that I might have done wrong.

To reproduce the problem, you could simply change the name of the user-gear-solid.svg to anything and see that it is still displayed on the main page. Or add a new SVG and trying to Svg.render() it would throw an SVG "name" not found error.

@quentin-bettoum
Copy link
Author

So I think I found the problem.
The ~r"assets/svg/*/.*(svg)$" pattern in config/dev.exs only tells phoenix to reload the page when a change is detected.
But it does not trigger a recompile of the Svg module because it doesn't know that the @library attribute depends on those svg files.

My solution is to use the @external_resource module attribute with the __mix_recompile__?/0 module function to tell elixir that this module depends on the SVG files present in the specified svg path.

Here is the commit I made to the example project to fix the issue.

This is what my Svg module looks like now

defmodule TestSvgWeb.Svg do
  @svg_path "assets/svg"
  @svg_path_wildcard Path.wildcard(@svg_path <> "/**/*.svg")
  @paths_hash :erlang.md5(@svg_path_wildcard)

  for path <- @svg_path_wildcard do
    @external_resource path
  end

  def __mix_recompile__?() do
    :erlang.md5(@svg_path_wildcard) != @paths_hash
  end

  # Build the library at compile time
  @library Adept.Svg.compile( @svg_path )

  # Accesses the library at run time
  defp library(), do: @library

  # Render an svg from the library
  def render( key, opts \\ [] ) do
    Adept.Svg.render( library(), key, opts )
  end
end

Now whenever I add/update/delete an svg in the specified folder, the module is recompiled, the page reloads and the changes are taken into account.

I don't know if making these changes in the library, in the Adept.Svg module, would work. I may try it at some point.
Or we could add that to the documentation if you think it's ok.

@edgurgel
Copy link

edgurgel commented Aug 3, 2022

@quentin-bettoum yeah you are right that __mix_recompile__? is the way to go.

A documentation update in the meantime seems like a good approach!

I wonder if the library could provide a macro to help with this boilerplate 🤔

@c4710n
Copy link

c4710n commented Apr 6, 2023

Now whenever I add/update/delete an svg in the specified folder, the module is recompiled

I found it only works when updating an existing svg. Adding or deleting an svg won't effect the compilation of this module.

A working example looks like:

defmodule TestSvgWeb.Svg do
  @svg_path "assets/svg"
  
  svg_path_wildcard = Path.wildcard(@svg_path <> "/**/*.svg")
  @paths_hash :erlang.md5(svg_path_wildcard)

  for path <- svg_path_wildcard do
    @external_resource path
  end

  def __mix_recompile__?() do
    Path.wildcard(@svg_path <> "/**/*.svg") |> :erlang.md5() != @paths_hash
  end

  # Build the library at compile time
  @library Adept.Svg.compile( @svg_path )

  # Accesses the library at run time
  defp library(), do: @library

  # Render an svg from the library
  def render( key, opts \\ [] ) do
    Adept.Svg.render( library(), key, opts )
  end
end

@c4710n
Copy link

c4710n commented Apr 6, 2023

And, I'd like to share one another code snippet:

defmodule DemoWeb.Helpers.SvgHelper do
  @moduledoc ~S"""
  Provides helpers for using inline SVG.

  ## Integrate with Phoenix

  Import the helper functions:

      defp html_helpers do
        quote do
          # ...
          import #{inspect(__MODULE__)}, only: [svg: 1, svg: 2, svg: 3]
        end
      end


  And, assuming the directory structure is like this:

      assets/svg
      ├── generic
      │   └── logo.svg
      └── pro
          ├── logo.svg
          └── footer.svg

  Then, we can use the helper functions like this:

      svg("logo")
      svg("logo", class: "h-6 w-auto mr-2")
      svg("logo", "generic", class: "h-6 w-auto mr-2")
      svg("logo", "pro", class: "h-6 w-auto mr-2")

  """

  @library_path Path.expand("../../../assets/svg", __DIR__)
  @library Adept.Svg.compile(@library_path)

  paths = Path.wildcard("#{@library_path}/**/*.svg")
  @paths_hash :erlang.md5(paths)

  for path <- paths do
    @external_resource path
  end

  def __mix_recompile__?() do
    Path.wildcard("#{@library_path}/**/*.svg") |> :erlang.md5() != @paths_hash
  end

  @default_collection "generic"

  defp library(), do: @library

  def svg(key) do
    svg(key, @default_collection, [])
  end

  def svg(key, collection) when is_binary(collection) do
    svg(key, collection, [])
  end

  def svg(key, opts) when is_list(opts) do
    svg(key, @default_collection, opts)
  end

  def svg(key, collection, opts) do
    final_key = Path.join(collection, key)
    Adept.Svg.render(library(), final_key, opts)
  end
end

@quentin-bettoum
Copy link
Author

Thanks @c4710n, I had noticed that issue, and it was on my to-do list, but I hadn't had time to look into it yet.
I'm glad it's fixed now.

The SvgHelper module is also interesting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants