File Coverage

blib/lib/Mojolicious/Plugin/AssetPack/Pipe/Fetch.pm
Criterion Covered Total %
statement 22 39 56.4
branch 2 12 16.6
condition n/a
subroutine 5 5 100.0
pod 1 1 100.0
total 30 57 52.6


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::AssetPack::Pipe::Fetch;
2 1     1   7 use Mojo::Base 'Mojolicious::Plugin::AssetPack::Pipe';
  1         4  
  1         9  
3              
4 1     1   316 use Mojolicious::Plugin::AssetPack::Util qw(diag DEBUG);
  1         2  
  1         73  
5 1     1   9 use Mojo::URL;
  1         2  
  1         9  
6              
7             # Only made public for quick fixes. Subject for change
8             our %FORMATS = (
9             css => {
10             re => qr{url\((['"]{0,1})(.*?)\1\)},
11             pos => sub {
12             my ($start, $url, $quotes) = @_;
13             my $len = length $url;
14             return $start - length($quotes) - $len - 1, $len;
15             },
16             },
17             js => {
18             re => qr{(//\W*sourceMappingURL=)(\S+)}m,
19             pos => sub {
20             my ($start, $url) = @_;
21             my $len = length $url;
22             return $start - $len, $len;
23             },
24             },
25             );
26              
27             sub process {
28 1     1 1 3 my ($self, $assets) = @_;
29 1         5 my $store = $self->assetpack->store;
30 1         6 my $route = $self->assetpack->route;
31 1         5 my %related;
32              
33             return $assets->each(sub {
34 1     1   21 my ($asset, $index) = @_;
35 1 50       8 return unless $asset->url =~ /^https?:/;
36 1 50       7 return unless my $format = $FORMATS{$asset->format};
37              
38 1         16 my $base = Mojo::URL->new($asset->url);
39 1         148 my $content = $asset->content;
40 1         47 my $re = $format->{re};
41              
42 1         17 while ($content =~ /$re/g) {
43 0         0 my @matches = ($2, $1);
44 0         0 my $url = $matches[0];
45              
46 0 0       0 next if $url =~ /^(?:\#|data:)/; # Avoid "data:image/svg+xml..." and "#foo"
47              
48 0         0 $url = Mojo::URL->new($url);
49 0 0       0 $url = $url->base($base)->to_abs->fragment(undef) unless $url->is_abs;
50              
51 0 0       0 unless ($related{$url}) {
52 0         0 diag "Fetch resource $url" if DEBUG;
53 0 0       0 my $related = $store->asset($url) or die "AssetPack was unable to fetch related asset $url";
54 0         0 $self->assetpack->process($related->name, $related);
55 0         0 my $path = $route->render($related->TO_JSON);
56 0         0 $path =~ s!^/!!;
57 0         0 my $up = join '', map {'../'} $path =~ m!\/!g;
  0         0  
58 0         0 $related{$url} = "$up$path";
59             }
60              
61 0         0 my ($start, $len) = $format->{pos}->(pos($content), @matches);
62 0         0 substr $content, $start, $len, Mojo::URL->new($related{$url})->query(Mojo::Parameters->new);
63 0         0 pos($content) = $start + $len;
64             }
65              
66 1         5 $asset->content($content);
67 1         54 });
68             }
69              
70             1;
71              
72             =encoding utf8
73              
74             =head1 NAME
75              
76             Mojolicious::Plugin::AssetPack::Pipe::Fetch - Fetch related assets
77              
78             =head1 SYNOPSIS
79              
80             use Mojolicious::Lite;
81             plugin AssetPack => {pipes => [qw(Css Fetch)]};
82             app->asset->process(
83             "app.css" =>
84             "https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"
85             );
86              
87             =head1 DESCRIPTION
88              
89             L will look for "url()" in a CSS
90             file and fetch the resource from the remote location.
91              
92             Note that this pipe is EXPERIMENTAL and subject for change.
93              
94             =head1 METHODS
95              
96             =head2 process
97              
98             See L.
99              
100             =head1 SEE ALSO
101              
102             L.
103              
104             =cut