propshaft 0.6.4 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7bee1e0c2fcf39062df053618528b93dd5977bd8968fea03a67d31b7196f04f9
4
- data.tar.gz: ad9c5f3b7bc878a359931d2c1edc2a2ecb98004b8cfba38dd226acd0a19e43ff
3
+ metadata.gz: 56736cd8d13ffa9511e5cd47d39e3d3849f66484f0ba489686b75aa5a5c57936
4
+ data.tar.gz: 7adfc7103ca6694027ad577b7cd14bf6972227f02bdf0bd0659d508371afdfad
5
5
  SHA512:
6
- metadata.gz: 41a54360ed2d9424f1c190af2606c5d2bc88a2d01d61a1396ed60fc64ba1531e815cc259ac41904fe3a49053d057ee2f838be0c8763b37a1ebbe79067f52301f
7
- data.tar.gz: be6381394ff2c2dfa9bf0ca23d2023b196492d83012970091eca5ce03822ee127fa40103382dd85d6093ae1edc5b91545a59be21beb0a9736fa3037a322d5678
6
+ metadata.gz: 67c4c686072bc75784519f8043225b9bb462a19a74a2617ec1628a25cb701bad1aabe05a873126038718b6bd18ba9d51f47cdd0daa89418186996832a0f5707c
7
+ data.tar.gz: f476c9aff5b7975df5815095bdf1917eeb748ee1c9ebab0f058aa670863597a6d4794c77b3bd379eafb355c83b9fa8008b366796ad52188d7804410f93c8ec33
data/README.md CHANGED
@@ -27,6 +27,16 @@ These assets can be referenced through their logical path using the normal helpe
27
27
 
28
28
  If you need to put multiple files that refer to each other through Propshaft, like a JavaScript file and its source map, you have to digest these files in advance to retain stable file names. Propshaft looks for the specific pattern of `-[digest].digested.js` as the postfix to any asset file as an indication that the file has already been digested.
29
29
 
30
+ ## Improving performance in development
31
+
32
+ Before every request Propshaft checks if any asset was updated to decide if a cache sweep is needed. This verification is done using the application's configured file watcher which, by default, is `ActiveSupport::FileUpdateChecker`.
33
+
34
+ If you have a lot of assets in your project, you can improve performance by adding the `listen` gem to the development group in your Gemfile, and this line to the `development.rb` environment file:
35
+
36
+ ```ruby
37
+ config.file_watcher = ActiveSupport::EventedFileUpdateChecker
38
+ ```
39
+
30
40
 
31
41
  ## Migrating from Sprockets
32
42
 
@@ -39,7 +49,7 @@ But for greenfield apps using the default import-map approach, Propshaft can als
39
49
 
40
50
  ## Will Propshaft replace Sprockets as the Rails default?
41
51
 
42
- Most likely, but Sprockets need to be supported as well for a long time to come. Plenty of apps and gems were built on Sprocket features, and they won't be migrating soon. Still working out the compatibility story. This is very much alpha software at the moment.
52
+ Most likely, but Sprockets need to be supported as well for a long time to come. Plenty of apps and gems were built on Sprocket features, and they won't be migrating soon. Still working out the compatibility story. This is very much beta software at the moment.
43
53
 
44
54
 
45
55
  ## License
@@ -4,8 +4,8 @@ require "propshaft/resolver/static"
4
4
  require "propshaft/server"
5
5
  require "propshaft/processor"
6
6
  require "propshaft/compilers"
7
- require "propshaft/compilers/css_asset_urls"
8
- require "propshaft/compilers/source_mapping_urls"
7
+ require "propshaft/compiler/css_asset_urls"
8
+ require "propshaft/compiler/source_mapping_urls"
9
9
 
10
10
  class Propshaft::Assembly
11
11
  attr_reader :config
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Propshaft::Compilers::CssAssetUrls
4
- attr_reader :assembly
3
+ require "propshaft/compiler"
5
4
 
6
- ASSET_URL_PATTERN = /url\(\s*["']?(?!(?:\#|data|http))([^"'\s?#)]+)([#?][^"']+)?\s*["']?\)/
7
-
8
- def initialize(assembly)
9
- @assembly = assembly
10
- end
5
+ class Propshaft::Compiler::CssAssetUrls < Propshaft::Compiler
6
+ ASSET_URL_PATTERN = /url\(\s*["']?(?!(?:\#|%23|data|http|\/\/))([^"'\s?#)]+)([#?][^"')]+)?\s*["']?\)/
11
7
 
12
8
  def compile(logical_path, input)
13
- input.gsub(ASSET_URL_PATTERN) { asset_url resolve_path(logical_path.dirname, $1), logical_path, $1 }
9
+ input.gsub(ASSET_URL_PATTERN) { asset_url resolve_path(logical_path.dirname, $1), logical_path, $2, $1 }
14
10
  end
15
11
 
16
12
  private
@@ -24,9 +20,9 @@ class Propshaft::Compilers::CssAssetUrls
24
20
  end
25
21
  end
26
22
 
27
- def asset_url(resolved_path, logical_path, pattern)
23
+ def asset_url(resolved_path, logical_path, fingerprint, pattern)
28
24
  if asset = assembly.load_path.find(resolved_path)
29
- %[url("#{assembly.config.prefix}/#{asset.digested_path}")]
25
+ %[url("#{url_prefix}/#{asset.digested_path}#{fingerprint}")]
30
26
  else
31
27
  Propshaft.logger.warn "Unable to resolve '#{pattern}' for missing asset '#{resolved_path}' in #{logical_path}"
32
28
  %[url("#{pattern}")]
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Propshaft::Compilers::SourceMappingUrls
4
- attr_reader :assembly
3
+ require "propshaft/compiler"
5
4
 
6
- SOURCE_MAPPING_PATTERN = %r{^(//|/\*)# sourceMappingURL=(.+\.map)}
7
-
8
- def initialize(assembly)
9
- @assembly = assembly
10
- end
5
+ class Propshaft::Compiler::SourceMappingUrls < Propshaft::Compiler
6
+ SOURCE_MAPPING_PATTERN = %r{(//|/\*)# sourceMappingURL=(.+\.map)(\s*?\*\/)?\s*?\Z}
11
7
 
12
8
  def compile(logical_path, input)
13
- input.gsub(SOURCE_MAPPING_PATTERN) { source_mapping_url(asset_path($2, logical_path), $1) }
9
+ input.gsub(SOURCE_MAPPING_PATTERN) { source_mapping_url(asset_path($2, logical_path), $1, $3) }
14
10
  end
15
11
 
16
12
  private
@@ -22,12 +18,12 @@ class Propshaft::Compilers::SourceMappingUrls
22
18
  end
23
19
  end
24
20
 
25
- def source_mapping_url(resolved_path, comment)
21
+ def source_mapping_url(resolved_path, comment_start, comment_end)
26
22
  if asset = assembly.load_path.find(resolved_path)
27
- "#{comment}# sourceMappingURL=#{assembly.config.prefix}/#{asset.digested_path}"
23
+ "#{comment_start}# sourceMappingURL=#{url_prefix}/#{asset.digested_path}#{comment_end}"
28
24
  else
29
25
  Propshaft.logger.warn "Removed sourceMappingURL comment for missing asset '#{resolved_path}' from #{resolved_path}"
30
- nil
26
+ "#{comment_start}#{comment_end}"
31
27
  end
32
28
  end
33
29
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Base compiler from which other compilers can inherit
4
+ class Propshaft::Compiler
5
+ attr_reader :assembly
6
+
7
+ def initialize(assembly)
8
+ @assembly = assembly
9
+ end
10
+
11
+ # Override this in a specific compiler
12
+ def compile(logical_path, input)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ private
17
+ def url_prefix
18
+ @url_prefix ||= File.join(assembly.config.relative_url_root.to_s, assembly.config.prefix.to_s).chomp("/")
19
+ end
20
+ end
@@ -3,5 +3,23 @@ module Propshaft
3
3
  def compute_asset_path(path, options = {})
4
4
  Rails.application.assets.resolver.resolve(path) || raise(MissingAssetError.new(path))
5
5
  end
6
+
7
+ # Add an option to call `stylesheet_link_tag` with `:all` to include every css file found on the load path.
8
+ def stylesheet_link_tag(*sources)
9
+ if sources.first == :all
10
+ super *all_stylesheets_paths
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ # Returns a sorted and unique array of logical paths for all stylesheets in the load path.
17
+ def all_stylesheets_paths
18
+ Rails.application.assets.load_path
19
+ .assets(content_types: [ Mime::EXTENSION_LOOKUP["css"] ])
20
+ .collect { |css| css.logical_path.to_s }
21
+ .sort
22
+ .uniq
23
+ end
6
24
  end
7
25
  end
@@ -28,7 +28,7 @@ class Propshaft::LoadPath
28
28
  end
29
29
  end
30
30
 
31
- # Returns a ActiveSupport::FileUpdateChecker object configured to clear the cache of the load_path
31
+ # Returns a file watcher object configured to clear the cache of the load_path
32
32
  # when the directories passed during its initialization have changes. This is used in development
33
33
  # and test to ensure the map caches are reset when javascript files are changed.
34
34
  def cache_sweeper
@@ -0,0 +1,14 @@
1
+ class Propshaft::QuietAssets
2
+ def initialize(app)
3
+ @app = app
4
+ @assets_regex = %r(\A/{0,2}#{::Rails.application.config.assets.prefix})
5
+ end
6
+
7
+ def call(env)
8
+ if env['PATH_INFO'] =~ @assets_regex
9
+ ::Rails.logger.silence { @app.call(env) }
10
+ else
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,6 @@
1
1
  require "rails"
2
2
  require "active_support/ordered_options"
3
+ require "propshaft/quiet_assets"
3
4
 
4
5
  module Propshaft
5
6
  class Railtie < ::Rails::Railtie
@@ -8,13 +9,15 @@ module Propshaft
8
9
  config.assets.excluded_paths = []
9
10
  config.assets.version = "1"
10
11
  config.assets.prefix = "/assets"
12
+ config.assets.quiet = false
11
13
  config.assets.compilers = [
12
- [ "text/css", Propshaft::Compilers::CssAssetUrls ],
13
- [ "text/css", Propshaft::Compilers::SourceMappingUrls ],
14
- [ "text/javascript", Propshaft::Compilers::SourceMappingUrls ]
14
+ [ "text/css", Propshaft::Compiler::CssAssetUrls ],
15
+ [ "text/css", Propshaft::Compiler::SourceMappingUrls ],
16
+ [ "text/javascript", Propshaft::Compiler::SourceMappingUrls ]
15
17
  ]
16
18
  config.assets.sweep_cache = Rails.env.development?
17
19
  config.assets.server = Rails.env.development? || Rails.env.test?
20
+ config.assets.relative_url_root = nil
18
21
 
19
22
  # Register propshaft initializer to copy the assets path in all the Rails Engines.
20
23
  # This makes possible for us to keep all `assets` config in this Railtie, but still
@@ -28,6 +31,7 @@ module Propshaft
28
31
  end
29
32
 
30
33
  config.after_initialize do |app|
34
+ config.assets.relative_url_root ||= app.config.relative_url_root
31
35
  config.assets.output_path ||=
32
36
  Pathname.new(File.join(app.config.paths["public"].first, app.config.assets.prefix))
33
37
 
@@ -54,6 +58,12 @@ module Propshaft
54
58
  Propshaft.logger = config.assets.logger || Rails.logger
55
59
  end
56
60
 
61
+ initializer :quiet_assets do |app|
62
+ if app.config.assets.quiet
63
+ app.middleware.insert_before ::Rails::Rack::Logger, Propshaft::QuietAssets
64
+ end
65
+ end
66
+
57
67
  rake_tasks do
58
68
  load "propshaft/railties/assets.rake"
59
69
  end
@@ -61,9 +71,7 @@ module Propshaft
61
71
  # Compatibility shiming (need to provide log warnings when used)
62
72
  config.assets.precompile = []
63
73
  config.assets.debug = nil
64
- config.assets.quiet = nil
65
74
  config.assets.compile = nil
66
- config.assets.version = nil
67
75
  config.assets.css_compressor = nil
68
76
  config.assets.js_compressor = nil
69
77
  end
@@ -2,6 +2,10 @@ namespace :assets do
2
2
  desc "Compile all the assets from config.assets.paths"
3
3
  task precompile: :environment do
4
4
  Rails.application.assets.processor.process
5
+ if Rails.env.development?
6
+ puts "Warning: You are precompiling assets in development. Rails will not " \
7
+ "serve any changed assets until you delete public#{Rails.application.config.assets.prefix}/.manifest.json"
8
+ end
5
9
  end
6
10
 
7
11
  desc "Remove config.assets.output_path"
@@ -20,7 +20,7 @@ module Propshaft::Resolver
20
20
 
21
21
  private
22
22
  def parsed_manifest
23
- @parsed_manifest ||= JSON.parse(manifest_path.read)
23
+ @parsed_manifest ||= JSON.parse(manifest_path.read, symbolize_names: false)
24
24
  end
25
25
  end
26
26
  end
@@ -11,19 +11,19 @@ class Propshaft::Server
11
11
  if (asset = @assembly.load_path.find(path)) && asset.fresh?(digest)
12
12
  compiled_content = @assembly.compilers.compile(asset)
13
13
 
14
- [
15
- 200,
14
+ [
15
+ 200,
16
16
  {
17
- "Content-Length" => compiled_content.length.to_s,
18
- "Content-Type" => asset.content_type.to_s,
19
- "Accept-Encoding" => "Vary",
20
- "ETag" => asset.digest,
21
- "Cache-Control" => "public, max-age=31536000, immutable"
17
+ Rack::CONTENT_LENGTH => compiled_content.length.to_s,
18
+ Rack::CONTENT_TYPE => asset.content_type.to_s,
19
+ VARY => "Accept-Encoding",
20
+ Rack::ETAG => asset.digest,
21
+ Rack::CACHE_CONTROL => "public, max-age=31536000, immutable"
22
22
  },
23
23
  [ compiled_content ]
24
24
  ]
25
25
  else
26
- [ 404, { "Content-Type" => "text/plain", "Content-Length" => "9" }, [ "Not found" ] ]
26
+ [ 404, { Rack::CONTENT_TYPE => "text/plain", Rack::CONTENT_LENGTH => "9" }, [ "Not found" ] ]
27
27
  end
28
28
  end
29
29
 
@@ -39,4 +39,10 @@ class Propshaft::Server
39
39
 
40
40
  [ path, digest ]
41
41
  end
42
+
43
+ if Gem::Version.new(Rack::RELEASE) < Gem::Version.new("3")
44
+ VARY = "Vary"
45
+ else
46
+ VARY = "vary"
47
+ end
42
48
  end
@@ -1,3 +1,3 @@
1
1
  module Propshaft
2
- VERSION = "0.6.4"
2
+ VERSION = "0.8.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: propshaft
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-22 00:00:00.000000000 Z
11
+ date: 2023-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -78,14 +78,16 @@ files:
78
78
  - lib/propshaft.rb
79
79
  - lib/propshaft/assembly.rb
80
80
  - lib/propshaft/asset.rb
81
+ - lib/propshaft/compiler.rb
82
+ - lib/propshaft/compiler/css_asset_urls.rb
83
+ - lib/propshaft/compiler/source_mapping_urls.rb
81
84
  - lib/propshaft/compilers.rb
82
- - lib/propshaft/compilers/css_asset_urls.rb
83
- - lib/propshaft/compilers/source_mapping_urls.rb
84
85
  - lib/propshaft/errors.rb
85
86
  - lib/propshaft/helper.rb
86
87
  - lib/propshaft/load_path.rb
87
88
  - lib/propshaft/output_path.rb
88
89
  - lib/propshaft/processor.rb
90
+ - lib/propshaft/quiet_assets.rb
89
91
  - lib/propshaft/railtie.rb
90
92
  - lib/propshaft/railties/assets.rake
91
93
  - lib/propshaft/resolver/dynamic.rb
@@ -112,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
114
  - !ruby/object:Gem::Version
113
115
  version: '0'
114
116
  requirements: []
115
- rubygems_version: 3.2.32
117
+ rubygems_version: 3.4.20
116
118
  signing_key:
117
119
  specification_version: 4
118
120
  summary: Deliver assets for Rails.