rack-pagespeed-fork 0.1.0 → 0.1.1
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/VERSION +1 -1
- data/lib/rack/pagespeed.rb +4 -2
- data/lib/rack/pagespeed/config.rb +3 -4
- data/lib/rack/pagespeed/filters/all.rb +1 -0
- data/lib/rack/pagespeed/filters/base.rb +39 -11
- data/lib/rack/pagespeed/filters/combine_css.rb +6 -5
- data/lib/rack/pagespeed/filters/combine_javascripts.rb +9 -8
- data/lib/rack/pagespeed/filters/inline_css.rb +5 -3
- data/lib/rack/pagespeed/filters/inline_images.rb +5 -3
- data/lib/rack/pagespeed/filters/inline_javascripts.rb +5 -4
- data/lib/rack/pagespeed/filters/minify_css.rb +31 -0
- data/lib/rack/pagespeed/filters/minify_javascripts.rb +4 -8
- data/lib/rack/pagespeed/store/disk.rb +6 -0
- data/rack-pagespeed-fork.gemspec +4 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec363d5fedd80da9e96fa635b10808d5b02a0f8d
|
4
|
+
data.tar.gz: 1654be013612d6d260554321ea6f08d095697a7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d58e5223f6e7df77d93dfa77047f182ab86d72fb002101b1b95368ee4e3640c1b222997d04092e7a5ed9a61a9f92046966d7a7daa52f280ba15eb8006c1c8b9
|
7
|
+
data.tar.gz: a898d685a180fe5786d668d745c8e63b8205b32f5a6e0361a02ecdd554cf44aea92db3015e4e4e522f9832bd8e4da87162b2c04952af87715886a764190fbd1b
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/lib/rack/pagespeed.rb
CHANGED
@@ -9,7 +9,7 @@ module Rack
|
|
9
9
|
|
10
10
|
def initialize app, options, &block
|
11
11
|
@app = app
|
12
|
-
@config = Config.new options, &block
|
12
|
+
@config = Config.new options.merge(app: app), &block
|
13
13
|
end
|
14
14
|
|
15
15
|
def call env
|
@@ -21,11 +21,12 @@ module Rack
|
|
21
21
|
body = ""; @response.each do |part| body << part end
|
22
22
|
@document = Nokogiri::HTML(body)
|
23
23
|
@config.filters.each do |filter|
|
24
|
+
filter.options[:env] = env
|
24
25
|
filter.execute! @document
|
25
26
|
end
|
26
27
|
body = @document.to_html
|
27
28
|
headers['Content-Length'] = body.length.to_s if headers['Content-Length'] # still UTF-8 unsafe
|
28
|
-
[status, headers, [body]]
|
29
|
+
[status, headers, [body]]
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
@@ -35,6 +36,7 @@ module Rack
|
|
35
36
|
[
|
36
37
|
200,
|
37
38
|
{
|
39
|
+
'Last-Modified' => store.mtime(asset_id).httpdate,
|
38
40
|
'Content-Length' => asset.length,
|
39
41
|
'Content-Type' => (Rack::Mime.mime_type(::File.extname(asset_id))),
|
40
42
|
'Cache-Control' => "public, max-age=#{(60*60*24*365.25*10).to_i}",
|
@@ -3,11 +3,10 @@ class Rack::PageSpeed::Config
|
|
3
3
|
class NoSuchStorageMechanism < StandardError; end
|
4
4
|
load "#{::File.dirname(__FILE__)}/store/disk.rb"
|
5
5
|
|
6
|
-
attr_reader :filters, :
|
6
|
+
attr_reader :filters, :app
|
7
7
|
|
8
8
|
def initialize options = {}, &block
|
9
|
-
@filters, @options, @
|
10
|
-
raise ArgumentError, ":public needs to be a directory" unless File.directory? @public.to_s
|
9
|
+
@filters, @options, @app = [], options, options[:app]
|
11
10
|
filters_to_methods
|
12
11
|
enable_filters_from_options
|
13
12
|
enable_store_from_options
|
@@ -61,7 +60,7 @@ class Rack::PageSpeed::Config
|
|
61
60
|
def filters_to_methods
|
62
61
|
Rack::PageSpeed::Filter.available_filters.each do |klass|
|
63
62
|
(class << self; self; end).send :define_method, klass.name do |*options|
|
64
|
-
default_options = {:
|
63
|
+
default_options = {:app => @options[:app], :store => @store}
|
65
64
|
instance = klass.new(options.any? ? default_options.merge(*options) : default_options)
|
66
65
|
@filters << instance if instance and !@filters.select { |k| k.is_a? instance.class }.any?
|
67
66
|
end
|
@@ -45,18 +45,46 @@ module Rack::PageSpeed::Filters
|
|
45
45
|
end
|
46
46
|
|
47
47
|
private
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
48
|
+
# Asset is not local if it has either a scheme (e.g. 'http:') or a host (e.g. '//google.com/')
|
49
|
+
def is_local? path
|
50
|
+
uri = URI.parse(path)
|
51
|
+
uri.scheme.nil? && uri.host.nil?
|
52
|
+
rescue URI::BadURIError
|
53
|
+
false
|
54
|
+
rescue URI::InvalidURIError
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
def content? node
|
59
|
+
content_for(node)[0] == 200
|
60
|
+
end
|
61
|
+
|
62
|
+
def content_only node
|
63
|
+
status, headers, body = content_for(node)
|
64
|
+
return nil if status != 200
|
65
|
+
full_body = ""; body.each do |part| full_body << part end
|
66
|
+
full_body
|
67
|
+
end
|
68
|
+
|
69
|
+
def path_for node
|
70
|
+
case node.name
|
71
|
+
when 'script'
|
72
|
+
node['src']
|
73
|
+
when 'img'
|
74
|
+
node['src']
|
75
|
+
when 'link'
|
76
|
+
node['href']
|
56
77
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
78
|
+
end
|
79
|
+
|
80
|
+
# Retrieve the referenced asset through the Rack application
|
81
|
+
def content_for node
|
82
|
+
path = path_for node
|
83
|
+
return [404, {}, ""] unless path && is_local?(path)
|
84
|
+
app = options[:app]
|
85
|
+
env = options[:env].dup
|
86
|
+
env['PATH_INFO'] = path
|
87
|
+
app.call(env)
|
60
88
|
end
|
61
89
|
end
|
62
90
|
# shortcut
|
@@ -22,7 +22,7 @@ class Rack::PageSpeed::Filters::CombineCSS < Rack::PageSpeed::Filter
|
|
22
22
|
|
23
23
|
private
|
24
24
|
def merge_contents nodes, separator = ';'
|
25
|
-
nodes.map { |node|
|
25
|
+
nodes.map { |node| content_only(node) rescue "" }.join("\n")
|
26
26
|
end
|
27
27
|
|
28
28
|
def save nodes
|
@@ -32,7 +32,7 @@ class Rack::PageSpeed::Filters::CombineCSS < Rack::PageSpeed::Filter
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def local_css? node
|
35
|
-
node.name == 'link' and
|
35
|
+
node.name == 'link' and content_for(node)[0] == 200
|
36
36
|
end
|
37
37
|
|
38
38
|
def topmost_of_sequence nodes
|
@@ -57,9 +57,10 @@ class Rack::PageSpeed::Filters::CombineCSS < Rack::PageSpeed::Filter
|
|
57
57
|
|
58
58
|
def unique_id nodes
|
59
59
|
return Digest::MD5.hexdigest nodes.map { |node|
|
60
|
-
|
61
|
-
next unless
|
62
|
-
|
60
|
+
status, headers, body = content_for node
|
61
|
+
next unless status == 200
|
62
|
+
full_body = ""; body.each do |part| full_body << part end
|
63
|
+
headers['Last-Modified'] + full_body
|
63
64
|
}.join unless @options[:hash]
|
64
65
|
@options[:hash].each do |urls, hash|
|
65
66
|
next unless (nodes.map { |node| node['href'] } & urls).length == urls.length
|
@@ -7,7 +7,7 @@ end
|
|
7
7
|
class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
|
8
8
|
requires_store
|
9
9
|
name 'combine_javascripts'
|
10
|
-
priority
|
10
|
+
priority 10
|
11
11
|
|
12
12
|
def execute! document
|
13
13
|
nodes = document.css('script[src]')
|
@@ -23,7 +23,7 @@ class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
|
|
23
23
|
|
24
24
|
private
|
25
25
|
def save nodes
|
26
|
-
contents = nodes.map { |node|
|
26
|
+
contents = nodes.map { |node| content_only(node) rescue "" }.join(';')
|
27
27
|
nodes_id = unique_id nodes
|
28
28
|
@options[:store]["#{nodes_id}.js"] = contents
|
29
29
|
end
|
@@ -36,7 +36,7 @@ class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def local_script? node
|
39
|
-
node.name == 'script' and
|
39
|
+
node.name == 'script' and content?(node)
|
40
40
|
end
|
41
41
|
|
42
42
|
def topmost_of_sequence nodes
|
@@ -44,7 +44,7 @@ class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
|
|
44
44
|
nodes.each do |node|
|
45
45
|
_previous, _next = node.previous_sibling, node.next_sibling
|
46
46
|
if _previous && local_script?(_previous) &&
|
47
|
-
(!_next || !
|
47
|
+
(!_next || !local_script?(_next))
|
48
48
|
result << node
|
49
49
|
end
|
50
50
|
end
|
@@ -52,10 +52,11 @@ class Rack::PageSpeed::Filters::CombineJavaScripts < Rack::PageSpeed::Filter
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def unique_id nodes
|
55
|
-
return Digest::MD5.hexdigest nodes.map { |node|
|
56
|
-
|
57
|
-
next unless
|
58
|
-
|
55
|
+
return Digest::MD5.hexdigest nodes.map { |node|
|
56
|
+
status, headers, body = content_for node
|
57
|
+
next unless status == 200
|
58
|
+
full_body = ""; body.each do |part| full_body << part end
|
59
|
+
headers['Last-Modified'] + full_body
|
59
60
|
}.join unless @options[:hash]
|
60
61
|
@options[:hash].each do |urls, hash|
|
61
62
|
next unless (nodes.map { |node| node['src'] } & urls).length == urls.length
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'csso'
|
1
2
|
class Rack::PageSpeed::Filters::InlineCSS < Rack::PageSpeed::Filter
|
2
3
|
priority 10
|
3
4
|
|
@@ -5,10 +6,11 @@ class Rack::PageSpeed::Filters::InlineCSS < Rack::PageSpeed::Filter
|
|
5
6
|
nodes = document.css('link[rel="stylesheet"][href]')
|
6
7
|
return false unless nodes.count > 0
|
7
8
|
nodes.each do |node|
|
8
|
-
|
9
|
-
next if !
|
9
|
+
status, headers, body = content_for node
|
10
|
+
next if !status == 200 or headers['Content-Length'].to_i > (@options[:max_size] or 2048)
|
10
11
|
inline = Nokogiri::XML::Node.new 'style', document
|
11
|
-
|
12
|
+
full_body = ""; body.each do |part| full_body << part end
|
13
|
+
inline.content = Csso.optimize(full_body)
|
12
14
|
node.before inline
|
13
15
|
node.remove
|
14
16
|
end
|
@@ -5,10 +5,12 @@ class Rack::PageSpeed::Filters::InlineImages < Rack::PageSpeed::Filter
|
|
5
5
|
nodes = document.css('img')
|
6
6
|
return false unless nodes.count > 0
|
7
7
|
nodes.each do |node|
|
8
|
-
|
9
|
-
next if
|
8
|
+
status, headers, body = content_for node
|
9
|
+
next if status != 200 or headers['Content-Length'].to_i > (@options[:max_size] or 1024)
|
10
|
+
url = node['src']
|
10
11
|
img = node.clone
|
11
|
-
|
12
|
+
full_body = ""; body.each do |part| full_body << part end
|
13
|
+
img['src'] = "data:#{Rack::Mime.mime_type(File.extname(path_for(node)))};base64,#{[full_body].pack('m')}"
|
12
14
|
img['alt'] = node['alt'] if node['alt']
|
13
15
|
node.before img
|
14
16
|
node.remove
|
@@ -1,15 +1,16 @@
|
|
1
1
|
class Rack::PageSpeed::Filters::InlineJavaScripts < Rack::PageSpeed::Filter
|
2
2
|
name 'inline_javascripts'
|
3
|
-
priority
|
3
|
+
priority 8
|
4
4
|
|
5
5
|
def execute! document
|
6
6
|
nodes = document.css('script[src]')
|
7
7
|
return false unless nodes.count > 0
|
8
8
|
nodes.each do |node|
|
9
|
-
|
10
|
-
next if
|
9
|
+
status, headers, body = content_for node
|
10
|
+
next if status != 200 or headers['Content-Length'].to_i > (@options[:max_size] or 2048)
|
11
11
|
inline = Nokogiri::XML::Node.new 'script', document
|
12
|
-
|
12
|
+
full_body = ""; body.each do |part| full_body << part end
|
13
|
+
inline.content = JSMin.minify(full_body)
|
13
14
|
node.before inline
|
14
15
|
node.remove
|
15
16
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'csso'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'md5'
|
5
|
+
rescue LoadError
|
6
|
+
require 'digest/md5'
|
7
|
+
end
|
8
|
+
|
9
|
+
class Rack::PageSpeed::Filters::MinifyCSS < Rack::PageSpeed::Filters::Base
|
10
|
+
requires_store
|
11
|
+
name 'minify_css'
|
12
|
+
priority 2
|
13
|
+
|
14
|
+
def execute! document
|
15
|
+
nodes = document.css('link[rel="stylesheet"][href]')
|
16
|
+
return false unless nodes.count > 0
|
17
|
+
nodes.each do |node|
|
18
|
+
if match = %r(^/rack-pagespeed-(.*)).match(node['href'])
|
19
|
+
store = @options[:store]
|
20
|
+
store[match[1]] = Csso.optimize(store[match[1]])
|
21
|
+
else
|
22
|
+
status, headers, body = content_for node
|
23
|
+
next unless node.name == 'link' && status == 200
|
24
|
+
css = ""; body.each do |part| css << part end
|
25
|
+
hash = Digest::MD5.hexdigest headers['Last-Modified'] + css
|
26
|
+
@options[:store]["#{hash}.css"] = Csso.optimize(css)
|
27
|
+
node['href'] = "/rack-pagespeed-#{hash}.css"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -21,10 +21,10 @@ class Rack::PageSpeed::Filters::MinifyJavaScripts < Rack::PageSpeed::Filters::Ba
|
|
21
21
|
store = @options[:store]
|
22
22
|
store[match[1]] = JSMin.minify store[match[1]]
|
23
23
|
else
|
24
|
-
|
25
|
-
|
26
|
-
javascript =
|
27
|
-
hash = Digest::MD5.hexdigest
|
24
|
+
status, headers, body = content_for node
|
25
|
+
next unless node.name == 'script' && status == 200
|
26
|
+
javascript = ""; body.each do |part| javascript << part end
|
27
|
+
hash = Digest::MD5.hexdigest headers['Last-Modified'] + javascript
|
28
28
|
compressed = Nokogiri::XML::Node.new 'script', document
|
29
29
|
compressed['src'] = "/rack-pagespeed-#{hash}.js"
|
30
30
|
@options[:store]["#{hash}.js"] = JSMin.minify javascript
|
@@ -34,8 +34,4 @@ class Rack::PageSpeed::Filters::MinifyJavaScripts < Rack::PageSpeed::Filters::Ba
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
38
|
-
def local_script? node
|
39
|
-
node.name == 'script' and file_for(node)
|
40
|
-
end
|
41
37
|
end
|
@@ -8,6 +8,12 @@ class Rack::PageSpeed::Store::Disk
|
|
8
8
|
@path = path
|
9
9
|
end
|
10
10
|
|
11
|
+
# Retrieve last modified time from Disk asset
|
12
|
+
def mtime key
|
13
|
+
path = "#{@path}/rack-pagespeed-#{key}"
|
14
|
+
File.mtime path if File.exists? path
|
15
|
+
end
|
16
|
+
|
11
17
|
def [] key
|
12
18
|
path = "#{@path}/rack-pagespeed-#{key}"
|
13
19
|
File.read path if File.exists? path
|
data/rack-pagespeed-fork.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: rack-pagespeed-fork 0.1.
|
5
|
+
# stub: rack-pagespeed-fork 0.1.1 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "rack-pagespeed-fork"
|
9
|
-
s.version = "0.1.
|
9
|
+
s.version = "0.1.1"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Will Jordan", "Julio Cesar Ody"]
|
14
|
-
s.date = "2014-10-
|
14
|
+
s.date = "2014-10-09"
|
15
15
|
s.description = "Web page speed optimizations at the Rack level - fork"
|
16
16
|
s.email = "will@code.org"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
"lib/rack/pagespeed/filters/inline_css.rb",
|
33
33
|
"lib/rack/pagespeed/filters/inline_images.rb",
|
34
34
|
"lib/rack/pagespeed/filters/inline_javascripts.rb",
|
35
|
+
"lib/rack/pagespeed/filters/minify_css.rb",
|
35
36
|
"lib/rack/pagespeed/filters/minify_javascripts.rb",
|
36
37
|
"lib/rack/pagespeed/store/disk.rb",
|
37
38
|
"lib/rack/pagespeed/store/memcached.rb",
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-pagespeed-fork
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Will Jordan
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-10-
|
12
|
+
date: 2014-10-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -116,6 +116,7 @@ files:
|
|
116
116
|
- lib/rack/pagespeed/filters/inline_css.rb
|
117
117
|
- lib/rack/pagespeed/filters/inline_images.rb
|
118
118
|
- lib/rack/pagespeed/filters/inline_javascripts.rb
|
119
|
+
- lib/rack/pagespeed/filters/minify_css.rb
|
119
120
|
- lib/rack/pagespeed/filters/minify_javascripts.rb
|
120
121
|
- lib/rack/pagespeed/store/disk.rb
|
121
122
|
- lib/rack/pagespeed/store/memcached.rb
|