sprockets 3.7.2 → 4.0.2
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 +47 -267
- data/README.md +477 -321
- data/bin/sprockets +11 -7
- data/lib/rake/sprocketstask.rb +3 -2
- data/lib/sprockets.rb +99 -39
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +31 -23
- data/lib/sprockets/autoload.rb +5 -0
- data/lib/sprockets/autoload/babel.rb +8 -0
- data/lib/sprockets/autoload/closure.rb +1 -0
- data/lib/sprockets/autoload/coffee_script.rb +1 -0
- data/lib/sprockets/autoload/eco.rb +1 -0
- data/lib/sprockets/autoload/ejs.rb +1 -0
- data/lib/sprockets/autoload/jsminc.rb +8 -0
- data/lib/sprockets/autoload/sass.rb +1 -0
- data/lib/sprockets/autoload/sassc.rb +8 -0
- data/lib/sprockets/autoload/uglifier.rb +1 -0
- data/lib/sprockets/autoload/yui.rb +1 -0
- data/lib/sprockets/autoload/zopfli.rb +7 -0
- data/lib/sprockets/babel_processor.rb +66 -0
- data/lib/sprockets/base.rb +49 -12
- data/lib/sprockets/bower.rb +5 -2
- data/lib/sprockets/bundle.rb +40 -4
- data/lib/sprockets/cache.rb +36 -1
- data/lib/sprockets/cache/file_store.rb +25 -3
- data/lib/sprockets/cache/memory_store.rb +9 -0
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cached_environment.rb +14 -19
- data/lib/sprockets/closure_compressor.rb +1 -0
- data/lib/sprockets/coffee_script_processor.rb +18 -4
- data/lib/sprockets/compressing.rb +43 -3
- data/lib/sprockets/configuration.rb +3 -7
- data/lib/sprockets/context.rb +97 -24
- data/lib/sprockets/dependencies.rb +1 -0
- data/lib/sprockets/digest_utils.rb +25 -5
- data/lib/sprockets/directive_processor.rb +45 -35
- data/lib/sprockets/eco_processor.rb +1 -0
- data/lib/sprockets/ejs_processor.rb +1 -0
- data/lib/sprockets/encoding_utils.rb +1 -0
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +28 -21
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/exporters/base.rb +71 -0
- data/lib/sprockets/exporters/file_exporter.rb +24 -0
- data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
- data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
- data/lib/sprockets/exporting.rb +73 -0
- data/lib/sprockets/file_reader.rb +1 -0
- data/lib/sprockets/http_utils.rb +25 -7
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +11 -10
- data/lib/sprockets/loader.rb +87 -67
- data/lib/sprockets/manifest.rb +64 -62
- data/lib/sprockets/manifest_utils.rb +9 -6
- data/lib/sprockets/mime.rb +8 -42
- data/lib/sprockets/npm.rb +52 -0
- data/lib/sprockets/path_dependency_utils.rb +3 -11
- data/lib/sprockets/path_digest_utils.rb +2 -1
- data/lib/sprockets/path_utils.rb +87 -7
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +31 -61
- data/lib/sprockets/processor_utils.rb +24 -35
- data/lib/sprockets/resolve.rb +177 -93
- data/lib/sprockets/sass_cache_store.rb +2 -6
- data/lib/sprockets/sass_compressor.rb +13 -1
- data/lib/sprockets/sass_functions.rb +1 -0
- data/lib/sprockets/sass_importer.rb +1 -0
- data/lib/sprockets/sass_processor.rb +30 -9
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +26 -23
- data/lib/sprockets/source_map_processor.rb +66 -0
- data/lib/sprockets/source_map_utils.rb +483 -0
- data/lib/sprockets/transformers.rb +63 -35
- data/lib/sprockets/uglifier_compressor.rb +21 -11
- data/lib/sprockets/unloaded_asset.rb +13 -11
- data/lib/sprockets/uri_tar.rb +1 -0
- data/lib/sprockets/uri_utils.rb +11 -8
- data/lib/sprockets/utils.rb +41 -74
- data/lib/sprockets/utils/gzip.rb +46 -14
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +1 -0
- metadata +127 -23
- data/LICENSE +0 -21
- data/lib/sprockets/coffee_script_template.rb +0 -17
- data/lib/sprockets/deprecation.rb +0 -90
- data/lib/sprockets/eco_template.rb +0 -17
- data/lib/sprockets/ejs_template.rb +0 -17
- data/lib/sprockets/engines.rb +0 -92
- data/lib/sprockets/erb_template.rb +0 -11
- data/lib/sprockets/legacy.rb +0 -330
- data/lib/sprockets/legacy_proc_processor.rb +0 -35
- data/lib/sprockets/legacy_tilt_processor.rb +0 -29
- data/lib/sprockets/sass_template.rb +0 -19
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'fileutils'
|
2
3
|
require 'logger'
|
3
4
|
require 'sprockets/encoding_utils'
|
@@ -19,7 +20,9 @@ module Sprockets
|
|
19
20
|
class FileStore
|
20
21
|
# Internal: Default key limit for store.
|
21
22
|
DEFAULT_MAX_SIZE = 25 * 1024 * 1024
|
22
|
-
|
23
|
+
EXCLUDED_DIRS = ['.', '..'].freeze
|
24
|
+
GITKEEP_FILES = ['.gitkeep', '.keep'].freeze
|
25
|
+
|
23
26
|
# Internal: Default standard error fatal logger.
|
24
27
|
#
|
25
28
|
# Returns a Logger.
|
@@ -32,8 +35,10 @@ module Sprockets
|
|
32
35
|
# Public: Initialize the cache store.
|
33
36
|
#
|
34
37
|
# root - A String path to a directory to persist cached values to.
|
35
|
-
# max_size - A Integer of the maximum
|
36
|
-
# (default:
|
38
|
+
# max_size - A Integer of the maximum size the store will hold (in bytes).
|
39
|
+
# (default: 25MB).
|
40
|
+
# logger - The logger to which some info will be printed.
|
41
|
+
# (default logger level is FATAL and won't output anything).
|
37
42
|
def initialize(root, max_size = DEFAULT_MAX_SIZE, logger = self.class.default_logger)
|
38
43
|
@root = root
|
39
44
|
@max_size = max_size
|
@@ -122,6 +127,23 @@ module Sprockets
|
|
122
127
|
"#<#{self.class} size=#{size}/#{@max_size}>"
|
123
128
|
end
|
124
129
|
|
130
|
+
# Public: Clear the cache
|
131
|
+
#
|
132
|
+
# adapted from ActiveSupport::Cache::FileStore#clear
|
133
|
+
#
|
134
|
+
# Deletes all items from the cache. In this case it deletes all the entries in the specified
|
135
|
+
# file store directory except for .keep or .gitkeep. Be careful which directory is specified
|
136
|
+
# as @root because everything in that directory will be deleted.
|
137
|
+
#
|
138
|
+
# Returns true
|
139
|
+
def clear(options=nil)
|
140
|
+
if File.exist?(@root)
|
141
|
+
root_dirs = Dir.entries(@root).reject { |f| (EXCLUDED_DIRS + GITKEEP_FILES).include?(f) }
|
142
|
+
FileUtils.rm_r(root_dirs.collect{ |f| File.join(@root, f) })
|
143
|
+
end
|
144
|
+
true
|
145
|
+
end
|
146
|
+
|
125
147
|
private
|
126
148
|
# Internal: Get all cache files along with stats.
|
127
149
|
#
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Sprockets
|
2
3
|
class Cache
|
3
4
|
# Public: Basic in memory LRU cache.
|
@@ -61,6 +62,14 @@ module Sprockets
|
|
61
62
|
def inspect
|
62
63
|
"#<#{self.class} size=#{@cache.size}/#{@max_size}>"
|
63
64
|
end
|
65
|
+
|
66
|
+
# Public: Clear the cache
|
67
|
+
#
|
68
|
+
# Returns true
|
69
|
+
def clear(options=nil)
|
70
|
+
@cache.clear
|
71
|
+
true
|
72
|
+
end
|
64
73
|
end
|
65
74
|
end
|
66
75
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Sprockets
|
2
3
|
class Cache
|
3
4
|
# Public: A compatible cache store that doesn't store anything. Used by
|
@@ -41,6 +42,13 @@ module Sprockets
|
|
41
42
|
def inspect
|
42
43
|
"#<#{self.class}>"
|
43
44
|
end
|
45
|
+
|
46
|
+
# Public: Simulate clearing the cache
|
47
|
+
#
|
48
|
+
# Returns true
|
49
|
+
def clear(options=nil)
|
50
|
+
true
|
51
|
+
end
|
44
52
|
end
|
45
53
|
end
|
46
54
|
end
|
@@ -1,26 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/base'
|
2
3
|
|
3
4
|
module Sprockets
|
4
|
-
# `
|
5
|
+
# `CachedEnvironment` is a special cached version of `Environment`.
|
5
6
|
#
|
6
7
|
# The expection is that all of its file system methods are cached
|
7
|
-
# for the instances lifetime. This makes `
|
8
|
+
# for the instances lifetime. This makes `CachedEnvironment` much faster. This
|
8
9
|
# behavior is ideal in production environments where the file system
|
9
10
|
# is immutable.
|
10
11
|
#
|
11
|
-
# `
|
12
|
+
# `CachedEnvironment` should not be initialized directly. Instead use
|
12
13
|
# `Environment#cached`.
|
13
14
|
class CachedEnvironment < Base
|
14
15
|
def initialize(environment)
|
15
16
|
initialize_configuration(environment)
|
16
17
|
|
17
18
|
@cache = environment.cache
|
18
|
-
@stats =
|
19
|
-
@entries =
|
20
|
-
@uris =
|
21
|
-
|
22
|
-
@
|
23
|
-
@resolved_dependencies = Hash.new { |h, k| h[k] = _resolve_dependency(k) }
|
19
|
+
@stats = {}
|
20
|
+
@entries = {}
|
21
|
+
@uris = {}
|
22
|
+
@processor_cache_keys = {}
|
23
|
+
@resolved_dependencies = {}
|
24
24
|
end
|
25
25
|
|
26
26
|
# No-op return self as cached environment.
|
@@ -30,33 +30,28 @@ module Sprockets
|
|
30
30
|
alias_method :index, :cached
|
31
31
|
|
32
32
|
# Internal: Cache Environment#entries
|
33
|
-
alias_method :_entries, :entries
|
34
33
|
def entries(path)
|
35
|
-
@entries[path]
|
34
|
+
@entries[path] ||= super(path)
|
36
35
|
end
|
37
36
|
|
38
37
|
# Internal: Cache Environment#stat
|
39
|
-
alias_method :_stat, :stat
|
40
38
|
def stat(path)
|
41
|
-
@stats[path]
|
39
|
+
@stats[path] ||= super(path)
|
42
40
|
end
|
43
41
|
|
44
42
|
# Internal: Cache Environment#load
|
45
|
-
alias_method :_load, :load
|
46
43
|
def load(uri)
|
47
|
-
@uris[uri]
|
44
|
+
@uris[uri] ||= super(uri)
|
48
45
|
end
|
49
46
|
|
50
47
|
# Internal: Cache Environment#processor_cache_key
|
51
|
-
alias_method :_processor_cache_key, :processor_cache_key
|
52
48
|
def processor_cache_key(str)
|
53
|
-
@processor_cache_keys[str]
|
49
|
+
@processor_cache_keys[str] ||= super(str)
|
54
50
|
end
|
55
51
|
|
56
52
|
# Internal: Cache Environment#resolve_dependency
|
57
|
-
alias_method :_resolve_dependency, :resolve_dependency
|
58
53
|
def resolve_dependency(str)
|
59
|
-
@resolved_dependencies[str]
|
54
|
+
@resolved_dependencies[str] ||= super(str)
|
60
55
|
end
|
61
56
|
|
62
57
|
private
|
@@ -1,4 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/autoload'
|
3
|
+
require 'sprockets/source_map_utils'
|
2
4
|
|
3
5
|
module Sprockets
|
4
6
|
# Processor engine class for the CoffeeScript compiler.
|
@@ -6,10 +8,10 @@ module Sprockets
|
|
6
8
|
#
|
7
9
|
# For more infomation see:
|
8
10
|
#
|
9
|
-
# https://github.com/
|
11
|
+
# https://github.com/rails/ruby-coffee-script
|
10
12
|
#
|
11
13
|
module CoffeeScriptProcessor
|
12
|
-
VERSION = '
|
14
|
+
VERSION = '2'
|
13
15
|
|
14
16
|
def self.cache_key
|
15
17
|
@cache_key ||= "#{name}:#{Autoload::CoffeeScript::Source.version}:#{VERSION}".freeze
|
@@ -17,9 +19,21 @@ module Sprockets
|
|
17
19
|
|
18
20
|
def self.call(input)
|
19
21
|
data = input[:data]
|
20
|
-
|
21
|
-
|
22
|
+
|
23
|
+
js, map = input[:cache].fetch([self.cache_key, data]) do
|
24
|
+
result = Autoload::CoffeeScript.compile(
|
25
|
+
data,
|
26
|
+
sourceMap: "v3",
|
27
|
+
sourceFiles: [File.basename(input[:filename])],
|
28
|
+
generatedFile: input[:filename]
|
29
|
+
)
|
30
|
+
[result['js'], JSON.parse(result['v3SourceMap'])]
|
22
31
|
end
|
32
|
+
|
33
|
+
map = SourceMapUtils.format_source_map(map, input)
|
34
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
35
|
+
|
36
|
+
{ data: js, map: map }
|
23
37
|
end
|
24
38
|
end
|
25
39
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/utils'
|
2
3
|
|
3
4
|
module Sprockets
|
@@ -10,6 +11,24 @@ module Sprockets
|
|
10
11
|
config[:compressors]
|
11
12
|
end
|
12
13
|
|
14
|
+
# Public: Register a new compressor `klass` at `sym` for `mime_type`.
|
15
|
+
#
|
16
|
+
# Registering a processor allows it to be looked up by `sym` later when
|
17
|
+
# assigning a JavaScript or CSS compressor.
|
18
|
+
#
|
19
|
+
# Compressors only operate on JavaScript and CSS. If you want to compress a
|
20
|
+
# different type of asset, use a processor instead.
|
21
|
+
#
|
22
|
+
# Examples
|
23
|
+
#
|
24
|
+
# register_compressor 'text/css', :my_sass, MySassCompressor
|
25
|
+
# css_compressor = :my_sass
|
26
|
+
#
|
27
|
+
# mime_type - String MIME Type (one of: 'test/css' or 'application/javascript').
|
28
|
+
# sym - Symbol registration address.
|
29
|
+
# klass - The compressor class.
|
30
|
+
#
|
31
|
+
# Returns nothing.
|
13
32
|
def register_compressor(mime_type, sym, klass)
|
14
33
|
self.config = hash_reassoc(config, :compressors, mime_type) do |compressors|
|
15
34
|
compressors[sym] = klass
|
@@ -35,7 +54,7 @@ module Sprockets
|
|
35
54
|
if compressor.is_a?(Symbol)
|
36
55
|
@css_compressor = klass = config[:compressors]['text/css'][compressor] || raise(Error, "unknown compressor: #{compressor}")
|
37
56
|
elsif compressor.respond_to?(:compress)
|
38
|
-
klass =
|
57
|
+
klass = proc { |input| compressor.compress(input[:data]) }
|
39
58
|
@css_compressor = :css_compressor
|
40
59
|
else
|
41
60
|
@css_compressor = klass = compressor
|
@@ -62,7 +81,7 @@ module Sprockets
|
|
62
81
|
if compressor.is_a?(Symbol)
|
63
82
|
@js_compressor = klass = config[:compressors]['application/javascript'][compressor] || raise(Error, "unknown compressor: #{compressor}")
|
64
83
|
elsif compressor.respond_to?(:compress)
|
65
|
-
klass =
|
84
|
+
klass = proc { |input| compressor.compress(input[:data]) }
|
66
85
|
@js_compressor = :js_compressor
|
67
86
|
else
|
68
87
|
@js_compressor = klass = compressor
|
@@ -83,12 +102,33 @@ module Sprockets
|
|
83
102
|
|
84
103
|
# Public: Enable or disable the creation of Gzip files.
|
85
104
|
#
|
86
|
-
#
|
105
|
+
# To disable gzip generation set to a falsey value:
|
87
106
|
#
|
88
107
|
# environment.gzip = false
|
89
108
|
#
|
109
|
+
# To enable set to a truthy value. By default zlib wil
|
110
|
+
# be used to gzip assets. If you have the Zopfli gem
|
111
|
+
# installed you can specify the zopfli algorithm to be used
|
112
|
+
# instead:
|
113
|
+
#
|
114
|
+
# environment.gzip = :zopfli
|
115
|
+
#
|
90
116
|
def gzip=(gzip)
|
91
117
|
self.config = config.merge(gzip_enabled: gzip).freeze
|
118
|
+
|
119
|
+
case gzip
|
120
|
+
when false, nil
|
121
|
+
self.unregister_exporter Exporters::ZlibExporter
|
122
|
+
self.unregister_exporter Exporters::ZopfliExporter
|
123
|
+
when :zopfli
|
124
|
+
self.unregister_exporter Exporters::ZlibExporter
|
125
|
+
self.register_exporter '*/*', Exporters::ZopfliExporter
|
126
|
+
else
|
127
|
+
self.unregister_exporter Exporters::ZopfliExporter
|
128
|
+
self.register_exporter '*/*', Exporters::ZlibExporter
|
129
|
+
end
|
130
|
+
|
131
|
+
gzip
|
92
132
|
end
|
93
133
|
end
|
94
134
|
end
|
@@ -1,27 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/compressing'
|
2
3
|
require 'sprockets/dependencies'
|
3
|
-
require 'sprockets/engines'
|
4
4
|
require 'sprockets/mime'
|
5
5
|
require 'sprockets/paths'
|
6
6
|
require 'sprockets/processing'
|
7
|
+
require 'sprockets/exporting'
|
7
8
|
require 'sprockets/transformers'
|
8
9
|
require 'sprockets/utils'
|
9
10
|
|
10
11
|
module Sprockets
|
11
12
|
module Configuration
|
12
|
-
include Paths, Mime,
|
13
|
+
include Paths, Mime, Transformers, Processing, Exporting, Compressing, Dependencies, Utils
|
13
14
|
|
14
15
|
def initialize_configuration(parent)
|
15
16
|
@config = parent.config
|
16
|
-
@computed_config = parent.computed_config
|
17
17
|
@logger = parent.logger
|
18
18
|
@context_class = Class.new(parent.context_class)
|
19
19
|
end
|
20
20
|
|
21
21
|
attr_reader :config
|
22
22
|
|
23
|
-
attr_accessor :computed_config
|
24
|
-
|
25
23
|
def config=(config)
|
26
24
|
raise TypeError, "can't assign mutable config" unless config.frozen?
|
27
25
|
@config = config
|
@@ -69,8 +67,6 @@ module Sprockets
|
|
69
67
|
self.config = config.merge(digest_class: klass).freeze
|
70
68
|
end
|
71
69
|
|
72
|
-
# Deprecated: Get `Context` class.
|
73
|
-
#
|
74
70
|
# This class maybe mutated and mixed in with custom helpers.
|
75
71
|
#
|
76
72
|
# environment.context_class.instance_eval do
|
data/lib/sprockets/context.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
require 'rack/utils'
|
3
3
|
require 'set'
|
4
4
|
require 'sprockets/errors'
|
5
5
|
|
6
6
|
module Sprockets
|
7
|
-
# Deprecated: `Context` provides helper methods to all processors.
|
8
7
|
# They are typically accessed by ERB templates. You can mix in custom helpers
|
9
8
|
# by injecting them into `Environment#context_class`. Do not mix them into
|
10
9
|
# `Context` directly.
|
@@ -19,10 +18,25 @@ module Sprockets
|
|
19
18
|
# The `Context` also collects dependencies declared by
|
20
19
|
# assets. See `DirectiveProcessor` for an example of this.
|
21
20
|
class Context
|
22
|
-
|
21
|
+
# Internal: Proxy for ENV that keeps track of the environment variables used
|
22
|
+
class ENVProxy < SimpleDelegator
|
23
|
+
def initialize(context)
|
24
|
+
@context = context
|
25
|
+
super(ENV)
|
26
|
+
end
|
23
27
|
|
24
|
-
|
25
|
-
|
28
|
+
def [](key)
|
29
|
+
@context.depend_on_env(key)
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch(key, *)
|
34
|
+
@context.depend_on_env(key)
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :environment, :filename
|
26
40
|
|
27
41
|
def initialize(input)
|
28
42
|
@environment = input[:environment]
|
@@ -31,7 +45,6 @@ module Sprockets
|
|
31
45
|
@logical_path = input[:name]
|
32
46
|
@filename = input[:filename]
|
33
47
|
@dirname = File.dirname(@filename)
|
34
|
-
@pathname = Pathname.new(@filename)
|
35
48
|
@content_type = input[:content_type]
|
36
49
|
|
37
50
|
@required = Set.new(@metadata[:required])
|
@@ -47,6 +60,10 @@ module Sprockets
|
|
47
60
|
dependencies: @dependencies }
|
48
61
|
end
|
49
62
|
|
63
|
+
def env_proxy
|
64
|
+
ENVProxy.new(self)
|
65
|
+
end
|
66
|
+
|
50
67
|
# Returns the environment path that contains the file.
|
51
68
|
#
|
52
69
|
# If `app/javascripts` and `app/stylesheets` are in your path, and
|
@@ -79,13 +96,13 @@ module Sprockets
|
|
79
96
|
# resolve("./bar.js")
|
80
97
|
# # => "file:///path/to/app/javascripts/bar.js?type=application/javascript"
|
81
98
|
#
|
82
|
-
# path
|
83
|
-
#
|
84
|
-
# accept - String content accept type
|
99
|
+
# path - String logical or absolute path
|
100
|
+
# accept - String content accept type
|
85
101
|
#
|
86
102
|
# Returns an Asset URI String.
|
87
|
-
def resolve(path,
|
88
|
-
|
103
|
+
def resolve(path, **kargs)
|
104
|
+
kargs[:base_path] = @dirname
|
105
|
+
uri, deps = environment.resolve!(path, **kargs)
|
89
106
|
@dependencies.merge(deps)
|
90
107
|
uri
|
91
108
|
end
|
@@ -105,15 +122,13 @@ module Sprockets
|
|
105
122
|
# including it.
|
106
123
|
#
|
107
124
|
# This is used for caching purposes. Any changes made to
|
108
|
-
# the dependency file
|
125
|
+
# the dependency file will invalidate the cache of the
|
109
126
|
# source file.
|
110
127
|
def depend_on(path)
|
111
|
-
path = path.to_s if path.is_a?(Pathname)
|
112
|
-
|
113
128
|
if environment.absolute_path?(path) && environment.stat(path)
|
114
129
|
@dependencies << environment.build_file_digest_uri(path)
|
115
130
|
else
|
116
|
-
resolve(path
|
131
|
+
resolve(path)
|
117
132
|
end
|
118
133
|
nil
|
119
134
|
end
|
@@ -123,10 +138,19 @@ module Sprockets
|
|
123
138
|
#
|
124
139
|
# This is used for caching purposes. Any changes that would
|
125
140
|
# invalidate the dependency asset will invalidate the source
|
126
|
-
# file. Unlike `depend_on`, this will
|
141
|
+
# file. Unlike `depend_on`, this will recursively include
|
127
142
|
# the target asset's dependencies.
|
128
143
|
def depend_on_asset(path)
|
129
|
-
load(resolve(path
|
144
|
+
load(resolve(path))
|
145
|
+
end
|
146
|
+
|
147
|
+
# `depend_on_env` allows you to state a dependency on an environment
|
148
|
+
# variable.
|
149
|
+
#
|
150
|
+
# This is used for caching purposes. Any changes in the value of the
|
151
|
+
# environment variable will invalidate the cache of the source file.
|
152
|
+
def depend_on_env(key)
|
153
|
+
@dependencies << "env:#{key}"
|
130
154
|
end
|
131
155
|
|
132
156
|
# `require_asset` declares `path` as a dependency of the file. The
|
@@ -139,7 +163,7 @@ module Sprockets
|
|
139
163
|
# <%= require_asset "#{framework}.js" %>
|
140
164
|
#
|
141
165
|
def require_asset(path)
|
142
|
-
@required << resolve(path, accept: @content_type, pipeline: :self
|
166
|
+
@required << resolve(path, accept: @content_type, pipeline: :self)
|
143
167
|
nil
|
144
168
|
end
|
145
169
|
|
@@ -147,7 +171,7 @@ module Sprockets
|
|
147
171
|
# `path` must be an asset which may or may not already be included
|
148
172
|
# in the bundle.
|
149
173
|
def stub_asset(path)
|
150
|
-
@stubbed << resolve(path, accept: @content_type, pipeline: :self
|
174
|
+
@stubbed << resolve(path, accept: @content_type, pipeline: :self)
|
151
175
|
nil
|
152
176
|
end
|
153
177
|
|
@@ -162,9 +186,10 @@ module Sprockets
|
|
162
186
|
asset
|
163
187
|
end
|
164
188
|
|
165
|
-
# Returns a
|
166
|
-
#
|
167
|
-
#
|
189
|
+
# Returns a `data:` URI with the contents of the asset at the specified
|
190
|
+
# path, and marks that path as a dependency of the current file.
|
191
|
+
#
|
192
|
+
# Uses URI encoding for SVG files, base64 encoding for all the other files.
|
168
193
|
#
|
169
194
|
# Use `asset_data_uri` from ERB with CSS or JavaScript assets:
|
170
195
|
#
|
@@ -174,8 +199,11 @@ module Sprockets
|
|
174
199
|
#
|
175
200
|
def asset_data_uri(path)
|
176
201
|
asset = depend_on_asset(path)
|
177
|
-
|
178
|
-
|
202
|
+
if asset.content_type == 'image/svg+xml'
|
203
|
+
svg_asset_data_uri(asset)
|
204
|
+
else
|
205
|
+
base64_asset_data_uri(asset)
|
206
|
+
end
|
179
207
|
end
|
180
208
|
|
181
209
|
# Expands logical path to full url to asset.
|
@@ -227,5 +255,50 @@ Extend your environment context with a custom method.
|
|
227
255
|
def stylesheet_path(path)
|
228
256
|
asset_path(path, type: :stylesheet)
|
229
257
|
end
|
258
|
+
|
259
|
+
protected
|
260
|
+
|
261
|
+
# Returns a URI-encoded data URI (always "-quoted).
|
262
|
+
def svg_asset_data_uri(asset)
|
263
|
+
svg = asset.source.dup
|
264
|
+
optimize_svg_for_uri_escaping!(svg)
|
265
|
+
data = Rack::Utils.escape(svg)
|
266
|
+
optimize_quoted_uri_escapes!(data)
|
267
|
+
"\"data:#{asset.content_type};charset=utf-8,#{data}\""
|
268
|
+
end
|
269
|
+
|
270
|
+
# Returns a Base64-encoded data URI.
|
271
|
+
def base64_asset_data_uri(asset)
|
272
|
+
data = Rack::Utils.escape(EncodingUtils.base64(asset.source))
|
273
|
+
"data:#{asset.content_type};base64,#{data}"
|
274
|
+
end
|
275
|
+
|
276
|
+
# Optimizes an SVG for being URI-escaped.
|
277
|
+
#
|
278
|
+
# This method only performs these basic but crucial optimizations:
|
279
|
+
# * Replaces " with ', because ' does not need escaping.
|
280
|
+
# * Removes comments, meta, doctype, and newlines.
|
281
|
+
# * Collapses whitespace.
|
282
|
+
def optimize_svg_for_uri_escaping!(svg)
|
283
|
+
# Remove comments, xml meta, and doctype
|
284
|
+
svg.gsub!(/<!--.*?-->|<\?.*?\?>|<!.*?>/m, '')
|
285
|
+
# Replace consecutive whitespace and newlines with a space
|
286
|
+
svg.gsub!(/\s+/, ' ')
|
287
|
+
# Collapse inter-tag whitespace
|
288
|
+
svg.gsub!('> <', '><')
|
289
|
+
# Replace " with '
|
290
|
+
svg.gsub!(/([\w:])="(.*?)"/, "\\1='\\2'")
|
291
|
+
svg.strip!
|
292
|
+
end
|
293
|
+
|
294
|
+
# Un-escapes characters in the given URI-escaped string that do not need
|
295
|
+
# escaping in "-quoted data URIs.
|
296
|
+
def optimize_quoted_uri_escapes!(escaped)
|
297
|
+
escaped.gsub!('%3D', '=')
|
298
|
+
escaped.gsub!('%3A', ':')
|
299
|
+
escaped.gsub!('%2F', '/')
|
300
|
+
escaped.gsub!('%27', "'")
|
301
|
+
escaped.tr!('+', ' ')
|
302
|
+
end
|
230
303
|
end
|
231
304
|
end
|