Skip to content

Commit

Permalink
Merge pull request #413 from alleycat-at-git/feature/asset_pipeline_d…
Browse files Browse the repository at this point in the history
…igests

Added non-digested version for assets (images, fonts, svg)
  • Loading branch information
justin808 committed May 6, 2016
2 parents 89d44f7 + 2a36ac5 commit 9491179
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 3 deletions.
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

0 comments on commit 9491179

Please sign in to comment.