1
1
package MetaCPAN::Middleware::Static ;
2
2
use strict;
3
3
use warnings;
4
- use Plack::Builder qw( builder enable mount ) ;
5
- use Plack::App::File ();
4
+ use Cpanel::JSON::XS ();
6
5
use Cwd qw( cwd ) ;
6
+ use Plack::App::File ();
7
+ use Plack::Builder qw( builder enable mount ) ;
7
8
use Plack::MIME ();
8
- use Cpanel::JSON::XS ();
9
+ use Plack::Util ();
9
10
10
11
Plack::MIME-> add_type(
11
12
' .eot' => ' application/vnd.ms-fontobject' ,
13
+ ' .map' => ' application/json' ,
14
+ ' .mjs' => ' application/javascript' ,
12
15
' .otf' => ' font/otf' ,
13
- ' .ttf' => ' font/ttf' ,
14
- ' .woff' => ' application/font-woff' ,
15
16
' .woff2' => ' application/font-woff2' ,
16
17
);
17
18
@@ -21,26 +22,77 @@ my $hour_ttl = 60 * 60;
21
22
my $day_ttl = $hour_ttl * 24;
22
23
my $year_ttl = $day_ttl * 365;
23
24
25
+ sub _response_mw {
26
+ my ( $app , $cb ) = @_ ;
27
+ sub { Plack::Util::response_cb( $app -> (@_ ), $cb ) };
28
+ }
29
+
30
+ sub _add_headers {
31
+ my ( $app , $add_headers ) = @_ ;
32
+ _response_mw(
33
+ $app ,
34
+ sub {
35
+ my $res = shift ;
36
+ my ( $status , $headers ) = @$res ;
37
+ if ( $status >= 200 && $status < 300 ) {
38
+ push @$headers , @$add_headers ;
39
+ }
40
+ return $res ;
41
+ }
42
+ );
43
+ }
44
+
45
+ sub _add_surrogate_keys {
46
+ my ($app ) = @_ ;
47
+ _response_mw(
48
+ $app ,
49
+ sub {
50
+ my $res = shift ;
51
+ my $headers = $res -> [1];
52
+ if ( my $content_type
53
+ = Plack::Util::header_get( $headers , ' Content-Type' ) )
54
+ {
55
+ $content_type =~ s / ;.*// ;
56
+ my $media_type = $content_type =~ s { /.*} {} r ;
57
+ push @$headers ,
58
+ ' Surrogate-Key' => join ( ' , ' ,
59
+ map " content_type=$_ " ,
60
+ $content_type , $media_type );
61
+ }
62
+ return $res ;
63
+ }
64
+ );
65
+ }
66
+
67
+ sub _file_app {
68
+ my ( $type , $path , $headers ) = @_ ;
69
+ _add_surrogate_keys( _add_headers(
70
+ Plack::App::File-> new( $type => $path )-> to_app, $headers ,
71
+ ) );
72
+ }
73
+
74
+ sub _get_assets {
75
+ my ($root ) = @_ ;
76
+ open my $fh , ' <' , " $root /assets/assets.json"
77
+ or die " can't find asset map" ;
78
+ my $json = do { local $/ ; <$fh > };
79
+ close $fh ;
80
+ my $files = Cpanel::JSON::XS-> new-> decode($json );
81
+ return [ map " /assets/$_ " , @$files ];
82
+ }
83
+
24
84
sub wrap {
25
85
my ( $self , $app , %args ) = @_ ;
26
86
my $root_dir = $args {root } || cwd;
87
+ my $root = " $root_dir /root" ;
27
88
my $dev_mode
28
89
= exists $args {dev_mode }
29
90
? $args {dev_mode }
30
91
: ( $ENV {PLACK_ENV } && $ENV {PLACK_ENV } eq ' development' );
31
92
32
- my $get_assets = sub {
33
- open my $fh , ' <' , " $root_dir /root/assets/assets.json"
34
- or die " can't find asset map" ;
35
- my $json = do { local $/ ; <$fh > };
36
- close $fh ;
37
- my $files = Cpanel::JSON::XS-> new-> decode($json );
38
- return [ map " /assets/$_ " , @$files ];
39
- };
40
-
41
93
my $assets ;
42
94
if ( !$dev_mode ) {
43
- $assets = $get_assets -> ( );
95
+ $assets = _get_assets( $root );
44
96
}
45
97
46
98
builder {
@@ -49,60 +101,49 @@ sub wrap {
49
101
sub {
50
102
my ($env ) = @_ ;
51
103
if ($dev_mode ) {
52
- $assets = $get_assets -> ( );
104
+ $assets = _get_assets( $root );
53
105
}
54
106
push @{ $env -> {' metacpan.assets' } ||= [] }, @$assets ;
55
107
$app -> ($env );
56
108
};
57
109
};
58
110
59
- my $favicon_app
60
- = Plack::App::File-> new( file => ' root/static/icons/favicon.ico' )
61
- -> to_app;
62
- mount ' /favicon.ico' => sub {
63
- my $res = $favicon_app -> (@_ );
64
- push @{ $res -> [1] },
65
- (
66
- ' Cache-Control' => " max-age=${day_ttl} " ,
111
+ mount ' /favicon.ico' => _file_app(
112
+ file => " $root /static/icons/favicon.ico" ,
113
+ [
114
+ ' Cache-Control' => " public, max-age=${day_ttl} " ,
67
115
' Surrogate-Control' => " max-age=${year_ttl} " ,
68
116
' Surrogate-Key' => ' assets' ,
69
- );
70
- $res ;
71
- };
72
- my $static_app
73
- = Plack::App::File-> new( root => ' root/static' )-> to_app;
74
- mount ' /static' => sub {
75
- my $env = shift ;
76
- my $res = $static_app -> ($env );
77
- if ( $env -> {PATH_INFO } =~ m { ^/(?:images|icons|fonts|modules)/} ) {
78
- push @{ $res -> [1] },
79
- ( ' Cache-Control' =>
80
- " public, max-age=${year_ttl} , immutable" , );
81
- }
82
- else {
83
- push @{ $res -> [1] },
84
- ( ' Cache-Control' => " public, max-age=${day_ttl} " , );
85
- }
86
- push @{ $res -> [1] },
87
- (
88
- ' Surrogate-Key' => ' assets' ,
89
- ' Surrogate-Control' => " max-age=${year_ttl} " ,
90
- );
91
- $res ;
92
- };
93
- my $assets_app
94
- = Plack::App::File-> new( root => ' root/assets' )-> to_app;
95
- mount ' /assets' => sub {
96
- my $env = shift ;
97
- my $res = $assets_app -> ($env );
98
- push @{ $res -> [1] },
99
- (
100
- ' Cache-Control' => " public, max-age=${year_ttl} , immutable" ,
101
- ' Surrogate-Key' => ' assets' ,
117
+ ],
118
+ );
119
+
120
+ for my $static_dir ( qw(
121
+ assets
122
+ static/icons
123
+ static/images
124
+ ) )
125
+ {
126
+ mount " /$static_dir " => _file_app(
127
+ root => " $root /$static_dir " ,
128
+ [
129
+ ' Cache-Control' =>
130
+ " public, max-age=${year_ttl} , immutable" ,
131
+ ' Surrogate-Control' => " max-age=${year_ttl} " ,
132
+ ' Surrogate-Key' => ' assets' ,
133
+ ],
134
+ );
135
+ }
136
+
137
+ mount " /static" => _file_app(
138
+ root => " $root /static" ,
139
+ [
140
+ $dev_mode
141
+ ? ( ' Cache-Control' => " public, max-age=${day_ttl} " , )
142
+ : ( ' Cache-Control' => " public" , ),
102
143
' Surrogate-Control' => " max-age=${year_ttl} " ,
103
- );
104
- return $res ;
105
- } ;
144
+ ' Surrogate-Key ' => ' assets ' ,
145
+ ],
146
+ ) ;
106
147
107
148
mount ' /' => $app ;
108
149
};
0 commit comments