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

Added non-digested version for assets (images, fonts, svg) #413

Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file. Items under

Contributors: please follow the recommendations outlined at [keepachangelog.com](http://keepachangelog.com/). Please use the existing headings and styling as a guide, and add a link for the version diff at the bottom of the file. Also, please update the `Unreleased` link to compare to the latest release version.
## [Unreleased]
##### Added
- Non-digested version of assets in public folder [#413](https://github.com/shakacode/react_on_rails/pull/413) by [alleycat-at-git]

##### Changed
- Replace URI with Addressable gem. See [#405](https://github.com/shakacode/react_on_rails/pull/405) by [lucke84]

Expand Down
19 changes: 19 additions & 0 deletions docs/additional-reading/rails-assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Rails assets

### Problem
When client js uses images in render methods, e.g. `<img src='...' />` or in css, e.g. `background-image: url(...)`
these assets fail to load. This happens because rails adds digest hashes to filenames
when compiling assets, e.g. `img1.jpg` becomes `img1-dbu097452jf2v2.jpg`.

When compiling its native css Rails transforms all urls and links to digested
versions, i.e. `background-image: image-url(img1.jpg)` becomes
`background-image: url(img1-dbu097452jf2v2.jpg)`. However this doesn't happen for js and
css files compiled by webpack on the client side, because they don't use
`image-url` and `asset-url` and therefore assets fail to load.

### Solution

Create symlinks of non-digested versions to digested versions when Rails assets compile.
The solution is implemented using `assets:precompile` after-hook. The assets for symlinking
are defined by `config.symlink_non_digested_assets_regex` in `config/initializers/react_on_rails.rb`.
To disable symlinks set this parameter to `nil`.
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,10 @@ ReactOnRails.configure do |config|

# The server render method - either ExecJS or NodeJS
config.server_render_method = "ExecJS"

# Client js uses assets not digested by rails.
# For any asset matching this regex, non-digested symlink will be created
# To disable symlinks set this parameter to nil.
config.symlink_non_digested_assets_regex = /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/

end
10 changes: 7 additions & 3 deletions lib/react_on_rails/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ def self.configuration
skip_display_none: false,
webpack_generated_files: [],
rendering_extension: nil,
server_render_method: ""
server_render_method: "",
symlink_non_digested_assets_regex: /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg)/
)
end

Expand All @@ -67,15 +68,17 @@ class Configuration
:logging_on_server, :server_renderer_pool_size,
:server_renderer_timeout, :raise_on_prerender_error,
:skip_display_none, :generated_assets_dirs, :generated_assets_dir,
:webpack_generated_files, :rendering_extension, :server_render_method
:webpack_generated_files, :rendering_extension,
:server_render_method, :symlink_non_digested_assets_regex

def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil,
trace: nil, development_mode: nil,
logging_on_server: nil, server_renderer_pool_size: nil,
server_renderer_timeout: nil, raise_on_prerender_error: nil,
skip_display_none: nil, generated_assets_dirs: nil,
generated_assets_dir: nil, webpack_generated_files: nil,
rendering_extension: nil, server_render_method: nil)
rendering_extension: nil, server_render_method: nil,
symlink_non_digested_assets_regex: nil)
self.server_bundle_js_file = server_bundle_js_file
self.generated_assets_dirs = generated_assets_dirs
self.generated_assets_dir = generated_assets_dir
Expand All @@ -100,6 +103,7 @@ def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil,
self.rendering_extension = rendering_extension

self.server_render_method = server_render_method
self.symlink_non_digested_assets_regex = symlink_non_digested_assets_regex
end
end
end
75 changes: 75 additions & 0 deletions lib/tasks/assets.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
module ReactOnRails
class << self
def assets_path
dir = File.join(Rails.configuration.paths['public'].first,
Rails.configuration.assets.prefix)
Pathname.new(dir)
end

def symlink_file(target, symlink)
if not File.exist?(symlink) or File.lstat(symlink).symlink?
if File.exist?(target)
puts "React On Rails: Symlinking #{target} to #{symlink}"
FileUtils.ln_s target, symlink, force: true
end
else
puts "React On Rails: File #{symlink} already exists. Failed to symlink #{target}"
end
end
end
end

if ReactOnRails.configuration.symlink_non_digested_assets_regex
Rake::Task["assets:precompile"].enhance do
Rake::Task["react_on_rails:assets:symlink_non_digested_assets"].invoke
Rake::Task["react_on_rails:assets:delete_broken_symlinks"].invoke
end
end

namespace :react_on_rails do
namespace :assets do

desc "Creates non-digested symlinks for the assets in the public asset dir"
task symlink_non_digested_assets: :"assets:environment" do
manifest_path = Dir.glob(ReactOnRails::assets_path.join(".sprockets-manifest-*.json"))
.first
manifest_data = JSON.load(File.new(manifest_path))

manifest_data["assets"].each do |logical_path, digested_path|
regex = ReactOnRails.configuration.symlink_non_digested_assets_regex
if logical_path =~ regex
full_digested_path = ReactOnRails::assets_path.join(digested_path)
full_nondigested_path = ReactOnRails::assets_path.join(logical_path)
extension = full_digested_path.extname
full_digested_gz_path = full_digested_path.sub_ext("#{extension}.gz")
full_nondigested_gz_path = full_nondigested_path.sub_ext("#{extension}.gz")
ReactOnRails::symlink_file(full_digested_path, full_nondigested_path)
ReactOnRails::symlink_file(full_digested_gz_path, full_nondigested_gz_path)
end
end
end

desc "Cleans all broken symlinks for the assets in the public asset dir"
task delete_broken_symlinks: :"assets:environment" do
Dir.glob(ReactOnRails::assets_path.join("*")).each do |filename|
if File.lstat(filename).symlink?
begin
target = File.readlink(filename)
rescue
puts "React on Rails: Warning: your platform doesn't support File::readlink method."/
"Skipping broken link check."
return
end
path = Pathname.new(File.dirname(filename))
target_path = path.join(target)
unless File.exist?(target_path)
puts "React on Rails: Deleting broken link: #{filename}"
File.delete(filename)
end
end
end
end

end
end