hanami-assets 1.1.1 → 1.2.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/hanami-assets.gemspec +2 -2
- data/lib/hanami/assets/configuration.rb +12 -0
- data/lib/hanami/assets/helpers.rb +109 -29
- data/lib/hanami/assets/version.rb +1 -1
- metadata +12 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dee96814cdbdc9c4b0bf4519052da244585da7ce22f1ee9d002ef2bfde88344d
|
4
|
+
data.tar.gz: 7a0607dac9d21de73b5052c5b02efb7e1cf316fb278cc19fee6a197780dfb890
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a984c83ee52c5d75c9175376090b1f00bad151ca63d354d2dd626ae955defeebd685999726be12f5b884bbd6fcb5b3c49304fa8ed2425f9de1cb74708b39270
|
7
|
+
data.tar.gz: 13217797668cc3bba5369fbabd88f69796a16752193f0fbf57f270f990e1e332ec71616dc0c751a25691e1517845dc621ca5a3038032b4b2fac38e929fcf2a4f
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# Hanami::Assets
|
2
2
|
Assets management for Ruby web applications
|
3
3
|
|
4
|
+
## v1.2.0.beta1 - 2018-02-28
|
5
|
+
### Added
|
6
|
+
- [Luca Guidi] Collect assets informations for Early Hints (103)
|
7
|
+
- [Luca Guidi] Send automatically javascripts and stylesheets via Push Promise / Early Hints
|
8
|
+
- [Luca Guidi] Add the ability to send audio, video, and generic assets for Push Promise / Early Hints
|
9
|
+
|
4
10
|
## v1.1.1 - 2018-02-27
|
5
11
|
### Added
|
6
12
|
- [Luca Guidi] Official support for Ruby: MRI 2.5
|
data/hanami-assets.gemspec
CHANGED
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
spec.required_ruby_version = '>= 2.3.0'
|
22
22
|
|
23
|
-
spec.add_runtime_dependency 'hanami-utils', '
|
24
|
-
spec.add_runtime_dependency 'hanami-helpers', '
|
23
|
+
spec.add_runtime_dependency 'hanami-utils', '1.2.0.beta1'
|
24
|
+
spec.add_runtime_dependency 'hanami-helpers', '1.2.0.beta1'
|
25
25
|
spec.add_runtime_dependency 'tilt', '~> 2.0', '>= 2.0.2'
|
26
26
|
|
27
27
|
spec.add_development_dependency 'bundler'
|
@@ -412,6 +412,18 @@ module Hanami
|
|
412
412
|
"#{@base_url}#{compile_path(source)}"
|
413
413
|
end
|
414
414
|
|
415
|
+
# Check if the given source is linked via Cross-Origin policy.
|
416
|
+
# In other words, the given source, doesn't satisfy the Same-Origin policy.
|
417
|
+
#
|
418
|
+
# @see https://en.wikipedia.org/wiki/Same-origin_policy#Origin_determination_rules
|
419
|
+
# @see https://en.wikipedia.org/wiki/Same-origin_policy#document.domain_property
|
420
|
+
#
|
421
|
+
# @since 1.2.0
|
422
|
+
# @api private
|
423
|
+
def crossorigin?(source)
|
424
|
+
!source.start_with?(@base_url)
|
425
|
+
end
|
426
|
+
|
415
427
|
# An array of crypographically secure hashing algorithms to use for
|
416
428
|
# generating asset subresource integrity checks
|
417
429
|
#
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'uri'
|
2
|
-
require 'set'
|
3
2
|
require 'hanami/helpers/html_helper'
|
4
3
|
require 'hanami/utils/escape'
|
5
4
|
|
@@ -97,7 +96,11 @@ module Hanami
|
|
97
96
|
# name of the algorithm, then a hyphen, then the hash value of the file.
|
98
97
|
# If more than one algorithm is used, they'll be separated by a space.
|
99
98
|
#
|
99
|
+
# It makes the script(s) eligible for HTTP/2 Push Promise/Early Hints.
|
100
|
+
# You can opt-out with inline option: `push: false`.
|
101
|
+
#
|
100
102
|
# @param sources [Array<String>] one or more assets by name or absolute URL
|
103
|
+
# @param push [TrueClass, FalseClass] HTTP/2 Push Promise/Early Hints flag
|
101
104
|
#
|
102
105
|
# @return [Hanami::Utils::Escape::SafeString] the markup
|
103
106
|
#
|
@@ -165,12 +168,17 @@ module Hanami
|
|
165
168
|
# <%= javascript 'application' %>
|
166
169
|
#
|
167
170
|
# # <script src="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js" type="text/javascript"></script>
|
168
|
-
|
171
|
+
#
|
172
|
+
# @example Disable Push Promise/Early Hints
|
173
|
+
#
|
174
|
+
# <%= javascript 'application', push: false %>
|
175
|
+
# <%= javascript 'http://cdn.example.test/jquery.js', 'dashboard', push: false %>
|
176
|
+
def javascript(*sources, push: true, **options) # rubocop:disable Metrics/MethodLength
|
169
177
|
options = options.reject { |k, _| k.to_sym == :src }
|
170
178
|
|
171
179
|
_safe_tags(*sources) do |source|
|
172
180
|
attributes = {
|
173
|
-
src: _typed_asset_path(source, JAVASCRIPT_EXT),
|
181
|
+
src: _typed_asset_path(source, JAVASCRIPT_EXT, push: push, as: :script),
|
174
182
|
type: JAVASCRIPT_MIME_TYPE
|
175
183
|
}
|
176
184
|
attributes.merge!(options)
|
@@ -199,7 +207,12 @@ module Hanami
|
|
199
207
|
# If the "subresource integrity mode" is on, <tt>integriy</tt> is the
|
200
208
|
# name of the algorithm, then a hyphen, then the hashed value of the file.
|
201
209
|
# If more than one algorithm is used, they'll be separated by a space.
|
210
|
+
#
|
211
|
+
# It makes the script(s) eligible for HTTP/2 Push Promise/Early Hints.
|
212
|
+
# You can opt-out with inline option: `push: false`.
|
213
|
+
#
|
202
214
|
# @param sources [Array<String>] one or more assets by name or absolute URL
|
215
|
+
# @param push [TrueClass, FalseClass] HTTP/2 Push Promise/Early Hints flag
|
203
216
|
#
|
204
217
|
# @return [Hanami::Utils::Escape::SafeString] the markup
|
205
218
|
#
|
@@ -256,12 +269,17 @@ module Hanami
|
|
256
269
|
# <%= stylesheet 'application' %>
|
257
270
|
#
|
258
271
|
# # <link href="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css" type="text/css" rel="stylesheet">
|
259
|
-
|
272
|
+
#
|
273
|
+
# @example Disable Push Promise/Early Hints
|
274
|
+
#
|
275
|
+
# <%= stylesheet 'application', push: false %>
|
276
|
+
# <%= stylesheet 'http://cdn.example.test/bootstrap.css', 'dashboard', push: false %>
|
277
|
+
def stylesheet(*sources, push: true, **options) # rubocop:disable Metrics/MethodLength
|
260
278
|
options = options.reject { |k, _| k.to_sym == :href }
|
261
279
|
|
262
280
|
_safe_tags(*sources) do |source|
|
263
281
|
attributes = {
|
264
|
-
href: _typed_asset_path(source, STYLESHEET_EXT),
|
282
|
+
href: _typed_asset_path(source, STYLESHEET_EXT, push: push, as: :style),
|
265
283
|
type: STYLESHEET_MIME_TYPE,
|
266
284
|
rel: STYLESHEET_REL
|
267
285
|
}
|
@@ -292,6 +310,8 @@ module Hanami
|
|
292
310
|
# application CDN.
|
293
311
|
#
|
294
312
|
# @param source [String] asset name or absolute URL
|
313
|
+
# @param options [Hash] HTML 5 attributes
|
314
|
+
# @option options [TrueClass, FalseClass] :push HTTP/2 Push Promise/Early Hints flag
|
295
315
|
#
|
296
316
|
# @return [Hanami::Utils::Helpers::HtmlBuilder] the builder
|
297
317
|
#
|
@@ -341,11 +361,14 @@ module Hanami
|
|
341
361
|
# <%= image 'logo.png' %>
|
342
362
|
#
|
343
363
|
# # <img src="https://assets.bookshelf.org/assets/logo-28a6b886de2372ee3922fcaf3f78f2d8.png" alt="Logo">
|
364
|
+
#
|
365
|
+
# @example Enable Push Promise/Early Hints
|
366
|
+
#
|
367
|
+
# <%= image 'logo.png', push: true %>
|
344
368
|
def image(source, options = {})
|
345
369
|
options = options.reject { |k, _| k.to_sym == :src }
|
346
|
-
|
347
370
|
attributes = {
|
348
|
-
src: asset_path(source),
|
371
|
+
src: asset_path(source, push: options.delete(:push) || false, as: :image),
|
349
372
|
alt: Utils::String.titleize(::File.basename(source, WILDCARD_EXT))
|
350
373
|
}
|
351
374
|
attributes.merge!(options)
|
@@ -366,6 +389,8 @@ module Hanami
|
|
366
389
|
# application CDN.
|
367
390
|
#
|
368
391
|
# @param source [String] asset name
|
392
|
+
# @param options [Hash] HTML 5 attributes
|
393
|
+
# @option options [TrueClass, FalseClass] :push HTTP/2 Push Promise/Early Hints flag
|
369
394
|
#
|
370
395
|
# @return [Hanami::Utils::Helpers::HtmlBuilder] the builder
|
371
396
|
#
|
@@ -393,7 +418,7 @@ module Hanami
|
|
393
418
|
#
|
394
419
|
# @example Custom HTML Attributes
|
395
420
|
#
|
396
|
-
# <%= favicon id:
|
421
|
+
# <%= favicon "favicon.ico", id: "fav" %>
|
397
422
|
#
|
398
423
|
# # <link id: "fav" href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon">
|
399
424
|
#
|
@@ -408,11 +433,15 @@ module Hanami
|
|
408
433
|
# <%= favicon %>
|
409
434
|
#
|
410
435
|
# # <link href="https://assets.bookshelf.org/assets/favicon-28a6b886de2372ee3922fcaf3f78f2d8.ico" rel="shortcut icon" type="image/x-icon">
|
436
|
+
#
|
437
|
+
# @example Enable Push Promise/Early Hints
|
438
|
+
#
|
439
|
+
# <%= favicon 'favicon.ico', push: true %>
|
411
440
|
def favicon(source = DEFAULT_FAVICON, options = {})
|
412
441
|
options = options.reject { |k, _| k.to_sym == :href }
|
413
442
|
|
414
443
|
attributes = {
|
415
|
-
href: asset_path(source),
|
444
|
+
href: asset_path(source, push: options.delete(:push) || false, as: :image),
|
416
445
|
rel: FAVICON_REL,
|
417
446
|
type: FAVICON_MIME_TYPE
|
418
447
|
}
|
@@ -437,6 +466,8 @@ module Hanami
|
|
437
466
|
# application CDN.
|
438
467
|
#
|
439
468
|
# @param source [String] asset name or absolute URL
|
469
|
+
# @param options [Hash] HTML 5 attributes
|
470
|
+
# @option options [TrueClass, FalseClass] :push HTTP/2 Push Promise/Early Hints flag
|
440
471
|
#
|
441
472
|
# @return [Hanami::Utils::Helpers::HtmlBuilder] the builder
|
442
473
|
#
|
@@ -535,8 +566,20 @@ module Hanami
|
|
535
566
|
# <%= video 'movie.mp4' %>
|
536
567
|
#
|
537
568
|
# # <video src="https://assets.bookshelf.org/assets/movie-28a6b886de2372ee3922fcaf3f78f2d8.mp4"></video>
|
569
|
+
#
|
570
|
+
# @example Enable Push Promise/Early Hints
|
571
|
+
#
|
572
|
+
# <%= video 'movie.mp4', push: true %>
|
573
|
+
#
|
574
|
+
# <%=
|
575
|
+
# video do
|
576
|
+
# text "Your browser does not support the video tag"
|
577
|
+
# source src: asset_path("movie.mp4", push: :video), type: "video/mp4"
|
578
|
+
# source src: asset_path("movie.ogg"), type: "video/ogg"
|
579
|
+
# end
|
580
|
+
# %>
|
538
581
|
def video(source = nil, options = {}, &blk)
|
539
|
-
options = _source_options(source, options, &blk)
|
582
|
+
options = _source_options(source, options, as: :video, &blk)
|
540
583
|
html.video(blk, options)
|
541
584
|
end
|
542
585
|
|
@@ -556,6 +599,8 @@ module Hanami
|
|
556
599
|
# application CDN.
|
557
600
|
#
|
558
601
|
# @param source [String] asset name or absolute URL
|
602
|
+
# @param options [Hash] HTML 5 attributes
|
603
|
+
# @option options [TrueClass, FalseClass] :push HTTP/2 Push Promise/Early Hints flag
|
559
604
|
#
|
560
605
|
# @return [Hanami::Utils::Helpers::HtmlBuilder] the builder
|
561
606
|
#
|
@@ -654,8 +699,20 @@ module Hanami
|
|
654
699
|
# <%= audio 'song.ogg' %>
|
655
700
|
#
|
656
701
|
# # <audio src="https://assets.bookshelf.org/assets/song-28a6b886de2372ee3922fcaf3f78f2d8.ogg"></audio>
|
702
|
+
#
|
703
|
+
# @example Enable Push Promise/Early Hints
|
704
|
+
#
|
705
|
+
# <%= audio 'movie.mp4', push: true %>
|
706
|
+
#
|
707
|
+
# <%=
|
708
|
+
# audio do
|
709
|
+
# text "Your browser does not support the audio tag"
|
710
|
+
# source src: asset_path("song.ogg", push: :audio), type: "audio/ogg"
|
711
|
+
# source src: asset_path("song.wav"), type: "audio/wav"
|
712
|
+
# end
|
713
|
+
# %>
|
657
714
|
def audio(source = nil, options = {}, &blk)
|
658
|
-
options = _source_options(source, options, &blk)
|
715
|
+
options = _source_options(source, options, as: :audio, &blk)
|
659
716
|
html.audio(blk, options)
|
660
717
|
end
|
661
718
|
|
@@ -671,6 +728,8 @@ module Hanami
|
|
671
728
|
# If CDN mode is on, it returns the absolute URL of the asset.
|
672
729
|
#
|
673
730
|
# @param source [String] the asset name
|
731
|
+
# @param push [TrueClass, FalseClass, Symbol] HTTP/2 Push Promise/Early Hints flag, or type
|
732
|
+
# @param as [Symbol] HTTP/2 Push Promise / Early Hints flag type
|
674
733
|
#
|
675
734
|
# @return [String] the asset path
|
676
735
|
#
|
@@ -703,8 +762,12 @@ module Hanami
|
|
703
762
|
# <%= asset_path 'application.js' %>
|
704
763
|
#
|
705
764
|
# # "https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
|
706
|
-
|
707
|
-
|
765
|
+
#
|
766
|
+
# @example Enable Push Promise/Early Hints
|
767
|
+
#
|
768
|
+
# <%= asset_path "application.js", push: :script %>
|
769
|
+
def asset_path(source, push: false, as: nil)
|
770
|
+
_asset_url(source, push: push, as: as) { _relative_url(source) }
|
708
771
|
end
|
709
772
|
|
710
773
|
# It generates the absolute URL for the given source.
|
@@ -719,6 +782,8 @@ module Hanami
|
|
719
782
|
# If CDN mode is on, it returns the absolute URL of the asset.
|
720
783
|
#
|
721
784
|
# @param source [String] the asset name
|
785
|
+
# @param push [TrueClass, FalseClass, Symbol] HTTP/2 Push Promise/Early Hints flag, or type
|
786
|
+
# @param as [Symbol] HTTP/2 Push Promise / Early Hints flag type
|
722
787
|
#
|
723
788
|
# @return [String] the asset URL
|
724
789
|
#
|
@@ -751,8 +816,12 @@ module Hanami
|
|
751
816
|
# <%= asset_url 'application.js' %>
|
752
817
|
#
|
753
818
|
# # "https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
|
754
|
-
|
755
|
-
|
819
|
+
#
|
820
|
+
# @example Enable Push Promise/Early Hints
|
821
|
+
#
|
822
|
+
# <%= asset_url "application.js", push: :script %>
|
823
|
+
def asset_url(source, push: false, as: nil)
|
824
|
+
_asset_url(source, push: push, as: as) { _absolute_url(source) }
|
756
825
|
end
|
757
826
|
|
758
827
|
private
|
@@ -769,18 +838,24 @@ module Hanami
|
|
769
838
|
|
770
839
|
# @since 0.1.0
|
771
840
|
# @api private
|
772
|
-
def _asset_url(source)
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
841
|
+
def _asset_url(source, push:, as:)
|
842
|
+
url = _absolute_url?(source) ? source : yield
|
843
|
+
|
844
|
+
case push
|
845
|
+
when Symbol
|
846
|
+
_push_promise(url, as: push)
|
847
|
+
when TrueClass
|
848
|
+
_push_promise(url, as: as)
|
849
|
+
end
|
850
|
+
|
851
|
+
url
|
777
852
|
end
|
778
853
|
|
779
854
|
# @since 0.1.0
|
780
855
|
# @api private
|
781
|
-
def _typed_asset_path(source, ext)
|
856
|
+
def _typed_asset_path(source, ext, push: false, as: nil)
|
782
857
|
source = "#{source}#{ext}" if _append_extension?(source, ext)
|
783
|
-
asset_path(source)
|
858
|
+
asset_path(source, push: push, as: as)
|
784
859
|
end
|
785
860
|
|
786
861
|
# @api private
|
@@ -800,6 +875,13 @@ module Hanami
|
|
800
875
|
ABSOLUTE_URL_MATCHER.match(source)
|
801
876
|
end
|
802
877
|
|
878
|
+
# @since 1.2.0
|
879
|
+
# @api private
|
880
|
+
def _crossorigin?(source)
|
881
|
+
return false unless _absolute_url?(source)
|
882
|
+
self.class.assets_configuration.crossorigin?(source)
|
883
|
+
end
|
884
|
+
|
803
885
|
# @since 0.1.0
|
804
886
|
# @api private
|
805
887
|
def _relative_url(source)
|
@@ -814,13 +896,13 @@ module Hanami
|
|
814
896
|
|
815
897
|
# @since 0.1.0
|
816
898
|
# @api private
|
817
|
-
def _source_options(src, options, &_blk)
|
899
|
+
def _source_options(src, options, as:, &_blk)
|
818
900
|
options ||= {}
|
819
901
|
|
820
902
|
if src.respond_to?(:to_hash)
|
821
903
|
options = src.to_hash
|
822
904
|
elsif src
|
823
|
-
options[:src] = asset_path(src)
|
905
|
+
options[:src] = asset_path(src, push: options.delete(:push) || false, as: as)
|
824
906
|
end
|
825
907
|
|
826
908
|
if !options[:src] && !block_given?
|
@@ -832,11 +914,9 @@ module Hanami
|
|
832
914
|
|
833
915
|
# @since 0.1.0
|
834
916
|
# @api private
|
835
|
-
def _push_promise(url)
|
836
|
-
|
837
|
-
|
838
|
-
Thread.current[:__hanami_assets].add(url.to_s)
|
839
|
-
end
|
917
|
+
def _push_promise(url, as: nil)
|
918
|
+
Thread.current[:__hanami_assets] ||= {}
|
919
|
+
Thread.current[:__hanami_assets][url.to_s] = { as: as, crossorigin: _crossorigin?(url) }
|
840
920
|
|
841
921
|
url
|
842
922
|
end
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanami-assets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-02-
|
11
|
+
date: 2018-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hanami-utils
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.2.0.beta1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.2.0.beta1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: hanami-helpers
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.2.0.beta1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.2.0.beta1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: tilt
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -240,9 +240,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
240
240
|
version: 2.3.0
|
241
241
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
242
242
|
requirements:
|
243
|
-
- - "
|
243
|
+
- - ">"
|
244
244
|
- !ruby/object:Gem::Version
|
245
|
-
version:
|
245
|
+
version: 1.3.1
|
246
246
|
requirements: []
|
247
247
|
rubyforge_project:
|
248
248
|
rubygems_version: 2.7.5
|