seo_cache 0.2.0 → 0.3.0
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 +7 -0
- data/README.md +147 -12
- data/lib/seo_cache/logger.rb +108 -0
- data/lib/seo_cache/page_caching.rb +1 -1
- data/lib/seo_cache/page_render.rb +2 -0
- data/lib/seo_cache/version.rb +1 -1
- data/lib/seo_cache.rb +26 -7
- data/seo_cache.gemspec +7 -5
- metadata +54 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a029127389aa4942e27c5fbca325e56c020dfe4d35ec743034649e45700b71f
|
4
|
+
data.tar.gz: cb8f7123d7ef7a959e86f53d65c127b4195cfc2b3c21938bf0fb31c6fdcbf507
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd0f5a06df0b92a34304fad8893e3b708ef5142bd62509664dba5689fab503ffa1ae7a50901c3ee14f626c92a4d0b3994a017989e3024c8b2e6dd0083cbe47e5
|
7
|
+
data.tar.gz: 7d1e4891181adb3b9deb3cb9c7773b9328befcebfc237f4c76ce3857b6c673751a14c72403126852782726c3b2998fb3253bf7a346d3f4f4f385542b538547bf
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
Cache dedicated for SEO with Javascript rendering :fire:
|
4
4
|
|
5
|
+
## Purpose
|
6
|
+
|
7
|
+
Google credo is: Don't waste my bot time!
|
8
|
+
|
9
|
+
So to reduce Googlebot crawling time, let's provide HTML files in a specific cache.
|
10
|
+
|
11
|
+
This cache is suitable for static (generated or not) pages but not for connected pages.
|
5
12
|
|
6
13
|
## Installation
|
7
14
|
|
@@ -19,42 +26,98 @@ Or install it yourself as:
|
|
19
26
|
|
20
27
|
$ gem install seo_cache
|
21
28
|
|
22
|
-
Install chrome driver on your device
|
29
|
+
Install chromium or chrome driver on your device (the chromedriver will be automatically downloaded).
|
23
30
|
|
24
|
-
|
31
|
+
Declare the middleware. For instance in `config/initializers/seo_cache.rb`:
|
25
32
|
|
26
|
-
|
33
|
+
```ruby
|
34
|
+
require 'seo_cache'
|
35
|
+
|
36
|
+
# See options below
|
27
37
|
|
28
|
-
|
38
|
+
Rails.application.config.middleware.use SeoCache::Middleware
|
39
|
+
```
|
29
40
|
|
30
|
-
|
41
|
+
## Options
|
42
|
+
|
43
|
+
Chrome path (**required**) (`disk` or `memory`):
|
44
|
+
|
45
|
+
SeoCache.chrome_path = Rails.env.development? ? '/usr/bin/chromium-browser' : '/usr/bin/chromium'
|
46
|
+
|
47
|
+
Choose a cache mode (`memory` (default) or `disk`):
|
31
48
|
|
32
49
|
SeoCache.cache_mode = 'memory'
|
33
50
|
|
34
|
-
|
51
|
+
Disk cache path (required if disk cache):
|
52
|
+
|
53
|
+
SeoCache.disk_cache_path = Rails.root.join('public', 'seo_cache')
|
54
|
+
|
55
|
+
Redis URL (required if memory cache):
|
35
56
|
|
36
|
-
SeoCache.
|
57
|
+
SeoCache.redis_url = "redis://localhost:6379/"
|
58
|
+
|
59
|
+
Redis prefix:
|
60
|
+
|
61
|
+
SeoCache.redis_namespace = '_my_project:seo_cache'
|
62
|
+
|
63
|
+
Specific log file (if you want to log missed cache urls):
|
64
|
+
|
65
|
+
SeoCache.logger_path = Rails.root.join('log', 'seo_cache.log')
|
66
|
+
|
67
|
+
Activate missed cache urls:
|
68
|
+
|
69
|
+
SeoCache.log_missed_cache = true
|
37
70
|
|
38
71
|
URLs to blacklist:
|
39
72
|
|
40
|
-
SeoCache.
|
73
|
+
SeoCache.blacklist_params = %w[^/assets/.* ^/admin.*]
|
74
|
+
|
75
|
+
Params to blacklist:
|
76
|
+
|
77
|
+
SeoCache.blacklist_urls = %w[page]
|
41
78
|
|
42
79
|
URLs to whitelist:
|
43
80
|
|
44
81
|
SeoCache.whitelist_urls = []
|
45
82
|
|
46
|
-
|
83
|
+
Parameter to add manually to the URl to force page caching, if you want to cache a specific URL (e.g. `https://<my_website>/?_seo_cache_=true`):
|
84
|
+
|
85
|
+
SeoCache.force_cache_url_param = '_seo_cache_'
|
86
|
+
|
87
|
+
URL extension to ignore when caching (already defined):
|
88
|
+
|
89
|
+
SeoCache.extensions_to_ignore = [<your_list>]
|
90
|
+
|
91
|
+
List of bot agents (already defined):
|
92
|
+
|
93
|
+
SeoCache.crawler_user_agents = [<your_list>]
|
94
|
+
|
95
|
+
Parameter added to URL when generating the page, avoid infinite rendering (override only if already used):
|
47
96
|
|
48
|
-
SeoCache.
|
97
|
+
SeoCache.prerender_url_param = '_prerender_'
|
98
|
+
|
99
|
+
Be aware, JS will be render twice: once by server rendering and once by client. For React, this not a problem but with jQuery plugins, it can duplicate elements in the page (you have to check the redundancy).
|
49
100
|
|
50
101
|
## Automatic caching
|
51
102
|
|
52
|
-
To automate
|
103
|
+
To automate caching, create a cron rake task (e.g. in `lib/tasks/populate_seo_cache.rake`):
|
53
104
|
|
54
105
|
```ruby
|
55
|
-
|
106
|
+
namespace :MyProject do
|
107
|
+
|
108
|
+
desc 'Populate cache for SEO'
|
109
|
+
task populate_seo_cache: :environment do |_task, _args|
|
110
|
+
require 'seo_cache/populate_cache'
|
111
|
+
|
112
|
+
paths_to_cache = public_paths_like_sitemap
|
113
|
+
|
114
|
+
SeoCache::PopulateCache.new('https://<your-domain-name>', paths_to_cache).new.perform
|
115
|
+
end
|
116
|
+
end
|
56
117
|
```
|
57
118
|
|
119
|
+
You can add the `force_cache: true` option to `SeoCache::PopulateCache` for overwrite cache data.
|
120
|
+
|
58
121
|
## Server
|
59
122
|
|
60
123
|
If you use disk caching, add to your Nginx configuration:
|
@@ -89,6 +152,78 @@ location / {
|
|
89
152
|
}
|
90
153
|
```
|
91
154
|
|
155
|
+
## Heroku case
|
156
|
+
|
157
|
+
If you use Heroku server, you can't store file on dynos. But you have two alternatives :
|
158
|
+
|
159
|
+
- Use the memory mode
|
160
|
+
|
161
|
+
- Use a second server (a dedicated one) to store HTML files and combine with Nginx.
|
162
|
+
|
163
|
+
To intercept the request, use the following middleware in Rails:
|
164
|
+
|
165
|
+
In `config/initializers`, create a new file:
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
require 'bot_detector'
|
169
|
+
|
170
|
+
if Rails.env.production?
|
171
|
+
Rails.application.config.middleware.insert_before ActionDispatch::Static, BotDetector
|
172
|
+
end
|
173
|
+
```
|
174
|
+
|
175
|
+
Then in `lib` directory, for instance, manage the request:
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
class BotRedirector
|
179
|
+
CRAWLER_USER_AGENTS = ['googlebot', 'yahoo', 'bingbot', 'baiduspider', 'facebookexternalhit', 'twitterbot', 'rogerbot', 'linkedinbot', 'embedly', 'bufferbot', 'quora link preview', 'showyoubot', 'outbrain', 'pinterest/0.', 'developers.google.com/+/web/snippet', 'www.google.com/webmasters/tools/richsnippets', 'slackbot', 'vkShare', 'W3C_Validator', 'redditbot', 'Applebot', 'WhatsApp', 'flipboard', 'tumblr', 'bitlybot', 'SkypeUriPreview', 'nuzzel', 'Discordbot', 'Google Page Speed', 'Qwantify'].freeze
|
180
|
+
|
181
|
+
IGNORE_URLS = [
|
182
|
+
'/robots.txt'
|
183
|
+
].freeze
|
184
|
+
|
185
|
+
def initialize(app)
|
186
|
+
@app = app
|
187
|
+
end
|
188
|
+
|
189
|
+
def call(env)
|
190
|
+
if env['HTTP_USER_AGENT'].present? && CRAWLER_USER_AGENTS.any? { |crawler_user_agent| env['HTTP_USER_AGENT'].downcase.include?(crawler_user_agent.downcase) }
|
191
|
+
begin
|
192
|
+
request = Rack::Request.new(env)
|
193
|
+
|
194
|
+
return @app.call(env) if IGNORE_URLS.any? { |ignore_url| request.fullpath.downcase =~ /^#{ignore_url.downcase}/ }
|
195
|
+
|
196
|
+
url = URI.parse(ENV['SEO_SERVER'] + request.fullpath)
|
197
|
+
headers = {
|
198
|
+
'User-Agent' => env['HTTP_USER_AGENT'],
|
199
|
+
'Accept-Encoding' => 'gzip'
|
200
|
+
}
|
201
|
+
req = Net::HTTP::Get.new(url.request_uri, headers)
|
202
|
+
# req.basic_auth(ENV['SEO_USER_ID'], ENV['SEO_PASSWD']) # if authentication mechanism
|
203
|
+
http = Net::HTTP.new(url.host, url.port)
|
204
|
+
http.use_ssl = true if url.scheme == 'https'
|
205
|
+
response = http.request(req)
|
206
|
+
if response['Content-Encoding'] == 'gzip'
|
207
|
+
response.body = ActiveSupport::Gzip.decompress(response.body)
|
208
|
+
response['Content-Length'] = response.body.length
|
209
|
+
response.delete('Content-Encoding')
|
210
|
+
end
|
211
|
+
|
212
|
+
return [response.code.to_i, { 'Content-Type' => response.header['Content-Type'] }, [response.body]]
|
213
|
+
rescue => error
|
214
|
+
Rails.logger.error("[bot_redirection] #{error.message}")
|
215
|
+
|
216
|
+
@app.call(env)
|
217
|
+
end
|
218
|
+
else
|
219
|
+
@app.call(env)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
```
|
224
|
+
|
225
|
+
If you use a second server, all links must be relatives in your HTML files, to avoid multi-domains links.
|
226
|
+
|
92
227
|
## Inspiration
|
93
228
|
|
94
229
|
Inspired by [prerender gem](https://github.com/prerender/prerender_rails).
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
module SeoCache
|
7
|
+
#
|
8
|
+
# @example Enable full logging
|
9
|
+
# SeoCache.logger.level = :debug
|
10
|
+
#
|
11
|
+
# @example Log to file
|
12
|
+
# SeoCache.logger.output = 'seo_cache.log'
|
13
|
+
#
|
14
|
+
# @example Use logger manually
|
15
|
+
# SeoCache.logger.info('This is info message')
|
16
|
+
# SeoCache.logger.warn('This is warning message')
|
17
|
+
#
|
18
|
+
class Logger
|
19
|
+
extend Forwardable
|
20
|
+
include ::Logger::Severity
|
21
|
+
|
22
|
+
def_delegators :@logger, :debug, :debug?,
|
23
|
+
:info, :info?,
|
24
|
+
:warn, :warn?,
|
25
|
+
:error, :error?,
|
26
|
+
:fatal, :fatal?,
|
27
|
+
:level
|
28
|
+
|
29
|
+
def initialize(logger_path = nil)
|
30
|
+
@logger = create_logger(logger_path || $stdout)
|
31
|
+
end
|
32
|
+
|
33
|
+
def output=(io)
|
34
|
+
# `Logger#reopen` was added in Ruby 2.3
|
35
|
+
if @logger.respond_to?(:reopen)
|
36
|
+
@logger.reopen(io)
|
37
|
+
else
|
38
|
+
@logger = create_logger(io)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# For Ruby < 2.3 compatibility
|
44
|
+
# Based on https://github.com/ruby/ruby/blob/ruby_2_3/lib/logger.rb#L250
|
45
|
+
#
|
46
|
+
|
47
|
+
def level=(severity)
|
48
|
+
if severity.is_a?(Integer)
|
49
|
+
@logger.level = severity
|
50
|
+
else
|
51
|
+
case severity.to_s.downcase
|
52
|
+
when 'debug'.freeze
|
53
|
+
@logger.level = DEBUG
|
54
|
+
when 'info'.freeze
|
55
|
+
@logger.level = INFO
|
56
|
+
when 'warn'.freeze
|
57
|
+
@logger.level = WARN
|
58
|
+
when 'error'.freeze
|
59
|
+
@logger.level = ERROR
|
60
|
+
when 'fatal'.freeze
|
61
|
+
@logger.level = FATAL
|
62
|
+
when 'unknown'.freeze
|
63
|
+
@logger.level = UNKNOWN
|
64
|
+
else
|
65
|
+
raise ArgumentError, "invalid log level: #{severity}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Returns IO object used by logger internally.
|
72
|
+
#
|
73
|
+
# Normally, we would have never needed it, but we want to
|
74
|
+
# use it as IO object for all child processes to ensure their
|
75
|
+
# output is redirected there.
|
76
|
+
#
|
77
|
+
# It is only used in debug level, in other cases output is suppressed.
|
78
|
+
#
|
79
|
+
# @api private
|
80
|
+
#
|
81
|
+
def io
|
82
|
+
@logger.instance_variable_get(:@logdev).instance_variable_get(:@dev)
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Marks code as deprecated with replacement.
|
87
|
+
#
|
88
|
+
# @param [String] old
|
89
|
+
# @param [String] new
|
90
|
+
#
|
91
|
+
def deprecate(old, new)
|
92
|
+
warn "[DEPRECATION] #{old} is deprecated. Use #{new} instead."
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def create_logger(output)
|
98
|
+
logger = ::Logger.new(output)
|
99
|
+
logger.progname = 'SeoCache'
|
100
|
+
logger.level = ($DEBUG ? DEBUG : INFO)
|
101
|
+
logger.formatter = proc do |severity, time, progname, msg|
|
102
|
+
"#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n"
|
103
|
+
end
|
104
|
+
|
105
|
+
logger
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -33,6 +33,8 @@ module SeoCache
|
|
33
33
|
def init_driver
|
34
34
|
# Selenium::WebDriver.logger.level = :info
|
35
35
|
|
36
|
+
Selenium::WebDriver::Chrome.path = SeoCache.chrome_path if SeoCache.chrome_path
|
37
|
+
|
36
38
|
client = ::Selenium::WebDriver::Remote::Http::Persistent.new
|
37
39
|
browser_options = ::Selenium::WebDriver::Chrome::Options.new
|
38
40
|
browser_options.args << '--headless'
|
data/lib/seo_cache/version.rb
CHANGED
data/lib/seo_cache.rb
CHANGED
@@ -1,23 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'net/http'
|
4
3
|
require 'active_support'
|
5
|
-
require '
|
6
|
-
require 'chromedriver-helper'
|
7
|
-
require 'selenium/webdriver/remote/http/persistent'
|
4
|
+
require 'net/http'
|
8
5
|
require 'redis'
|
9
6
|
require 'redis-namespace'
|
7
|
+
require 'selenium/webdriver'
|
8
|
+
require 'selenium/webdriver/remote/http/persistent'
|
9
|
+
require 'webdrivers'
|
10
10
|
|
11
|
+
require 'seo_cache/logger'
|
11
12
|
require 'seo_cache/version'
|
12
13
|
require 'seo_cache/middleware'
|
13
14
|
|
14
15
|
module SeoCache
|
15
16
|
|
17
|
+
mattr_accessor :chrome_path
|
18
|
+
self.chrome_path = nil
|
19
|
+
|
16
20
|
mattr_accessor :cache_mode # disk or memory
|
17
21
|
self.cache_mode = 'memory'
|
18
22
|
|
19
23
|
mattr_accessor :disk_cache_path
|
20
|
-
self.disk_cache_path =
|
24
|
+
self.disk_cache_path = ''
|
21
25
|
|
22
26
|
mattr_accessor :disk_cache_extension
|
23
27
|
self.disk_cache_extension = '.html'
|
@@ -89,6 +93,15 @@ module SeoCache
|
|
89
93
|
'Qwantify'
|
90
94
|
]
|
91
95
|
|
96
|
+
mattr_accessor :logger_path
|
97
|
+
self.logger_path = nil
|
98
|
+
|
99
|
+
mattr_accessor :logger_level
|
100
|
+
self.logger_level = :INFO
|
101
|
+
|
102
|
+
mattr_accessor :logger
|
103
|
+
# self.logger = SeoCache::Logger.new(SeoCache.logger_path)
|
104
|
+
|
92
105
|
def self.memory_cache?
|
93
106
|
SeoCache.cache_mode == 'memory'
|
94
107
|
end
|
@@ -97,11 +110,17 @@ module SeoCache
|
|
97
110
|
SeoCache.cache_mode == 'disk'
|
98
111
|
end
|
99
112
|
|
113
|
+
def self.logger
|
114
|
+
@logger ||= SeoCache::Logger.new(SeoCache.logger_path)
|
115
|
+
end
|
116
|
+
|
100
117
|
def self.log(message)
|
101
|
-
|
118
|
+
SeoCache.logger.info(message)
|
119
|
+
# Rails.logger.info { "[seo_cache] #{message}" }
|
102
120
|
end
|
103
121
|
|
104
122
|
def self.log_error(message)
|
105
|
-
|
123
|
+
SeoCache.logger.error(message)
|
124
|
+
# Rails.logger.error { "[seo_cache] #{message}" }
|
106
125
|
end
|
107
126
|
end
|
data/seo_cache.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
|
11
11
|
spec.summary = 'Cache dedicated for SEO with Javascript rendering'
|
12
12
|
spec.description = 'Specific cache for bots to optimize time to first byte and render Javascript on server side.'
|
13
|
-
spec.homepage = 'https://github.com/floXcoder/
|
13
|
+
spec.homepage = 'https://github.com/floXcoder/seo_cache'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
@@ -20,16 +20,18 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
|
+
spec.add_dependency 'activesupport', '~> 5'
|
24
|
+
spec.add_dependency 'net-http-persistent', '~> 3'
|
23
25
|
spec.add_dependency 'rack', '~> 2'
|
24
26
|
spec.add_dependency 'railties', '~> 5'
|
25
|
-
spec.add_dependency 'net-http-persistent', '~> 3'
|
26
|
-
spec.add_dependency 'activesupport', '~> 5'
|
27
|
-
spec.add_dependency 'selenium-webdriver', '~> 3'
|
28
|
-
spec.add_dependency 'chromedriver-helper', '~> 2'
|
29
27
|
spec.add_dependency 'redis', '~> 4'
|
30
28
|
spec.add_dependency 'redis-namespace', '~> 1'
|
29
|
+
spec.add_dependency 'selenium-webdriver', '~> 3'
|
30
|
+
spec.add_dependency 'webdrivers', '~> 3'
|
31
31
|
|
32
32
|
spec.add_development_dependency 'bundler', '~> 1'
|
33
33
|
spec.add_development_dependency 'rake', '~> 12'
|
34
34
|
spec.add_development_dependency 'rspec', '~> 3'
|
35
|
+
spec.add_development_dependency 'simplecov', '~> 0.16'
|
36
|
+
spec.add_development_dependency 'webmock', '~> 3'
|
35
37
|
end
|
metadata
CHANGED
@@ -1,59 +1,59 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: seo_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- FloXcoder
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5'
|
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: '5'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: net-http-persistent
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '3'
|
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: '3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rack
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '2'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '2'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: railties
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
@@ -67,61 +67,61 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '5'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: redis
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '4'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '4'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: redis-namespace
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '1'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '1'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: selenium-webdriver
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '3'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
110
|
+
version: '3'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: webdrivers
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
117
|
+
version: '3'
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
124
|
+
version: '3'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: bundler
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +164,34 @@ dependencies:
|
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '3'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: simplecov
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0.16'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0.16'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: webmock
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '3'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '3'
|
167
195
|
description: Specific cache for bots to optimize time to first byte and render Javascript
|
168
196
|
on server side.
|
169
197
|
email:
|
@@ -186,13 +214,14 @@ files:
|
|
186
214
|
- bin/console
|
187
215
|
- bin/setup
|
188
216
|
- lib/seo_cache.rb
|
217
|
+
- lib/seo_cache/logger.rb
|
189
218
|
- lib/seo_cache/middleware.rb
|
190
219
|
- lib/seo_cache/page_caching.rb
|
191
220
|
- lib/seo_cache/page_render.rb
|
192
221
|
- lib/seo_cache/populate_cache.rb
|
193
222
|
- lib/seo_cache/version.rb
|
194
223
|
- seo_cache.gemspec
|
195
|
-
homepage: https://github.com/floXcoder/
|
224
|
+
homepage: https://github.com/floXcoder/seo_cache
|
196
225
|
licenses:
|
197
226
|
- MIT
|
198
227
|
metadata: {}
|