propshaft 0.5.0 → 0.6.3

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: ed27e836fd19bb9d9293ca1fad143a3aa6454c40e671891cd47cfd279524d16f
4
- data.tar.gz: fa7b4f0f3dd48634b0d9f5ba012bc1d90d43445aee137846c6a9e66c96754e6a
3
+ metadata.gz: 2e186c6a8b298be03fa1f414751bf99e425614701c2283eafeafc49d14a10dd9
4
+ data.tar.gz: d447859d4a45ae4d7f62b54d71a9ce5c4d15d2151c98a3369cd33229587a1441
5
5
  SHA512:
6
- metadata.gz: daea545ac84a7c13ddb0198544f3058fbde3ccf9dfa42302f705613f4ec06c8c9962e2ffebe8276a9cc97912122ee8b8591c246f0ff09d6a91124c49b142bd09
7
- data.tar.gz: '09355d57890f7b5ac3372f9d76dd08784f2e2b1de7b83f099ef8c9f3eebd73d53a2247e58df0e7ca0c59247bbb1478d4e6ec68e260d599e8002c2ad367779439'
6
+ metadata.gz: 337241f55febf946b0b4e508012d3f8737882c8fc92665f84a6d407ec52a93acd9c11840f456897f8100294665ce4dac5ae6b70c79ca08b25479c6cf4689877e
7
+ data.tar.gz: e436e82a80404f84eb27e32e493d38bda181e80b08b8c0ca788a69354bd97eef51b2c73ddfff62ebeb6407ecf553b15a290bf5680d7e2fcd7150ede657675dcb
data/README.md CHANGED
@@ -7,21 +7,20 @@ So that's what Propshaft doesn't do. Here's what it does provide:
7
7
  1. **Configurable load path**: You can register directories from multiple places in your app and gems, and reference assets from all of these paths as though they were one.
8
8
  1. **Digest stamping**: All assets in the load path will be copied (or compiled) in a precompilation step for production that also stamps all of them with a digest hash, so you can use long-expiry cache headers for better performance. The digested assets can be referred to through their logical path because the processing leaves a manifest file that provides a way to translate.
9
9
  1. **Development server**: There's no need to precompile the assets in development. You can refer to them via the same asset_path helpers and they'll be served by a development server.
10
- 1. **Basic compilers**: Propshaft was explicitly not designed to provide full transpiler capabilities. You can get that better elsewhere. But it does offer a simple input->output compiler setup that by default is used to translate `asset-path` function calls in CSS to `url(digested-asset)` instead.
10
+ 1. **Basic compilers**: Propshaft was explicitly not designed to provide full transpiler capabilities. You can get that better elsewhere. But it does offer a simple input->output compiler setup that by default is used to translate `url(asset)` function calls in CSS to `url(digested-asset)` instead and source mapping comments likewise.
11
11
 
12
12
 
13
13
  ## Installation
14
14
 
15
- With Rails 7+, you can start a new application with propshaft using `rails new myapp -a propshaft`.
16
-
15
+ With Rails 7+, you can start a new application with propshaft using `rails new myapp -a propshaft`. For existing applications, check the [upgrade guide](https://github.com/rails/propshaft/blob/main/UPGRADING.md) which contains step-by-step instructions.
17
16
 
18
17
  ## Usage
19
18
 
20
- Propshaft makes all the assets from all the paths it's been configured with through `config.assets.paths` available for serving and will copy all of them into `public/assets` when precompiling. This is unlike Sprockets, which did not copy over assets that hadn't been explicitly included in one of the bundled assets.
19
+ Propshaft makes all the assets from all the paths it's been configured with through `config.assets.paths` available for serving and will copy all of them into `public/assets` when precompiling. This is unlike Sprockets, which did not copy over assets that hadn't been explicitly included in one of the bundled assets.
21
20
 
22
- These assets can be referenced through their logical path using the normal helpers like `asset_path`, `image_tag`, `javascript_include_tag`, and all the other asset helper tags. These logical references are automatically converted into digest-aware paths in production when `assets:precompile` has been run (through a JSON mapping file found in `public/assets/.manifest.json`).
21
+ You can however exempt directories that have been added through the `config.assets.excluded_paths`. This is useful if you're for example using `app/assets/stylesheets` exclusively as a set of inputs to a compiler like Dart Sass for Rails, and you don't want these input files to be part of the load path. (Remember you need to add full paths, like `Rails.root.join("app/assets/stylesheets")`).
23
22
 
24
- Additionally, Propshaft ships with a CSS function called `asset-path("image.svg")` that'll be compiled into `url("/assets/image-f2e1ec14d6856e1958083094170ca6119c529a73.svg")` when doing `assets:precompile`. This function is applied to all `.css` files.
23
+ These assets can be referenced through their logical path using the normal helpers like `asset_path`, `image_tag`, `javascript_include_tag`, and all the other asset helper tags. These logical references are automatically converted into digest-aware paths in production when `assets:precompile` has been run (through a JSON mapping file found in `public/assets/.manifest.json`).
25
24
 
26
25
 
27
26
  ## Bypassing the digest step
@@ -15,7 +15,7 @@ class Propshaft::Assembly
15
15
  end
16
16
 
17
17
  def load_path
18
- @load_path ||= Propshaft::LoadPath.new(config.paths)
18
+ @load_path ||= Propshaft::LoadPath.new(config.paths, version: config.version)
19
19
  end
20
20
 
21
21
  def resolver
@@ -47,8 +47,8 @@ class Propshaft::Assembly
47
47
  def reveal(path_type = :logical_path)
48
48
  path_type = path_type.presence_in(%i[ logical_path path ]) || raise(ArgumentError, "Unknown path_type: #{path_type}")
49
49
 
50
- load_path.assets.each do |asset|
51
- Propshaft.logger.info asset.send(path_type)
50
+ load_path.assets.collect do |asset|
51
+ asset.send(path_type)
52
52
  end
53
53
  end
54
54
 
@@ -2,10 +2,10 @@ require "digest/sha1"
2
2
  require "action_dispatch/http/mime_type"
3
3
 
4
4
  class Propshaft::Asset
5
- attr_reader :path, :logical_path
5
+ attr_reader :path, :logical_path, :version
6
6
 
7
- def initialize(path, logical_path:)
8
- @path, @logical_path = path, Pathname.new(logical_path)
7
+ def initialize(path, logical_path:, version: nil)
8
+ @path, @logical_path, @version = path, Pathname.new(logical_path), version
9
9
  end
10
10
 
11
11
  def content
@@ -21,7 +21,7 @@ class Propshaft::Asset
21
21
  end
22
22
 
23
23
  def digest
24
- @digest ||= Digest::SHA1.hexdigest(content)
24
+ @digest ||= Digest::SHA1.hexdigest("#{content}#{version}")
25
25
  end
26
26
 
27
27
  def digested_path
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
- require "propshaft/errors"
3
2
 
4
3
  class Propshaft::Compilers::CssAssetUrls
5
4
  attr_reader :assembly
6
5
 
7
- ASSET_URL_PATTERN = /url\(\s*["']?(?!(?:\#|data|http))([^"'\s)]+)\s*["']?\)/
6
+ ASSET_URL_PATTERN = /url\(\s*["']?(?!(?:\#|data|http))([^"'\s?#)]+)([#?][^"']+)?\s*["']?\)/
8
7
 
9
8
  def initialize(assembly)
10
9
  @assembly = assembly
@@ -1,5 +1,7 @@
1
- module Propshaft::Helper
2
- def compute_asset_path(path, options = {})
3
- Rails.application.assets.resolver.resolve(path)
1
+ module Propshaft
2
+ module Helper
3
+ def compute_asset_path(path, options = {})
4
+ Rails.application.assets.resolver.resolve(path) || raise(MissingAssetError.new(path))
5
+ end
4
6
  end
5
7
  end
@@ -1,10 +1,11 @@
1
1
  require "propshaft/asset"
2
2
 
3
3
  class Propshaft::LoadPath
4
- attr_reader :paths
4
+ attr_reader :paths, :version
5
5
 
6
- def initialize(paths = [])
7
- @paths = Array(paths).collect { |path| Pathname.new(path) }
6
+ def initialize(paths = [], version: nil)
7
+ @paths = dedup(paths)
8
+ @version = version
8
9
  end
9
10
 
10
11
  def find(asset_name)
@@ -45,9 +46,9 @@ class Propshaft::LoadPath
45
46
  def assets_by_path
46
47
  @cached_assets_by_path ||= Hash.new.tap do |mapped|
47
48
  paths.each do |path|
48
- all_files_from_tree(path).each do |file|
49
+ without_dotfiles(all_files_from_tree(path)).each do |file|
49
50
  logical_path = file.relative_path_from(path)
50
- mapped[logical_path.to_s] ||= Propshaft::Asset.new(file, logical_path: logical_path)
51
+ mapped[logical_path.to_s] ||= Propshaft::Asset.new(file, logical_path: logical_path, version: version)
51
52
  end if path.exist?
52
53
  end
53
54
  end
@@ -57,7 +58,19 @@ class Propshaft::LoadPath
57
58
  path.children.flat_map { |child| child.directory? ? all_files_from_tree(child) : child }
58
59
  end
59
60
 
61
+ def without_dotfiles(files)
62
+ files.reject { |file| file.basename.to_s.starts_with?(".") }
63
+ end
64
+
60
65
  def clear_cache
61
66
  @cached_assets_by_path = nil
62
67
  end
68
+
69
+ def dedup(paths)
70
+ [].tap do |deduped|
71
+ Array(paths).map(&:to_s).sort.each do |path|
72
+ deduped << Pathname.new(path) if deduped.blank? || !path.start_with?(deduped.last.to_s)
73
+ end
74
+ end
75
+ end
63
76
  end
@@ -4,9 +4,11 @@ require "active_support/ordered_options"
4
4
  module Propshaft
5
5
  class Railtie < ::Rails::Railtie
6
6
  config.assets = ActiveSupport::OrderedOptions.new
7
- config.assets.paths = []
8
- config.assets.prefix = "/assets"
9
- config.assets.compilers = [
7
+ config.assets.paths = []
8
+ config.assets.excluded_paths = []
9
+ config.assets.version = "1"
10
+ config.assets.prefix = "/assets"
11
+ config.assets.compilers = [
10
12
  [ "text/css", Propshaft::Compilers::CssAssetUrls ],
11
13
  [ "text/css", Propshaft::Compilers::SourceMappingUrls ],
12
14
  [ "text/javascript", Propshaft::Compilers::SourceMappingUrls ]
@@ -21,6 +23,8 @@ module Propshaft
21
23
  app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories)
22
24
  app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories)
23
25
  app.config.assets.paths.unshift(*paths["app/assets"].existent_directories)
26
+
27
+ app.config.assets.paths = app.config.assets.paths.without(Array(app.config.assets.excluded_paths).collect(&:to_s))
24
28
  end
25
29
 
26
30
  config.after_initialize do |app|
@@ -16,13 +16,13 @@ namespace :assets do
16
16
 
17
17
  desc "Print all the assets available in config.assets.paths"
18
18
  task reveal: :environment do
19
- Rails.application.assets.reveal(:logical_path)
19
+ puts Rails.application.assets.reveal(:logical_path).join("\n")
20
20
  end
21
21
 
22
22
  namespace :reveal do
23
23
  desc "Print the full path of assets available in config.assets.paths"
24
24
  task full: :environment do
25
- Rails.application.assets.reveal(:path)
25
+ puts Rails.application.assets.reveal(:path).join("\n")
26
26
  end
27
27
  end
28
28
  end
@@ -9,8 +9,12 @@ module Propshaft::Resolver
9
9
  def resolve(logical_path)
10
10
  if asset = load_path.find(logical_path)
11
11
  File.join prefix, asset.digested_path
12
- else
13
- raise Propshaft::MissingAssetError.new(logical_path)
12
+ end
13
+ end
14
+
15
+ def read(logical_path)
16
+ if asset = load_path.find(logical_path)
17
+ asset.content
14
18
  end
15
19
  end
16
20
  end
@@ -9,8 +9,12 @@ module Propshaft::Resolver
9
9
  def resolve(logical_path)
10
10
  if asset_path = parsed_manifest[logical_path]
11
11
  File.join prefix, asset_path
12
- else
13
- raise Propshaft::MissingAssetError.new(logical_path)
12
+ end
13
+ end
14
+
15
+ def read(logical_path)
16
+ if asset_path = parsed_manifest[logical_path]
17
+ manifest_path.dirname.join(asset_path).read
14
18
  end
15
19
  end
16
20
 
@@ -1,3 +1,3 @@
1
1
  module Propshaft
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.3"
3
3
  end
data/lib/propshaft.rb CHANGED
@@ -7,5 +7,6 @@ module Propshaft
7
7
  end
8
8
 
9
9
  require "propshaft/assembly"
10
+ require "propshaft/errors"
10
11
  require "propshaft/helper"
11
12
  require "propshaft/railtie"
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.5.0
4
+ version: 0.6.3
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-01-27 00:00:00.000000000 Z
11
+ date: 2022-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack