jamesmartin / inline_svg

Embed SVG documents in your Rails views and style them with CSS
MIT License
694 stars 72 forks source link

Feature request: Add vite support #160

Open jamesst20 opened 2 weeks ago

jamesst20 commented 2 weeks ago

It would be nice to support Vite: https://github.com/ElMassimo/vite_ruby

jamesst20 commented 2 weeks ago
module ViteInlineSvgFileLoader
  class << self
    def named(filename)
      vite = ViteRuby.instance
      vite_asset_path = vite.manifest.path_for(filename)

      if vite.dev_server_running?
        fetch_from_dev_server(vite_asset_path)
      else
        Rails.public_path.join(vite_asset_path.sub(%r{^/}, "")).read
      end
    end

    private

    def fetch_from_dev_server(path)
      config = ViteRuby.config
      dev_server_uri = URI("#{config.protocol}://#{config.host_with_port}#{path}")
      response = Net::HTTP.get_response(dev_server_uri)
      raise "Failed to load inline SVG from #{dev_server_uri}" unless response.is_a?(Net::HTTPSuccess)

      response.body
    end
  end
end

InlineSvg.configure do |config|
  config.asset_file = ViteInlineSvgFileLoader
end

Source: https://mattbrictson.com/blog/inline-svg-with-vite-rails

jamesmartin commented 1 week ago

Thanks for the suggestion. Given the small amount of code required to build a Vite loader (as you demonstrated), and Vite's relatively small following, I'm not sure if it's worth building support directly into the gem.

Will leave this open so other Vite enthusiasts can upvote this idea.

raybrownco commented 1 week ago

Thanks for sharing your code, @jamesst20! I was able to get it working in my app without much fuss.

The only hiccup I had was related to the filenames provided to inline_svg. Previously, code like <%= inline_svg("foo.svg") %> would know to look in app/assets/images/. These filenames stopped working after the switch to Vite Ruby, which makes sense–the images now live in app/frontend/images.

I had to update the filenames to match the asset manifest entries instead. So, given a manifest entry like:

// public/vite-dev/.vite/manifest-assets.json
{
  "images/foo.svg": {
    "file": "assets/foo-yC27NFda.svg",
    "src": "images/foo.svg",
    "integrity": "sha384-[sha]"
  },
  // ...
}

...I would now have to use the following value to reference the image:

- <%= inline_svg("foo.svg") %>
+ <%= inline_svg("images/foo.svg") %>

Not a huge change, but definitely a difference. I suspect that I could have dug a bit further and added some Vite configuration to avoid the change, but the impact was small enough for my current concerns that it was faster to just update the filenames.

jamesst20 commented 1 week ago

Thanks for sharing your code, @jamesst20! I was able to get it working in my app without much fuss.

The only hiccup I had was related to the filenames provided to inline_svg. Previously, code like <%= inline_svg("foo.svg") %> would know to look in app/assets/images/. These filenames stopped working after the switch to Vite Ruby, which makes sense–the images now live in app/frontend/images.

I had to update the filenames to match the asset manifest entries instead. So, given a manifest entry like:

// public/vite-dev/.vite/manifest-assets.json
{
  "images/foo.svg": {
    "file": "assets/foo-yC27NFda.svg",
    "src": "images/foo.svg",
    "integrity": "sha384-[sha]"
  },
  // ...
}

...I would now have to use the following value to reference the image:

- <%= inline_svg("foo.svg") %>
+ <%= inline_svg("images/foo.svg") %>

Not a huge change, but definitely a difference. I suspect that I could have dug a bit further and added some Vite configuration to avoid the change, but the impact was small enough for my current concerns that it was faster to just update the filenames.

My pleasure! The path change is indeed something that comes with Vite. All view helpers requires the folder name in the path. This is indeed a difference from shakapacker or sprockets.

This is also true for all these methods

image_tag -> vite_image_tag("images/...")
asset_path -> vite_asset_path("images/...")