propshaft-compressor 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ae21d35868b662276eadac320870558edd5d2ff66ae95dfd7c20debf6a548099
4
+ data.tar.gz: 18644d8d89a1d7094174a475b56182bd0dc9e49c562e9bc731d0fceeefcbc397
5
+ SHA512:
6
+ metadata.gz: 0f58623def363231939821a7eb19ee0b08b3695fd27b991df7b2f3f64c70b249794ec41ab72c2a2d994a86c55f0d65ae708fd12521bb837a371bcce413711e42
7
+ data.tar.gz: 88ecb506e40fb61b87581fb8198a3c069ab8b45b08d83d11701bc88f470adbe9cd50f51f61e1605cde0420ed590208851723f42b508e1321065bc5133aa74843
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2024 thomas morgan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # Propshaft::Compressor
2
+
3
+ `Propshaft::Compressor` is an extension for the Propshaft asset pipeline for Rails. It adds automatic compression of assets. It is intended to be as plug-and-play as possible.
4
+
5
+ It is designed to be compatible with the new Rails 8 deployment idioms, but works with Rails 7.x too. Since it's a plugin to Propshaft, it requires the app to use Propshaft instead of Sprockets.
6
+
7
+ This gem will always compile `.gz` (gzip) versions of assets. It will add `.br` (brotli) versions if the `brotli` gem is present. Likewise, it will add `.zst` (zstandard) versions if the `zstd-ruby` gem is present.
8
+
9
+ All formats compile at max-compression.
10
+
11
+ Some common file types are automatically excluded from compression since they already contain dense or compressed content. These include: jpg, mp3, mp4, png, webp, woff, woff2.
12
+
13
+
14
+ ## Installation
15
+
16
+ Just add the gem to your app's Gemfile. It will automatically hook into the `assets:precompile` task and compress all assets after compiling.
17
+
18
+ ```ruby
19
+ gem "propshaft-compressor"
20
+
21
+ # optional (either or both)
22
+ gem "brotli"
23
+ gem "zstd-ruby"
24
+ ```
25
+
26
+
27
+ ## Usage
28
+
29
+ To make use of the precompressed assets, something needs to recognize and serve the compressed version when requested by client browsers.
30
+
31
+ If your app is using the built-in Rails file server (many do), no additional config is required. The Rails file server will automatically recognize and serve `gz` and `br`, but not `zst`.
32
+
33
+ Nginx has a built-in module that can recognize and use `gz` files. There are also addon modules for both `br` and `zst`.
34
+
35
+ Other webservers have varying support for serving pre-compressed assets.
36
+
37
+ This gem makes no effort to cleanup stale assets. If using Dockerfile-based deployments, this should be no problem. If using a deployment mechanism that leaves old assets behind, it may be necessary to periodically run `assets:clobber` (before `assets:precompile`).
38
+
39
+
40
+ ## FAQ
41
+
42
+ Q: My webserver or CDN automatically compresses assets. Do I need this?
43
+ A: Possibly. Most on-the-fly compression will use lower compression levels to improve compression speed. Precompressing at a higher compression level will result in smaller files, faster downloads, and smaller bandwidth bills.
44
+ Additionally, some webservers and CDNs limit which formats they will use to dynamically compress content. Precompressing may give you more control over this.
45
+
46
+ Q: Does this compress dynamic content?
47
+ A: No, just static assets that are precompiled as part of the asset pipeline.
48
+
49
+ Q: Can I use this with Sprockets?
50
+ A: No, it's just for Propshaft.
51
+
52
+
53
+ ## Contributing
54
+
55
+ Contributions welcomed. Please use standard GitHub Pull Requests.
56
+
57
+
58
+ ## License
59
+
60
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/setup"
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ t.warning = true
9
+ end
10
+
11
+ task default: :test
@@ -0,0 +1,9 @@
1
+ namespace :assets do
2
+ Rake::Task['assets:precompile'].enhance do
3
+ Rake::Task['assets:compress'].invoke
4
+ end
5
+
6
+ task :compress do
7
+ Propshaft::Compressor.compress_assets Rails.application.assets.processor
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Propshaft
2
+ module Compressor
3
+ class Railtie < ::Rails::Railtie
4
+
5
+ rake_tasks do
6
+ load 'propshaft/compressor/assets.rake'
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module Propshaft
2
+ module Compressor
3
+ VERSION = '0.2.0'
4
+ end
5
+ end
@@ -0,0 +1,86 @@
1
+ require 'zlib'
2
+ begin
3
+ require 'brotli'
4
+ rescue LoadError
5
+ end
6
+ begin
7
+ require 'zstd-ruby'
8
+ rescue LoadError
9
+ end
10
+
11
+ module Propshaft
12
+ module Compressor
13
+
14
+ FORMATS = {} # { '.ext' => [GzipWriter, 9] }
15
+
16
+ class Writer
17
+ def self.compress(...)
18
+ new(...).compress
19
+ end
20
+
21
+ def initialize(from:, to:, level: 8)
22
+ @from = from
23
+ @to = to
24
+ @level = level
25
+ end
26
+
27
+ def compress
28
+ File.open(@from, 'rb') do |from_io|
29
+ File.open(@to, 'wb+') do |to_io|
30
+ writer = build_writer to_io, from_io.mtime
31
+ from_io.each do |blk|
32
+ writer.write blk
33
+ end
34
+ ensure
35
+ writer&.close
36
+ end
37
+ File.utime from_io.atime, from_io.mtime, @to
38
+ end
39
+ end
40
+
41
+ def build_writer(io)
42
+ raise 'abstract'
43
+ end
44
+ end
45
+
46
+ if defined? Brotli::Writer
47
+ class BrotliWriter < Writer
48
+ def build_writer(io, _)
49
+ Brotli::Writer.new io, quality: @level
50
+ end
51
+ end
52
+ FORMATS['.br'] = [ BrotliWriter, 11 ]
53
+ end
54
+
55
+ class GzipWriter < Writer
56
+ def build_writer(io, mtime)
57
+ Zlib::GzipWriter.new(io, @level).tap do |gz|
58
+ gz.mtime = mtime
59
+ end
60
+ end
61
+ end
62
+ FORMATS['.gz'] = [ GzipWriter, 9 ]
63
+
64
+ if defined? Zstd::StreamWriter
65
+ class ZstdWriter < Writer
66
+ def build_writer(io, _)
67
+ Zstd::StreamWriter.new io, level: @level
68
+ end
69
+ end
70
+ FORMATS['.zst'] = [ ZstdWriter, 22 ]
71
+
72
+ if Zstd::VERSION <= '1.5.6.6'
73
+ module ZstdStreamWriterPatch
74
+ # monkeypatch to silence deprecation warning
75
+ def initialize(io, level: nil)
76
+ @io = io
77
+ @stream = Zstd::StreamingCompress.new level: level
78
+ end
79
+ end
80
+ Zstd::StreamWriter.prepend ZstdStreamWriterPatch
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+
@@ -0,0 +1,33 @@
1
+ require 'propshaft'
2
+
3
+ %w(
4
+ version
5
+ writer
6
+ railtie
7
+ ).each do |f|
8
+ require_relative "compressor/#{f}"
9
+ end
10
+
11
+
12
+ module Propshaft
13
+ module Compressor
14
+
15
+ SKIP_EXTS = %w(jpg mp3 mp4 png webp woff woff2)
16
+
17
+ def self.compress_assets(processor)
18
+ processor.load_path.assets.each do |asset|
19
+ in_path = processor.output_path.join(asset.digested_path).to_s
20
+ next if SKIP_EXTS.any?{|ext| in_path.ends_with? ".#{ext}" }
21
+
22
+ FORMATS.each do |ext, (klass, level)|
23
+ out_path = processor.output_path.join(asset.digested_path.to_s+ext)
24
+ unless out_path.exist?
25
+ Propshaft.logger.info "Writing #{asset.digested_path}#{ext}"
26
+ klass.compress from: in_path, to: out_path, level: level
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: propshaft-compressor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - thomas morgan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-12-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: propshaft
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: railties
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '7'
41
+ description: Adds asset compression to Propshaft. Compresses with gzip, brotli, and/or
42
+ zstandard.
43
+ email:
44
+ - tm@iprog.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - LICENSE.txt
50
+ - README.md
51
+ - Rakefile
52
+ - lib/propshaft/compressor.rb
53
+ - lib/propshaft/compressor/assets.rake
54
+ - lib/propshaft/compressor/railtie.rb
55
+ - lib/propshaft/compressor/version.rb
56
+ - lib/propshaft/compressor/writer.rb
57
+ homepage: https://github.com/zarqman/propshaft-compressor
58
+ licenses:
59
+ - MIT
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '2.7'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubygems_version: 3.5.22
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Extends Propshaft to add asset compression using gzip, brotli, zstandard
80
+ test_files: []