Skip to content

Commit

Permalink
Support cross slice assets (#1372)
Browse files Browse the repository at this point in the history
Update asset helpers to accept `Hanami::Assets::Asset` instances and use the `#url` from those, as an alternative to looking up assets via string names from the `assets` in the view context.
  • Loading branch information
timriley committed Feb 11, 2024
1 parent c925bf1 commit 35285bd
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 8 deletions.
17 changes: 9 additions & 8 deletions lib/hanami/helpers/assets_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ module AssetsHelper
# name of the algorithm, then a hyphen, then the hash value of the file.
# If more than one algorithm is used, they"ll be separated by a space.
#
# @param source_paths [Array<String>] one or more assets by name or absolute URL
# @param source_paths [Array<String, #url>] one or more assets by name or absolute URL
#
# @return [Hanami::View::HTML::SafeString] the markup
#
Expand Down Expand Up @@ -189,7 +189,7 @@ def javascript_tag(*source_paths, **options)
# name of the algorithm, then a hyphen, then the hashed value of the file.
# If more than one algorithm is used, they"ll be separated by a space.
#
# @param source_paths [Array<String>] one or more assets by name or absolute URL
# @param source_paths [Array<String, #url>] one or more assets by name or absolute URL
#
# @return [Hanami::View::HTML::SafeString] the markup
#
Expand Down Expand Up @@ -282,7 +282,7 @@ def stylesheet_tag(*source_paths, **options)
# If the "CDN mode" is on, the `src` is an absolute URL of the
# application CDN.
#
# @param source [String] asset name or absolute URL
# @param source [String, #url] asset name, absolute URL, or asset object
# @param options [Hash] HTML 5 attributes
#
# @return [Hanami::View::HTML::SafeString] the markup
Expand Down Expand Up @@ -353,7 +353,7 @@ def image_tag(source, options = {})
# If the "CDN mode" is on, the `href` is an absolute URL of the
# application CDN.
#
# @param source [String] asset name
# @param source [String, #url] asset name or asset object
# @param options [Hash] HTML 5 attributes
#
# @return [Hanami::View::HTML::SafeString] the markup
Expand Down Expand Up @@ -424,7 +424,7 @@ def favicon_tag(source = DEFAULT_FAVICON, options = {})
# If the "CDN mode" is on, the `src` is an absolute URL of the
# application CDN.
#
# @param source [String] asset name or absolute URL
# @param source [String, #url] asset name, absolute URL or asset object
# @param options [Hash] HTML 5 attributes
#
# @return [Hanami::View::HTML::SafeString] the markup
Expand Down Expand Up @@ -526,7 +526,7 @@ def video_tag(source = nil, options = {}, &blk)
# If the "CDN mode" is on, the `src` is an absolute URL of the
# application CDN.
#
# @param source [String] asset name or absolute URL
# @param source [String, #url] asset name, absolute URL or asset object
# @param options [Hash] HTML 5 attributes
#
# @return [Hanami::View::HTML::SafeString] the markup
Expand Down Expand Up @@ -626,7 +626,7 @@ def audio_tag(source = nil, options = {}, &blk)
#
# If CDN mode is on, it returns the absolute URL of the asset.
#
# @param source_path [String] the asset name
# @param source_path [String, #url] the asset name or asset object
#
# @return [String] the asset path
#
Expand Down Expand Up @@ -666,6 +666,7 @@ def audio_tag(source = nil, options = {}, &blk)
#
# # "https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
def asset_url(source_path)
return source_path.url if source_path.respond_to?(:url)
return source_path if _absolute_url?(source_path)

_context.assets[source_path].url
Expand All @@ -684,7 +685,7 @@ def _safe_tags(*source_paths, &blk)
# @since 2.1.0
# @api private
def _typed_path(source, ext)
source = "#{source}#{ext}" if _append_extension?(source, ext)
source = "#{source}#{ext}" if source.is_a?(String) && _append_extension?(source, ext)
asset_url(source)
end

Expand Down
130 changes: 130 additions & 0 deletions spec/integration/assets/cross_slice_assets_helpers_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# frozen_string_literal: true

require "rack/test"
require "stringio"

RSpec.describe "Cross-slice assets via helpers", :app_integration do
include Rack::Test::Methods
let(:app) { Hanami.app }
let(:root) { make_tmp_directory }

before do
with_directory(root) do
write "config/app.rb", <<~RUBY
module TestApp
class App < Hanami::App
config.logger.stream = StringIO.new
end
end
RUBY

write "config/slices/admin.rb", <<~RUBY
module Admin
class Slice < Hanami::Slice
# TODO: we should update `import` to make importing from the app nicer
# TODO: this test failed when I tried doing `as: "app"` (string instead of symbol); fix this in dry-system
import keys: ["assets"], from: Hanami.app.container, as: :app
end
end
RUBY

write "config/assets.js", <<~JS
import * as assets from "hanami-assets";
await assets.run();
JS

write "package.json", <<~JSON
{
"type": "module"
}
JSON

write "app/view.rb", <<~RUBY
# auto_register: false
require "hanami/view"
module TestApp
class View < Hanami::View
config.layout = nil
end
end
RUBY

write "app/assets/js/app.ts", <<~TS
import "../css/app.css";
console.log("Hello from index.ts");
TS

write "app/assets/css/app.css", <<~CSS
.btn {
background: #f00;
}
CSS

write "slices/admin/assets/js/app.ts", <<~TS
import "../css/app.css";
console.log("Hello from admin's index.ts");
TS

write "slices/admin/assets/css/app.css", <<~CSS
.btn {
background: #f00;
}
CSS

write "slices/admin/view.rb", <<~RUBY
# auto_register: false
module Admin
class View < TestApp::View
end
end
RUBY

write "slices/admin/views/posts/show.rb", <<~RUBY
module Admin
module Views
module Posts
class Show < Admin::View
end
end
end
end
RUBY

write "slices/admin/views/context.rb", <<~RUBY
# auto_register: false
require "hanami/view"
module Admin
module Views
class Context < Hanami::View::Context
include Deps[app_assets: "app.assets"]
end
end
end
RUBY

write "slices/admin/templates/posts/show.html.erb", <<~ERB
<%= stylesheet_tag(app_assets["app.css"]) %>
<%= javascript_tag(app_assets["app.js"]) %>
ERB

before_prepare if respond_to?(:before_prepare)
require "hanami/prepare"
end
end

specify "assets are available in helpers and in `assets` component" do
compile_assets!

output = Admin::Slice["views.posts.show"].call.to_s

expect(output).to match(%r{<link href="/assets/app-[A-Z0-9]{8}.css" type="text/css" rel="stylesheet">})
expect(output).to match(%r{<script src="/assets/app-[A-Z0-9]{8}.js" type="text/javascript"></script>})
end
end
11 changes: 11 additions & 0 deletions spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,15 @@ def before_prepare
end
end
end

context "given an asset object" do
it "returns the URL for the asset" do
asset = Hanami::Assets::Asset.new(
path: "/foo/bar.js",
base_url: Hanami.app.config.assets.base_url
)

expect(asset_url(asset)).to eq "/foo/bar.js"
end
end
end

0 comments on commit 35285bd

Please sign in to comment.