rails / sprockets-rails

Sprockets Rails integration
MIT License
579 stars 247 forks source link

Assets (Sprockets 4.1.1 and Sprockets-rails 3.4.2) not work correctly with images within engine with third party libraries #507

Open Sega100500 opened 2 years ago

Sega100500 commented 2 years ago

System configuration

Problem

I use my own engine "Admin", in which I connect the jQuery-UI library. With sprockets 3.7.2 and sprockets-rails 3.2.2 all work fine! ... but later versions not working correctly (config.assets.compile = true)

Directory of engine is 'admin'. Config manifest file for admin: admin/app/assets/config/admin.js:

//= link_tree ../images/admin
//= link_directory ../javascripts/admin .js
//= link_directory ../stylesheets/admin .css

//= link_tree ../javascripts/admin/lib .js

//= link_tree ../stylesheets/admin/lib .css
//= link_tree ../stylesheets/admin/lib .png
//= link_tree ../stylesheets/admin/lib .jpg
//= link_tree ../stylesheets/admin/lib .jpeg
//= link_tree ../stylesheets/admin/lib .gif

(replace with require_tree also not work)

connect library jQuery-UI with stylesheet_link_tag and javascript_include_tag

jQuery-UI files placed in: admin/app/assets/javascripts/admin/lib/jquery-ui admin/app/assets/stylesheets/admin/lib/jquery-ui

in initializer I also add:

Rails.application.config.assets.precompile += %w( admin/*.js admin/*.css admin/**/*.js admin/**/*.css )
Rails.application.config.assets.precompile += %w( admin/*.png admin/**/*.png admin/*.gif admin/**/*.gif )
Rails.application.config.assets.precompile += %w( admin/*.jpg admin/**/*.jpg admin/*.jpeg admin/**/*.jpeg )

Rails.application.config.assets.precompile += Ckeditor.assets
Rails.application.config.assets.precompile += %w( ckeditor/*.js ckeditor/**/*.js ckeditor/*.css ckeditor/**/*.css ckeditor/*.md ckeditor/*.txt ckeditor/*.html )
Rails.application.config.assets.precompile += %w( ckeditor/*.png ckeditor/**/*.png ckeditor/*.gif ckeditor/**/*.gif )

Rails.application.config.assets.paths << Admin::Engine.root.join('app','assets','images')
Rails.application.config.assets.paths << Admin::Engine.root.join('app','assets','images','admin')

Rails.application.config.assets.paths << Admin::Engine.root.join('app','assets','javascripts','admin')
Rails.application.config.assets.paths << Admin::Engine.root.join('app','assets','stylesheets','admin')

jQuery-UI library is loaded, but background images of elements are not displayed

Inspection of example jQuery-UI element show this style:

.ui-widget-header {
  border: 1px solid #4297d7;
  background: #5c9ccc url(/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x;
  color: #fff;
  font-weight: bold;
}

Also I use gem ckeditor, in this case not showing icons images and images placed in page. Images loaded in ckeditor with mini_magic and ActiveStorage and link to image is like this:

'/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--a6378272645dcac2d56fb1a971b3e8fc3a682b86/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJYW5CbkJqb0dSVlE2QzNKbGMybDZaVWtpQ1Rnd01ENEdPd1pVIiwiZXhwIjpudWxsLCJwdXIiOiJ2YXJpYXRpb24ifX0=--2ccbd7d12a252e03eb26bb2401505e4efaeff669/7d85fe9c160bb2f3b559a45303cc8ce4.jpg'

With sprockets 3.7.2 and sprockets-rails 3.2.2 all work fine! ... but later versions not working correctly

What could be wrong? I tried many options for specifying paths, direct specifying files, but it does not work as it should. Please, help!...

gems for non-digest assets are not helped to me: non-digest-assets gem. sprockets-redirect gem. smart_assets gem.

Sega100500 commented 2 years ago

More detailed comments for this issue

Sega100500 commented 2 years ago

I found in sprockets-rails 3.2.2 → 3.3.0 changes that make it. It is from version sprockets 3.3.0 that such incorrect processing is observed.

in file data/lib/sprockets/rails/asset_url_processor.rb ADDED

module Sprockets
  module Rails
    # Rewrites urls in CSS files with the digested paths
    class AssetUrlProcessor
      REGEX = /url\(\s*["']?(?!(?:\#|data|http))([^"'\s)]+)\s*["']?\)/

      def self.call(input)
        context = input[:environment].context_class.new(input)
        data    = input[:data].gsub(REGEX) { |_match| "url(#{context.asset_path($1)})" }

        { data: data }
      end
    end
  end
end

This section of code does the conversion:

from background: #5c9ccc url("images/ui-bg_gloss-wave_55_5c9ccc_500x100.png") 50% 50% repeat-x; to: background: #5c9ccc url(/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x;

But why do this for stylesheets of third-party?...

Problem not in REGEX, but in substitution path in context.asset_path($1)

code sprockets-rails 3.4.2 :

module Sprockets
  module Rails
    # Resolve assets referenced in CSS `url()` calls and replace them with the digested paths
    class AssetUrlProcessor
      REGEX = /url\(\s*["']?(?!(?:\#|data|http))(?<relativeToCurrentDir>\.\/)?(?<path>[^"'\s)]+)\s*["']?\)/
      def self.call(input)
        context = input[:environment].context_class.new(input)
        data    = input[:data].gsub(REGEX) do |_match|
          path = Regexp.last_match[:path]
          "url(#{context.asset_path(path)})"
        end

        context.metadata.merge(data: data)
      end
    end
  end
end

again in this code path - is valid, but context.asset_path(path) - path with leading slash /images/ui-bg_gloss-wave_55_5c9ccc_500x100.png - wrong

Sega100500 commented 2 years ago

In sprockets-rails 3.4.2, they probably noticed that there can be a relative path, but for some reason they decided that it must begin with ./:

REGEX = /url\(\s*["']?(?!(?:\#|data|http))(?<relativeToCurrentDir>\.\/)?(?<path>[^"'\s)]+)\s*["']?\)/

BUT! relative path may be without any leading slashes and dots, like this one background: #5c9ccc url("images/ui-bg_gloss-wave_55_5c9ccc_500x100.png") 50% 50% repeat-x; - this start with subdirectory name.

Even if we assume that a path without initial slashes is found, then it would be most correct to add ./ to the beginning of the path, but not /.

Sega100500 commented 2 years ago

The patch that fixed the bug

For experiment I a little patch file lib/sprockets/rails/asset_url_processor.rb

module Sprockets
  module Rails
    # Resolve assets referenced in CSS `url()` calls and replace them with the digested paths
    class AssetUrlProcessor
      REGEX = /url\(\s*["']?(?!(?:\#|data|http))(?<relativeToCurrentDir>\.\/)?(?<path>[^"'\s)]+)\s*["']?\)/
      def self.call(input)
        context = input[:environment].context_class.new(input)
        data    = input[:data].gsub(REGEX) do |_match|
          path = Regexp.last_match[:path]
          # original: "url(#{context.asset_path(path)})"

          # my patch
          orig_path = path
          path = context.asset_path(path)
          path = (path == "/#{orig_path}") ? ".#{path}" : path
          "url(#{path})"

        end

        context.metadata.merge(data: data)
      end
    end
  end
end

... and all works correctly in development and production environments! This patch works correctly with relative paths in both assets and third-paty css-styles.

Of course, these are not full-fledged corrections and the method context.asset_path(path) must be corrected. But I clearly and specifically showed exactly what the problem is.

Please fix this bug in the library.

rafaelfranca commented 2 years ago

Please fix this bug in the library.

Please feel free to submit a pull request. Thank you!

Sega100500 commented 2 years ago

@rafaelfranca

Read Contributing to Sprockets Rails and I try:

git clone https://github.com/contributor/sprockets-rails.git

Answer:

Cloning into 'sprockets-rails'...
Username for 'https://github.com': Sega100500
Password for 'https://Sega100500@github.com':
remote: Repository not found.
fatal: repository 'https://github.com/contributor/sprockets-rails.git/' not found
yahonda commented 2 years ago

Here contributor is GitHub username that have sprockets-rails repository.

git clone https://github.com/contributor/sprockets-rails.git

Once you have cloned https://github.com/rails/sprockets-rails/ to your account the correct address should be

git clone https://github.com/Sega100500/sprockets-rails.git

I have opened a pull request https://github.com/rails/sprockets-rails/pull/508 to update it.

Sega100500 commented 2 years ago

@yahonda , @rafaelfranca

Both git clone https://github.com/contributor/sprockets-rails.git and git clone https://github.com/Sega100500/sprockets-rails.git output these:

ruby@inet:~/devel$ git clone https://github.com/contributor/sprockets-rails.git
Cloning into 'sprockets-rails'...
Username for 'https://github.com': Sega100500
Password for 'https://Sega100500@github.com':
remote: Repository not found.
fatal: repository 'https://github.com/contributor/sprockets-rails.git/' not found

ruby@inet:~/devel$ git clone https://github.com/Sega100500/sprockets-rails.git
Cloning into 'sprockets-rails'...
Username for 'https://github.com': Sega100500
Password for 'https://Sega100500@github.com':
remote: Repository not found.
fatal: repository 'https://github.com/Sega100500/sprockets-rails.git/' not found
rafaelfranca commented 2 years ago

Did you fork the project before cloning?

Sega100500 commented 2 years ago

@rafaelfranca

No, I don't know much about Git workflows. Especially when it comes to making changes to other people's projects. I just followed the instructions Contributing to Sprockets Rails and I thought that at the same time I would learn how to do it, but I stumbled on the first step. Although I have 2FA and token in my profile Github.

Fork the Project

Fork the project on Github and check out your copy.

git clone https://github.com/contributor/sprockets-rails.git cd sprockets-rails git remote add upstream https://github.com/rails/sprockets-rails.git

But this happen (above):

...
remote: Repository not found.
fatal: repository 'https://github.com/Sega100500/sprockets-rails.git/' not found

I didn't get any files from the repository.

Sega100500 commented 2 years ago

@rafaelfranca

Pull request

But in one test is fail... Somesing wrong with rmdir in one test...

P.S. It's strange that I was only able to do this using Git Desktop, but not command line...