turbo-sprockets-rails4 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -10
- data/lib/turbo-sprockets-rails4.rb +52 -3
- data/lib/turbo-sprockets/asset_resolver.rb +82 -0
- data/lib/turbo-sprockets/parallel_compiler.rb +2 -4
- data/lib/turbo-sprockets/parallel_preloader.rb +89 -0
- data/lib/turbo-sprockets/railtie.rb +24 -2
- data/lib/turbo-sprockets/version.rb +1 -1
- data/spec/asset_resolver_spec.rb +154 -0
- data/spec/log/test.log +88 -0
- data/spec/parallel_compiler_spec.rb +22 -5
- data/spec/parallel_preloader_spec.rb +31 -0
- data/spec/spec_helper.rb +13 -4
- data/spec/tmp/cache/assets/sprockets/v3.0/Le/LeawzTm7RwKtrjUFVCR7o9JVRLjcbCfbykBpzdSZxtM.cache +1 -0
- data/spec/tmp/cache/assets/sprockets/v3.0/Ok/OkAys_2Q1L3vb5MfExaVwWECnkhnpaauOKQ4K5h2EQM.cache +1 -0
- data/spec/tmp/cache/assets/sprockets/v3.0/{rs/rsmYKfF63AJstBxp9BfJQ_Alz93hJXeRW6AlZasgAg8.cache → P5/P5S3gl7IvP4a1i2vH3aGqb7MG5quRXURszmF4Jo-exM.cache} +0 -0
- data/spec/tmp/cache/assets/sprockets/v3.0/{F9/F9uLDkuCpwXDtwzIob92yhwmsuBy0NUF2GnJGRiyWF4.cache → Tj/TjacfODSnBaChvUCg9VRCYGvF9N9D1BFEYa_LOY0Myo.cache} +0 -0
- data/spec/tmp/cache/assets/sprockets/v3.0/{-m/-mYOrHQQw4eQz_Ht_LzLRCkKUaiPsHUZnmBchCOMAQU.cache → YF/YFli9jLfluQ3HEM4JQkUGPnhKztRu1QjsR-krCrHnDQ.cache} +0 -0
- data/spec/tmp/cache/assets/sprockets/v3.0/_T/_T7w3tcNAR1OjzPNFDxGLBsotNkwlubZL18upfeyLOk.cache +1 -0
- data/spec/tmp/cache/assets/sprockets/v3.0/{FA/FA7o1GffPYj_2A2EsHqBM8vMKfdSdGYJzMYpjhkXAxE.cache → aH/aHkgzJaZpAnMTLP7DvYxN89R8XHqtxL4DrC2d90U3Z8.cache} +0 -0
- data/spec/tmp/cache/assets/sprockets/v3.0/zI/zIeYCT_q2r-xVxHddTUvci_yk-5Aa8M6wKAaxpqoNt0.cache +1 -0
- data/turbo-sprockets-rails4.gemspec +1 -1
- metadata +15 -23
- data/spec/public/assets/file1-9461265d541718e5776632b202c4ccdd21f13d9cd7d0b4d92c1b43131292749a.js +0 -4
- data/spec/public/assets/file1-9461265d541718e5776632b202c4ccdd21f13d9cd7d0b4d92c1b43131292749a.js.gz +0 -0
- data/spec/public/assets/file2-e2a24754a5ca8cb2f9c645a80ad4d4ca375c4d9914f1d962b4fb3e779dc4ad34.js +0 -4
- data/spec/public/assets/file2-e2a24754a5ca8cb2f9c645a80ad4d4ca375c4d9914f1d962b4fb3e779dc4ad34.js.gz +0 -0
- data/spec/tmp/cache/assets/sprockets/v3.0/0g/0geAvurz1AX0xI67Ou6WBG0HEnHLFZG5Rbvog7JuFh8.cache +0 -1
- data/spec/tmp/cache/assets/sprockets/v3.0/Ny/Ny4Hng5x4A-TVYWIKr0AjzqV9U32nMfeROjIYX3t1zc.cache +0 -1
- data/spec/tmp/cache/assets/sprockets/v3.0/Py/PyP_Z86btB-ByMXeasgN-buL98MfdATp8WPzc8AWy6c.cache +0 -1
- data/spec/tmp/cache/assets/sprockets/v3.0/Yi/Yi_k91msAv7kbymP50BwVfhkKwo_XMEZIJmMf6LgTAA.cache +0 -1
- data/spec/tmp/cache/assets/sprockets/v3.0/b8/b8XCYwFHJAQi_UQnYIe_rPgE6W5gMlmY69smkT7lUUg.cache +0 -1
- data/spec/tmp/cache/assets/sprockets/v3.0/sk/skLSgxSN-gAyttjzKsGZfvS6147mrFxxK3ztXCqNNP8.cache +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93dc4b63a52cdc1eac49f1cb2465a380d547ae89
|
4
|
+
data.tar.gz: 35b1991e4acb678231774f80f13ef1cdf707c4bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06571631ba75f30ee811bca5c54fdb3de1fb8d2e2aa69e7910b44db0ef7e5c427bedcbf52a658cf42dd402af406fa331d88e153098d50af2758d221fb20b9ff8
|
7
|
+
data.tar.gz: 455c9c46852d8e3acc202e8c1891ae36694ce2a5592b1ab4d6b1c701ec4d373342ceaf52f921035f8c0489666794d1a8bd83c3c183e0d3ac2d890e831f6f6fa5
|
data/Gemfile
CHANGED
@@ -1,9 +1,58 @@
|
|
1
1
|
require 'turbo-sprockets/railtie'
|
2
2
|
|
3
3
|
module TurboSprockets
|
4
|
-
autoload :
|
4
|
+
autoload :AssetResolver, 'turbo-sprockets/asset_resolver'
|
5
|
+
autoload :ParallelCompiler, 'turbo-sprockets/parallel_compiler'
|
6
|
+
autoload :ParallelPreloader, 'turbo-sprockets/parallel_preloader'
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
+
class Config
|
9
|
+
attr_reader :precompiler, :preloader
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@precompiler = ComponentConfig.new(options.fetch(:precompiler, {}))
|
13
|
+
@preloader = ComponentConfig.new(options.fetch(:preloader, {}))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ComponentConfig
|
18
|
+
DEFAULT_WORKER_COUNT = 2
|
19
|
+
|
20
|
+
attr_accessor :enabled, :worker_count, :logger
|
21
|
+
alias_method :enabled?, :enabled
|
22
|
+
|
23
|
+
def initialize(options = {})
|
24
|
+
options.each_pair do |key, value|
|
25
|
+
send("#{key}=", value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def worker_count
|
30
|
+
worker_count_from_env || @worker_count || DEFAULT_WORKER_COUNT
|
31
|
+
end
|
32
|
+
|
33
|
+
def logger
|
34
|
+
@logger || Rails.logger
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def worker_count_from_env
|
40
|
+
if count = ENV['TURBO_SPROCKETS_WORKER_COUNT']
|
41
|
+
count.to_i
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def configure
|
48
|
+
yield configuration
|
49
|
+
end
|
50
|
+
|
51
|
+
def configuration
|
52
|
+
@configuration ||= Config.new(
|
53
|
+
precompiler: { enabled: true },
|
54
|
+
preloader: { enabled: true }
|
55
|
+
)
|
56
|
+
end
|
8
57
|
end
|
9
58
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module TurboSprockets
|
2
|
+
class AssetResolver
|
3
|
+
class << self
|
4
|
+
# Returns a relative, digested asset path for the given logical path.
|
5
|
+
#
|
6
|
+
# For example:
|
7
|
+
# AssetResolver.resolve('lux/checkmark_2x.png')
|
8
|
+
# => lux/checkmark_2x-7177b0151ec35ffb6d.png
|
9
|
+
#
|
10
|
+
def resolve(logical_path)
|
11
|
+
# If compile is true we're running in development and have access to the
|
12
|
+
# sprockets environment. If compile is false the sprockets environment
|
13
|
+
# will not be available, so we have to fall back to the asset manifest.
|
14
|
+
if Rails.application.config.assets.compile
|
15
|
+
asset = Rails.application.assets.find_asset(logical_path)
|
16
|
+
|
17
|
+
if Rails.application.config.assets.digest
|
18
|
+
asset.try(&:digest_path)
|
19
|
+
else
|
20
|
+
asset.try(&:logical_path)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
Rails.application.assets_manifest.assets[logical_path]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns an absolute, undigested asset path for the given logical path.
|
28
|
+
# This is the original asset path from app/assets or similar.
|
29
|
+
#
|
30
|
+
# For example:
|
31
|
+
# AssetResolver.resolve_naked('lux/checkmark_2x.png')
|
32
|
+
# => /data/lumoslabs/shared/bundle/ruby/2.4.0/gems/lux-2.11.0/app/assets/images/lux/checkmark_2x.png
|
33
|
+
#
|
34
|
+
def resolve_naked(logical_path)
|
35
|
+
# check to see if logical_path exists within any of the current asset paths
|
36
|
+
Rails.application.config.assets.paths.each do |path|
|
37
|
+
candidate = File.join(path, logical_path)
|
38
|
+
return candidate if File.exist?(candidate)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the absolute, digested URL for the given logical path. This
|
43
|
+
# includes important stuff like the CDN host/port and asset prefix
|
44
|
+
# (i.e. /compiled).
|
45
|
+
#
|
46
|
+
# For example:
|
47
|
+
# AssetResolver.resolve_url_for('lux/checkmark_2x.png')
|
48
|
+
# => https://asset.lumosity.com:443/compiled/lux/checkmark_2x-7177b0151ec35ffb6d.png
|
49
|
+
#
|
50
|
+
def resolve_url_for(logical_path)
|
51
|
+
url_join(
|
52
|
+
Rails.application.config.action_controller.asset_host,
|
53
|
+
Rails.application.config.assets.prefix,
|
54
|
+
resolve(logical_path)
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Operates like File.join, but on segments of a URL. Specifically, it makes
|
59
|
+
# sure the segments are conjoined by only one forward slash. The URI class
|
60
|
+
# is also capable of doing this, but is much more difficult to use. Note
|
61
|
+
# that this method doesn't consider whether or not the segments are relative
|
62
|
+
# or absolute - it simply joins them.
|
63
|
+
#
|
64
|
+
# Examples:
|
65
|
+
# UrlMethods.join('/foo/', '/bar', '/baz/')
|
66
|
+
# => 'foo/bar/baz'
|
67
|
+
#
|
68
|
+
# UrlMethods.join('http://foo.com', 'bar/', '/baz')
|
69
|
+
# # => 'http://foo.com/bar/baz'
|
70
|
+
#
|
71
|
+
def url_join(*segments)
|
72
|
+
segments.compact!
|
73
|
+
|
74
|
+
# this regex strips off leading and trailing forward slashes
|
75
|
+
joined = segments.map { |p| p.sub(/\A\/?(.*?)\/?\z/, "\\1") }.join('/')
|
76
|
+
|
77
|
+
# handle absolute URLs
|
78
|
+
segments.first.start_with?('/') ? "/#{joined}" : joined
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -4,8 +4,6 @@ require 'json'
|
|
4
4
|
|
5
5
|
module TurboSprockets
|
6
6
|
class ParallelCompiler
|
7
|
-
DEFAULT_WORKER_COUNT = 2
|
8
|
-
|
9
7
|
attr_reader :manifest
|
10
8
|
|
11
9
|
def initialize(manifest)
|
@@ -86,7 +84,7 @@ module TurboSprockets
|
|
86
84
|
end
|
87
85
|
|
88
86
|
def worker_count
|
89
|
-
|
87
|
+
TurboSprockets.configuration.precompiler.worker_count
|
90
88
|
end
|
91
89
|
|
92
90
|
def environment
|
@@ -94,7 +92,7 @@ module TurboSprockets
|
|
94
92
|
end
|
95
93
|
|
96
94
|
def logger
|
97
|
-
|
95
|
+
TurboSprockets.configuration.precompiler.logger
|
98
96
|
end
|
99
97
|
end
|
100
98
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
|
3
|
+
# The asset preloader is designed to precompute and cache all precompilable
|
4
|
+
# assets in parallel to avoid doing it in serial on the first request. As of
|
5
|
+
# Sprockets 3, all assets on the precompile list (i.e. config.assets.precompile)
|
6
|
+
# are compiled on the first request whether the current page has asked for them
|
7
|
+
# or not. Obviously such behavior can mean a very slow initial request (we were
|
8
|
+
# seeing load times on the order of 10-11 minutes). By preloading, or warming the
|
9
|
+
# sprockets cache, initial page load times can be reduced to ~15 seconds (with
|
10
|
+
# an additional ~2 minutes spent during boot). Preloading only happens once, so
|
11
|
+
# subsequent requests should be fast. Preloading is different from precompiling,
|
12
|
+
# as the latter does not appear to cache the assets once they've been compiled.
|
13
|
+
# Generally speaking, preloading should be done in development and precompiling
|
14
|
+
# should be done in production.
|
15
|
+
module TurboSprockets
|
16
|
+
class ParallelPreloader
|
17
|
+
class << self
|
18
|
+
def preload!
|
19
|
+
list = precompile_list
|
20
|
+
|
21
|
+
count = 0
|
22
|
+
count_mutex = Mutex.new
|
23
|
+
|
24
|
+
options = {
|
25
|
+
in_processes: worker_count,
|
26
|
+
finish: -> (*) {
|
27
|
+
count_mutex.synchronize { count += 1 }
|
28
|
+
|
29
|
+
if count % 10 == 0 || count == list.size
|
30
|
+
logger.info("#{count}/#{list.size} preloading assets... ")
|
31
|
+
end
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
Parallel.each(list, options) do |path|
|
36
|
+
# compat: false causes #resolve to return fully resolved asset URIs,
|
37
|
+
# complete with correct MIME type, etc
|
38
|
+
uri, _ = assets.resolve(path, compat: false)
|
39
|
+
next unless uri
|
40
|
+
|
41
|
+
# only load the asset if it hasn't been cached yet
|
42
|
+
unloaded = Sprockets::UnloadedAsset.new(uri, assets)
|
43
|
+
key = unloaded.dependency_history_key
|
44
|
+
assets.load(uri) unless assets.cache.get(key)
|
45
|
+
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
logger.info('done')
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# find all assets that have been added to the precompile list
|
55
|
+
# code adapted from Sprockets::Manifest and Sprockets::Legacy
|
56
|
+
def precompile_list
|
57
|
+
paths, filters = config.assets.precompile.partition do |arg|
|
58
|
+
Sprockets::Manifest.simple_logical_path?(arg)
|
59
|
+
end
|
60
|
+
|
61
|
+
filters = filters.map do |arg|
|
62
|
+
Sprockets::Manifest.compile_match_filter(arg)
|
63
|
+
end
|
64
|
+
|
65
|
+
paths + assets.logical_paths.each_with_object([]) do |(logical_path, filename), ret|
|
66
|
+
if filters.any? { |f| f.call(logical_path, filename) }
|
67
|
+
ret << logical_path
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def worker_count
|
73
|
+
TurboSprockets.configuration.preloader.worker_count
|
74
|
+
end
|
75
|
+
|
76
|
+
def config
|
77
|
+
Rails.application.config
|
78
|
+
end
|
79
|
+
|
80
|
+
def assets
|
81
|
+
Rails.application.assets
|
82
|
+
end
|
83
|
+
|
84
|
+
def logger
|
85
|
+
TurboSprockets.configuration.preloader.logger
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -4,10 +4,32 @@ module TurboSprockets
|
|
4
4
|
unless Sprockets::Manifest.method_defined?(:compile_with_parallelism)
|
5
5
|
Sprockets::Manifest.class_eval do
|
6
6
|
def compile_with_parallelism(*args)
|
7
|
-
|
7
|
+
if TurboSprockets.configuration.precompiler.enabled?
|
8
|
+
TurboSprockets::ParallelCompiler.new(self).compile(*args)
|
9
|
+
else
|
10
|
+
compile_without_parallelism
|
11
|
+
end
|
8
12
|
end
|
9
13
|
|
10
|
-
|
14
|
+
alias_method :compile_without_parallelism, :compile
|
15
|
+
alias_method :compile, :compile_with_parallelism
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
config.after_initialize do
|
21
|
+
if ::TurboSprockets.configuration.preloader.enabled?
|
22
|
+
# make sure routes are available before attempting to preload, since
|
23
|
+
# assets may make use of route helpers
|
24
|
+
Rails.application.reload_routes!
|
25
|
+
|
26
|
+
# actually do the preloading
|
27
|
+
TurboSprockets::ParallelPreloader.preload!
|
28
|
+
|
29
|
+
# for some reason parallel operations may cause activerecord to
|
30
|
+
# disconnect
|
31
|
+
if const_defined?(:ActiveRecord)
|
32
|
+
ActiveRecord::Base.connection.reconnect!
|
11
33
|
end
|
12
34
|
end
|
13
35
|
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
describe TurboSprockets::AssetResolver do
|
5
|
+
RSpec::Matchers.define :match_digested do |expected|
|
6
|
+
match do |actual|
|
7
|
+
extname = File.extname(expected)
|
8
|
+
re = /#{expected.chomp(extname)}-[a-f0-9]+#{extname}/
|
9
|
+
!!(re =~ actual)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:environment) { Sprockets::Environment.new(Rails.root) }
|
14
|
+
let(:manifest_path) { 'manifest.json' }
|
15
|
+
let(:logical_path) { 'file1.js' }
|
16
|
+
let(:asset_host) { 'http://localhost:3000' }
|
17
|
+
|
18
|
+
# sprockets options
|
19
|
+
let(:prefix) { '' }
|
20
|
+
let(:digest) { true }
|
21
|
+
let(:compile) { true }
|
22
|
+
|
23
|
+
# adapted from:
|
24
|
+
# https://github.com/rails/sprockets-rails/blob/v3.2.0/lib/sprockets/railtie.rb#L198
|
25
|
+
let(:manifest) do
|
26
|
+
path = File.join('public', prefix)
|
27
|
+
Sprockets::Manifest.new(environment, path, manifest_path)
|
28
|
+
end
|
29
|
+
|
30
|
+
def logical_to_digested_path(logical_path)
|
31
|
+
extname = File.extname(logical_path)
|
32
|
+
digest_hash = SecureRandom.hex
|
33
|
+
"#{logical_path.chomp(extname)}-#{digest_hash}#{extname}"
|
34
|
+
end
|
35
|
+
|
36
|
+
before do
|
37
|
+
allow(Rails.application).to receive(:assets).and_return(environment)
|
38
|
+
allow(Rails.application).to receive(:assets_manifest).and_return(manifest)
|
39
|
+
allow(Rails.application.config.assets).to receive(:digest).and_return(digest)
|
40
|
+
allow(Rails.application.config.assets).to receive(:compile).and_return(compile)
|
41
|
+
allow(Rails.application.config.assets).to receive(:prefix).and_return(prefix)
|
42
|
+
allow(Rails.application.config.action_controller).to receive(:asset_host).and_return(asset_host)
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '.url_join' do
|
46
|
+
it 'joins url segments with mismatched leading/trailing slashes' do
|
47
|
+
expect(described_class.url_join('foo/', '/bar/', '/baz')).to eq('foo/bar/baz')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'keeps absolute URLs absolute' do
|
51
|
+
expect(described_class.url_join('/foo', '/bar/', '/baz')).to eq('/foo/bar/baz')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "doesn't modify domain names and schemes" do
|
55
|
+
expect(described_class.url_join('https://foo.com', '/bar/', '/baz')).to(
|
56
|
+
eq('https://foo.com/bar/baz')
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with a sprockets environment' do
|
62
|
+
before do
|
63
|
+
Rails.application.config.assets.paths.each do |path|
|
64
|
+
environment.append_path(path)
|
65
|
+
environment.context_class.send(:include, ::Sprockets::Rails::Context)
|
66
|
+
environment.context_class.digest_assets = digest
|
67
|
+
environment.context_class.assets_prefix = prefix
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when digesting is disabled' do
|
72
|
+
let(:digest) { false }
|
73
|
+
|
74
|
+
describe '.resolve' do
|
75
|
+
it 'returns a relative undigested path' do
|
76
|
+
expect(described_class.resolve(logical_path)).to eq(logical_path)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '.resolve_naked' do
|
81
|
+
it 'returns the original, absolute, undigested asset path' do
|
82
|
+
expect(described_class.resolve_naked(logical_path)).to eq(
|
83
|
+
Rails.root.join(File.join(%w[app assets javascripts])).join(logical_path).to_s
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '.resolve_url_for' do
|
89
|
+
it 'returns the full undigested URL' do
|
90
|
+
expect(described_class.resolve_url_for(logical_path)).to eq(
|
91
|
+
"#{asset_host}/#{prefix}/#{logical_path}"
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when digesting is enabled' do
|
98
|
+
describe '.resolve' do
|
99
|
+
it 'returns a relative digested asset path' do
|
100
|
+
result = described_class.resolve(logical_path)
|
101
|
+
expect(result).to match_digested(logical_path)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '.resolve_naked' do
|
106
|
+
it 'returns the original, absolute, undigested asset path' do
|
107
|
+
expect(described_class.resolve_naked(logical_path)).to eq(
|
108
|
+
Rails.root.join(File.join(%w[app assets javascripts])).join(logical_path).to_s
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '.resolve_url_for' do
|
114
|
+
it 'returns the full digested URL' do
|
115
|
+
uri = URI.parse(described_class.resolve_url_for(logical_path))
|
116
|
+
expect(uri.path.sub(/\/?#{prefix}\/?/, '')).to match_digested(logical_path)
|
117
|
+
expect(uri.to_s).to start_with(asset_host)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'without a sprockets environment' do
|
124
|
+
let(:environment) { nil }
|
125
|
+
let(:compile) { false }
|
126
|
+
|
127
|
+
before do
|
128
|
+
manifest.assets[logical_path] = logical_to_digested_path(logical_path)
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '.resolve' do
|
132
|
+
it 'returns the relative digested path from the manifest' do
|
133
|
+
result = described_class.resolve(logical_path)
|
134
|
+
expect(result).to eq(manifest.assets[logical_path])
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe '.resolve_naked' do
|
139
|
+
it 'returns the original, absolute, undigested asset path' do
|
140
|
+
expect(described_class.resolve_naked(logical_path)).to eq(
|
141
|
+
Rails.root.join(File.join(%w[app assets javascripts])).join(logical_path).to_s
|
142
|
+
)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '.resolve_url_for' do
|
147
|
+
it 'returns the full digested URL' do
|
148
|
+
uri = URI.parse(described_class.resolve_url_for(logical_path))
|
149
|
+
expect(uri.path.sub(/\/?#{prefix}\/?/, '')).to match_digested(logical_path)
|
150
|
+
expect(uri.to_s).to start_with(asset_host)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
data/spec/log/test.log
CHANGED
@@ -0,0 +1,88 @@
|
|
1
|
+
1/2 preloading assets...
|
2
|
+
2/2 preloading assets...
|
3
|
+
done
|
4
|
+
1/2 preloading assets...
|
5
|
+
2/2 preloading assets...
|
6
|
+
done
|
7
|
+
1/2 preloading assets...
|
8
|
+
2/2 preloading assets...
|
9
|
+
done
|
10
|
+
1/2 preloading assets...
|
11
|
+
2/2 preloading assets...
|
12
|
+
done
|
13
|
+
1/2 preloading assets...
|
14
|
+
2/2 preloading assets...
|
15
|
+
done
|
16
|
+
1/2 preloading assets...
|
17
|
+
2/2 preloading assets...
|
18
|
+
done
|
19
|
+
1/2 preloading assets...
|
20
|
+
2/2 preloading assets...
|
21
|
+
done
|
22
|
+
1/2 preloading assets...
|
23
|
+
2/2 preloading assets...
|
24
|
+
done
|
25
|
+
1/2 preloading assets...
|
26
|
+
2/2 preloading assets...
|
27
|
+
done
|
28
|
+
1/2 preloading assets...
|
29
|
+
2/2 preloading assets...
|
30
|
+
done
|
31
|
+
2/2 preloading assets...
|
32
|
+
done
|
33
|
+
2/2 preloading assets...
|
34
|
+
done
|
35
|
+
2/2 preloading assets...
|
36
|
+
done
|
37
|
+
2/2 preloading assets...
|
38
|
+
done
|
39
|
+
2/2 preloading assets...
|
40
|
+
done
|
41
|
+
2/2 preloading assets...
|
42
|
+
done
|
43
|
+
2/2 preloading assets...
|
44
|
+
done
|
45
|
+
2/2 preloading assets...
|
46
|
+
done
|
47
|
+
2/2 preloading assets...
|
48
|
+
done
|
49
|
+
2/2 preloading assets...
|
50
|
+
done
|
51
|
+
2/2 preloading assets...
|
52
|
+
done
|
53
|
+
2/2 preloading assets...
|
54
|
+
done
|
55
|
+
2/2 preloading assets...
|
56
|
+
done
|
57
|
+
2/2 preloading assets...
|
58
|
+
done
|
59
|
+
2/2 preloading assets...
|
60
|
+
done
|
61
|
+
2/2 preloading assets...
|
62
|
+
done
|
63
|
+
2/2 preloading assets...
|
64
|
+
done
|
65
|
+
2/2 preloading assets...
|
66
|
+
done
|
67
|
+
2/2 preloading assets...
|
68
|
+
done
|
69
|
+
2/2 preloading assets...
|
70
|
+
done
|
71
|
+
2/2 preloading assets...
|
72
|
+
done
|
73
|
+
2/2 preloading assets...
|
74
|
+
done
|
75
|
+
2/2 preloading assets...
|
76
|
+
done
|
77
|
+
2/2 preloading assets...
|
78
|
+
done
|
79
|
+
2/2 preloading assets...
|
80
|
+
done
|
81
|
+
2/2 preloading assets...
|
82
|
+
done
|
83
|
+
2/2 preloading assets...
|
84
|
+
done
|
85
|
+
2/2 preloading assets...
|
86
|
+
done
|
87
|
+
2/2 preloading assets...
|
88
|
+
done
|
@@ -42,14 +42,31 @@ describe TurboSprockets::ParallelCompiler do
|
|
42
42
|
expect(manifest['assets']).to eq(files)
|
43
43
|
end
|
44
44
|
|
45
|
-
it 'uses the specified number of workers' do
|
46
|
-
|
47
|
-
allow(TurboSprockets).to receive(:logger).and_return(logger)
|
48
|
-
|
49
|
-
with_env('SPROCKETS_WORKER_COUNT' => '4') do
|
45
|
+
it 'uses the specified number of workers from the ENV' do
|
46
|
+
with_env('TURBO_SPROCKETS_WORKER_COUNT' => '4') do
|
50
47
|
precompile!
|
51
48
|
end
|
52
49
|
|
53
50
|
expect(logger.messages).to include([:warn, 'Precompiling with 4 workers'])
|
54
51
|
end
|
52
|
+
|
53
|
+
it 'uses the specified number of workers from the config' do
|
54
|
+
TurboSprockets.configure do |config|
|
55
|
+
config.precompiler.worker_count = 5
|
56
|
+
end
|
57
|
+
|
58
|
+
precompile!
|
59
|
+
|
60
|
+
expect(logger.messages).to include([:warn, 'Precompiling with 5 workers'])
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'does not compile in parallel when configured not to' do
|
64
|
+
TurboSprockets.configure do |config|
|
65
|
+
config.precompiler.enabled = false
|
66
|
+
end
|
67
|
+
|
68
|
+
precompile!
|
69
|
+
|
70
|
+
expect(logger.messages).to be_empty
|
71
|
+
end
|
55
72
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TurboSprockets::ParallelPreloader do
|
4
|
+
let(:logical_paths) { %w(file1.js file2.js) }
|
5
|
+
|
6
|
+
def get_cached_asset(path)
|
7
|
+
uri, _ = assets.resolve(path, compat: false)
|
8
|
+
key = Sprockets::UnloadedAsset.new(uri, assets).dependency_history_key
|
9
|
+
assets.cache.get(key)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.preload!' do
|
13
|
+
it 'preloads all assets' do
|
14
|
+
logical_paths.each do |path|
|
15
|
+
expect(get_cached_asset(path)).to be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
described_class.preload!
|
19
|
+
|
20
|
+
logical_paths.each do |path|
|
21
|
+
expect(get_cached_asset(path)).to_not be_nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'parallelizes the preload' do
|
26
|
+
# make sure we have _some_ way of knowing parallel compliation is happening
|
27
|
+
expect(Parallel).to receive(:each).and_call_original
|
28
|
+
described_class.preload!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -22,9 +22,9 @@ end
|
|
22
22
|
module LetDeclarations
|
23
23
|
extend RSpec::SharedContext
|
24
24
|
|
25
|
-
let(:app)
|
26
|
-
|
27
|
-
|
25
|
+
let(:app) { Rails.application }
|
26
|
+
let(:assets) { app.assets }
|
27
|
+
let(:logger) { CapturingLogger.new }
|
28
28
|
|
29
29
|
let(:assets_dir) do
|
30
30
|
TurboSprockets::DummyApplication.root.join('public/assets')
|
@@ -58,9 +58,18 @@ end
|
|
58
58
|
RSpec.configure do |config|
|
59
59
|
config.include(LetDeclarations)
|
60
60
|
|
61
|
-
config.before
|
61
|
+
config.before do
|
62
62
|
FileUtils.rm_rf(tmp_dir)
|
63
63
|
FileUtils.rm_rf(assets_dir)
|
64
64
|
FileUtils.mkdir_p(assets_dir)
|
65
|
+
|
66
|
+
TurboSprockets.configure do |config|
|
67
|
+
config.preloader.logger = logger
|
68
|
+
config.precompiler.logger = logger
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
config.after(:each) do
|
73
|
+
TurboSprockets.instance_variable_set(:@configuration, nil)
|
65
74
|
end
|
66
75
|
end
|
data/spec/tmp/cache/assets/sprockets/v3.0/Le/LeawzTm7RwKtrjUFVCR7o9JVRLjcbCfbykBpzdSZxtM.cache
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
I"app/assets/javascripts/file1.js?type=application/javascript&id=f8187f06aff5f6971815ff0ee8806c8ed5eb9924fdc8094fea7c73134ed73bce:ET
|
data/spec/tmp/cache/assets/sprockets/v3.0/Ok/OkAys_2Q1L3vb5MfExaVwWECnkhnpaauOKQ4K5h2EQM.cache
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
I"�app/assets/javascripts/file1.js?type=application/javascript&pipeline=self&id=4a6526d450ce35992b00a9ae6913b6ef20260999c28f6b3bca28b79353e33be5:ET
|
Binary file
|
Binary file
|
Binary file
|
data/spec/tmp/cache/assets/sprockets/v3.0/_T/_T7w3tcNAR1OjzPNFDxGLBsotNkwlubZL18upfeyLOk.cache
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
I"�app/assets/javascripts/file2.js?type=application/javascript&pipeline=self&id=c0f02293ed827ef09372ec69f2eacc7cc884fb685310c441a3a49a09eae13970:ET
|
Binary file
|
data/spec/tmp/cache/assets/sprockets/v3.0/zI/zIeYCT_q2r-xVxHddTUvci_yk-5Aa8M6wKAaxpqoNt0.cache
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
I"app/assets/javascripts/file2.js?type=application/javascript&id=035933ec486cdea65727bf40150c9be42540a7243591294b9d7aa9466c5be4be:ET
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turbo-sprockets-rails4
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cameron Dutro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parallel
|
@@ -31,9 +31,6 @@ dependencies:
|
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '4'
|
34
|
-
- - "<"
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: '5'
|
37
34
|
type: :runtime
|
38
35
|
prerelease: false
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -41,9 +38,6 @@ dependencies:
|
|
41
38
|
- - ">="
|
42
39
|
- !ruby/object:Gem::Version
|
43
40
|
version: '4'
|
44
|
-
- - "<"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '5'
|
47
41
|
- !ruby/object:Gem::Dependency
|
48
42
|
name: sprockets
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -69,33 +63,31 @@ files:
|
|
69
63
|
- README.md
|
70
64
|
- Rakefile
|
71
65
|
- lib/turbo-sprockets-rails4.rb
|
66
|
+
- lib/turbo-sprockets/asset_resolver.rb
|
72
67
|
- lib/turbo-sprockets/parallel_compiler.rb
|
68
|
+
- lib/turbo-sprockets/parallel_preloader.rb
|
73
69
|
- lib/turbo-sprockets/railtie.rb
|
74
70
|
- lib/turbo-sprockets/version.rb
|
75
71
|
- spec/app/assets/javascripts/file1.js
|
76
72
|
- spec/app/assets/javascripts/file2.js
|
73
|
+
- spec/asset_resolver_spec.rb
|
77
74
|
- spec/config/application.rb
|
78
75
|
- spec/log/test.log
|
79
76
|
- spec/parallel_compiler_spec.rb
|
80
|
-
- spec/
|
81
|
-
- spec/public/assets/file1-9461265d541718e5776632b202c4ccdd21f13d9cd7d0b4d92c1b43131292749a.js.gz
|
82
|
-
- spec/public/assets/file2-e2a24754a5ca8cb2f9c645a80ad4d4ca375c4d9914f1d962b4fb3e779dc4ad34.js
|
83
|
-
- spec/public/assets/file2-e2a24754a5ca8cb2f9c645a80ad4d4ca375c4d9914f1d962b4fb3e779dc4ad34.js.gz
|
77
|
+
- spec/parallel_preloader_spec.rb
|
84
78
|
- spec/spec_helper.rb
|
85
|
-
- spec/tmp/cache/assets/sprockets/v3.0
|
86
|
-
- spec/tmp/cache/assets/sprockets/v3.0/
|
87
|
-
- spec/tmp/cache/assets/sprockets/v3.0/F9/F9uLDkuCpwXDtwzIob92yhwmsuBy0NUF2GnJGRiyWF4.cache
|
88
|
-
- spec/tmp/cache/assets/sprockets/v3.0/FA/FA7o1GffPYj_2A2EsHqBM8vMKfdSdGYJzMYpjhkXAxE.cache
|
89
|
-
- spec/tmp/cache/assets/sprockets/v3.0/Ny/Ny4Hng5x4A-TVYWIKr0AjzqV9U32nMfeROjIYX3t1zc.cache
|
79
|
+
- spec/tmp/cache/assets/sprockets/v3.0/Le/LeawzTm7RwKtrjUFVCR7o9JVRLjcbCfbykBpzdSZxtM.cache
|
80
|
+
- spec/tmp/cache/assets/sprockets/v3.0/Ok/OkAys_2Q1L3vb5MfExaVwWECnkhnpaauOKQ4K5h2EQM.cache
|
90
81
|
- spec/tmp/cache/assets/sprockets/v3.0/Oo/OoRDv9ysw5g18-975bcUUGTFBnb0-ShhbDgUqo-VuOU.cache
|
91
|
-
- spec/tmp/cache/assets/sprockets/v3.0/
|
92
|
-
- spec/tmp/cache/assets/sprockets/v3.0/
|
82
|
+
- spec/tmp/cache/assets/sprockets/v3.0/P5/P5S3gl7IvP4a1i2vH3aGqb7MG5quRXURszmF4Jo-exM.cache
|
83
|
+
- spec/tmp/cache/assets/sprockets/v3.0/Tj/TjacfODSnBaChvUCg9VRCYGvF9N9D1BFEYa_LOY0Myo.cache
|
84
|
+
- spec/tmp/cache/assets/sprockets/v3.0/YF/YFli9jLfluQ3HEM4JQkUGPnhKztRu1QjsR-krCrHnDQ.cache
|
93
85
|
- spec/tmp/cache/assets/sprockets/v3.0/_4/_4pm9XADf-SWLKsx4Qea0XRAZetvbGWa8MQf_aMqcm0.cache
|
94
|
-
- spec/tmp/cache/assets/sprockets/v3.0/
|
86
|
+
- spec/tmp/cache/assets/sprockets/v3.0/_T/_T7w3tcNAR1OjzPNFDxGLBsotNkwlubZL18upfeyLOk.cache
|
87
|
+
- spec/tmp/cache/assets/sprockets/v3.0/aH/aHkgzJaZpAnMTLP7DvYxN89R8XHqtxL4DrC2d90U3Z8.cache
|
95
88
|
- spec/tmp/cache/assets/sprockets/v3.0/c5/c5fWyhSDQYpk5wBXxoIj4L8d8VRI5fx8BA-Vusc-Tm8.cache
|
96
89
|
- spec/tmp/cache/assets/sprockets/v3.0/fi/fide8IvH1RAoWxoK8yipcMFLPqQym3YmbZs93J5nyGM.cache
|
97
|
-
- spec/tmp/cache/assets/sprockets/v3.0/
|
98
|
-
- spec/tmp/cache/assets/sprockets/v3.0/sk/skLSgxSN-gAyttjzKsGZfvS6147mrFxxK3ztXCqNNP8.cache
|
90
|
+
- spec/tmp/cache/assets/sprockets/v3.0/zI/zIeYCT_q2r-xVxHddTUvci_yk-5Aa8M6wKAaxpqoNt0.cache
|
99
91
|
- turbo-sprockets-rails4.gemspec
|
100
92
|
homepage: http://github.com/camertron
|
101
93
|
licenses: []
|
@@ -116,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
116
108
|
version: '0'
|
117
109
|
requirements: []
|
118
110
|
rubyforge_project:
|
119
|
-
rubygems_version: 2.
|
111
|
+
rubygems_version: 2.6.11
|
120
112
|
signing_key:
|
121
113
|
specification_version: 4
|
122
114
|
summary: Speed up asset precompliation by compiling assets in parallel.
|
data/spec/public/assets/file1-9461265d541718e5776632b202c4ccdd21f13d9cd7d0b4d92c1b43131292749a.js.gz
DELETED
Binary file
|
data/spec/public/assets/file2-e2a24754a5ca8cb2f9c645a80ad4d4ca375c4d9914f1d962b4fb3e779dc4ad34.js.gz
DELETED
Binary file
|
data/spec/tmp/cache/assets/sprockets/v3.0/0g/0geAvurz1AX0xI67Ou6WBG0HEnHLFZG5Rbvog7JuFh8.cache
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
"%h,t�[�J�!�R����S$I�9Q�F2��^g�
|
data/spec/tmp/cache/assets/sprockets/v3.0/Ny/Ny4Hng5x4A-TVYWIKr0AjzqV9U32nMfeROjIYX3t1zc.cache
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
I"app/assets/javascripts/file1.js?type=application/javascript&id=fd26267e172201fa2d3b128fce4cb1a53c227f28aa0b693ac2708a9ab0b44ea2:ET
|
data/spec/tmp/cache/assets/sprockets/v3.0/Py/PyP_Z86btB-ByMXeasgN-buL98MfdATp8WPzc8AWy6c.cache
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
I"app/assets/javascripts/file2.js?type=application/javascript&id=8e7ad17b3e9d5262767b265f3b265c1f5fc9742a2782ce3232b8087632963d4d:ET
|
data/spec/tmp/cache/assets/sprockets/v3.0/Yi/Yi_k91msAv7kbymP50BwVfhkKwo_XMEZIJmMf6LgTAA.cache
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
"%N�a�t�%�چ�e�o/���H.����t⠝
|
data/spec/tmp/cache/assets/sprockets/v3.0/b8/b8XCYwFHJAQi_UQnYIe_rPgE6W5gMlmY69smkT7lUUg.cache
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
I"�app/assets/javascripts/file2.js?type=application/javascript&pipeline=self&id=93fac2a2152bd5b89fdb8f97fd3fac83e8b82a3621681c1f077981a977775fcf:ET
|
data/spec/tmp/cache/assets/sprockets/v3.0/sk/skLSgxSN-gAyttjzKsGZfvS6147mrFxxK3ztXCqNNP8.cache
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
I"�app/assets/javascripts/file1.js?type=application/javascript&pipeline=self&id=18ce48382a6f42ab81da8c115f1e4c686ad07b2fec30a431a20e627dd718ae7f:ET
|