railpack 1.2.17 → 1.3.1
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 +49 -0
- data/README.md +58 -0
- data/lib/railpack/manager.rb +86 -83
- data/lib/railpack/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f0e77f850d344d1b29f2e275c3cd49be7a4a684d0f3d5c880d03146b5cbeed6b
|
|
4
|
+
data.tar.gz: 2d2874defb0fd76f9c2c0ca3d4e746edf9067ce59fba07ef151ff096ffad5016
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e7308ab9513cfbdb703dac82f3534b8382948e9ee705dc39505014ad951141e3e75c7c2277977e20912975236b9f0efbe9acecf0032ad4203723a273f48cb8d9
|
|
7
|
+
data.tar.gz: 652705db3d4555423ea5ddcfbf8aecb6aa3584063a1c594934594052e5d7ec370c8ac44e7804092963a5b550f740fc15b414e86d03cb53811f732a0638b384d6
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.3.1] - 2026-01-26
|
|
4
|
+
|
|
5
|
+
This patch release includes final polish and documentation improvements.
|
|
6
|
+
|
|
7
|
+
### Changes
|
|
8
|
+
|
|
9
|
+
- **Code style**: Properly indented private methods and removed duplicate `private` keyword
|
|
10
|
+
- **Pre-build validation**: Added `FileUtils.mkdir_p(outdir)` to ensure output directories exist before build
|
|
11
|
+
- **Documentation**: Added comprehensive examples for `analyze_bundle` (gzip output), build hooks (payload details), and manifest delegation
|
|
12
|
+
|
|
13
|
+
## [1.3.0] - 2026-01-26
|
|
14
|
+
|
|
15
|
+
### 🚀 **Major Architecture Refactoring**
|
|
16
|
+
|
|
17
|
+
This release includes comprehensive refactoring of Railpack's two core classes, representing a significant architectural improvement while maintaining full backward compatibility.
|
|
18
|
+
|
|
19
|
+
#### ✨ **Config Class Overhaul (Railpack::Config)**
|
|
20
|
+
- **Security Hardening**: Implemented YAML safe loading with `permitted_classes: [], aliases: false`
|
|
21
|
+
- **Deep Immutability**: All configurations are now deep-frozen to prevent runtime mutations
|
|
22
|
+
- **Production Validation**: Critical settings validation in production environment
|
|
23
|
+
- **Developer Experience**: Explicit accessor methods, comprehensive documentation, deprecation warnings
|
|
24
|
+
- **Performance**: Cached configurations per environment, thread-safe access
|
|
25
|
+
|
|
26
|
+
#### 🏗️ **Manager Class Refactoring (Railpack::Manager)**
|
|
27
|
+
- **Manifest Extraction**: Created dedicated `Railpack::Manifest::Propshaft` and `::Sprockets` classes
|
|
28
|
+
- **Improved Pipeline Detection**: Direct `Rails.application.config.assets` class inspection
|
|
29
|
+
- **Enhanced Bundle Analysis**: Optional gzip size reporting for realistic metrics
|
|
30
|
+
- **Better Error Context**: Rich manifest generation error messages with pipeline type and asset counts
|
|
31
|
+
- **Pre-build Validation**: Output directory existence warnings before build starts
|
|
32
|
+
|
|
33
|
+
#### 📊 **Architecture Improvements**
|
|
34
|
+
- **Separation of Concerns**: Manifest generation isolated from orchestration logic
|
|
35
|
+
- **Testability**: Core logic now independently testable with 75 tests passing
|
|
36
|
+
- **Maintainability**: Smaller, focused classes with single responsibilities
|
|
37
|
+
- **Extensibility**: Easy to add new asset pipelines and manifest formats
|
|
38
|
+
- **Documentation**: Comprehensive class and method documentation throughout
|
|
39
|
+
|
|
40
|
+
#### 🔧 **Technical Enhancements**
|
|
41
|
+
- **Bundle Size Reporting**: Human-readable units (B, KB, MB, GB) with optional gzip analysis
|
|
42
|
+
- **Error Handling**: Enhanced error logging with contextual information
|
|
43
|
+
- **Hook System**: Improved build lifecycle hooks with detailed payload documentation
|
|
44
|
+
- **Validation**: Pre-build checks and comprehensive input validation
|
|
45
|
+
|
|
46
|
+
#### 📚 **Migration Notes**
|
|
47
|
+
- All changes are backward compatible - no breaking changes
|
|
48
|
+
- Existing configurations and APIs continue to work unchanged
|
|
49
|
+
- New features are opt-in (like gzip analysis via `analyze_bundle: true`)
|
|
50
|
+
- Enhanced error messages provide better debugging information
|
|
51
|
+
|
|
3
52
|
## [1.2.17] - 2026-01-26
|
|
4
53
|
|
|
5
54
|
### ✨ **Manager Class Final Polish - Production Perfection**
|
data/README.md
CHANGED
|
@@ -43,6 +43,7 @@ default:
|
|
|
43
43
|
sourcemap: false
|
|
44
44
|
entrypoint: "./app/javascript/application.js"
|
|
45
45
|
outdir: "app/assets/builds"
|
|
46
|
+
analyze_bundle: false # Enable for gzip size reporting
|
|
46
47
|
|
|
47
48
|
# Bundler-specific config
|
|
48
49
|
bun:
|
|
@@ -52,9 +53,11 @@ bun:
|
|
|
52
53
|
# Environment overrides
|
|
53
54
|
development:
|
|
54
55
|
sourcemap: true
|
|
56
|
+
analyze_bundle: true # Show gzip sizes in dev
|
|
55
57
|
|
|
56
58
|
production:
|
|
57
59
|
minify: true
|
|
60
|
+
analyze_bundle: true # Production bundle analysis
|
|
58
61
|
```
|
|
59
62
|
|
|
60
63
|
## Usage
|
|
@@ -111,6 +114,61 @@ Railpack.on_build_complete do |result|
|
|
|
111
114
|
end
|
|
112
115
|
```
|
|
113
116
|
|
|
117
|
+
### Advanced Usage
|
|
118
|
+
|
|
119
|
+
#### Bundle Analysis with Gzip
|
|
120
|
+
|
|
121
|
+
Enable `analyze_bundle: true` to see both uncompressed and gzipped bundle sizes:
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
# config/railpack.yml
|
|
125
|
+
default:
|
|
126
|
+
analyze_bundle: true
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Output example:
|
|
130
|
+
```
|
|
131
|
+
✅ Build completed successfully in 45.23ms (1.23 MB (0.45 MB gzipped))
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Build Hooks with Payload Details
|
|
135
|
+
|
|
136
|
+
Hook payloads provide detailed information about build results:
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
# config/initializers/railpack.rb
|
|
140
|
+
Railpack.on_build_complete do |payload|
|
|
141
|
+
if payload[:success]
|
|
142
|
+
# Success payload: { success: true, config: {...}, duration: 45.23, bundle_size: "1.23 MB" }
|
|
143
|
+
Rails.logger.info "Build succeeded in #{payload[:duration]}ms - #{payload[:bundle_size]}"
|
|
144
|
+
else
|
|
145
|
+
# Error payload: { success: false, error: #<Error>, config: {...}, duration: 12.34 }
|
|
146
|
+
Rails.logger.error "Build failed after #{payload[:duration]}ms: #{payload[:error].message}"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
Railpack.on_build_start do |config|
|
|
151
|
+
# Config hash contains all current settings
|
|
152
|
+
Rails.logger.info "Starting #{config['bundler']} build for #{Rails.env}"
|
|
153
|
+
end
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### Manifest Generation
|
|
157
|
+
|
|
158
|
+
Railpack automatically detects your asset pipeline and generates appropriate manifests:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
# For Propshaft (Rails 7+ default)
|
|
162
|
+
# Generates: app/assets/builds/.manifest.json
|
|
163
|
+
Railpack::Manifest::Propshaft.generate(config)
|
|
164
|
+
|
|
165
|
+
# For Sprockets (Rails < 7)
|
|
166
|
+
# Generates: app/assets/builds/.sprockets-manifest-*.json
|
|
167
|
+
Railpack::Manifest::Sprockets.generate(config)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The manifest generation is handled automatically after each build, but you can trigger it manually if needed.
|
|
171
|
+
|
|
114
172
|
## Supported Bundlers
|
|
115
173
|
|
|
116
174
|
### Bun (Default)
|
data/lib/railpack/manager.rb
CHANGED
|
@@ -56,6 +56,8 @@ module Railpack
|
|
|
56
56
|
# Calculate bundle size if output directory exists
|
|
57
57
|
bundle_size = calculate_bundle_size(config)
|
|
58
58
|
|
|
59
|
+
# Build result hash passed to build_complete hooks
|
|
60
|
+
# Contains: success status, config used, build duration, and bundle size
|
|
59
61
|
success_result = {
|
|
60
62
|
success: true,
|
|
61
63
|
config: config,
|
|
@@ -68,12 +70,15 @@ module Railpack
|
|
|
68
70
|
# Generate asset manifest for Rails
|
|
69
71
|
generate_asset_manifest(config)
|
|
70
72
|
|
|
73
|
+
# Trigger build_complete hooks with success result
|
|
71
74
|
Railpack.trigger_build_complete(success_result)
|
|
72
75
|
result
|
|
73
76
|
rescue => error
|
|
74
77
|
duration = ((Time.now - start_time) * 1000).round(2)
|
|
75
78
|
Railpack.logger.error "❌ Build failed after #{duration}ms: #{error.message}"
|
|
76
79
|
|
|
80
|
+
# Error result hash passed to build_complete hooks
|
|
81
|
+
# Contains: failure status, error object, config used, and build duration
|
|
77
82
|
error_result = {
|
|
78
83
|
success: false,
|
|
79
84
|
error: error,
|
|
@@ -127,109 +132,107 @@ module Railpack
|
|
|
127
132
|
|
|
128
133
|
private
|
|
129
134
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
def create_bundler
|
|
136
|
+
bundler_name = Railpack.config.bundler
|
|
137
|
+
bundler_class = BUNDLERS[bundler_name]
|
|
133
138
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
139
|
+
unless bundler_class
|
|
140
|
+
raise Error, "Unsupported bundler: #{bundler_name}. Available: #{BUNDLERS.keys.join(', ')}"
|
|
141
|
+
end
|
|
137
142
|
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
bundler_class.new(Railpack.config)
|
|
144
|
+
end
|
|
140
145
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
146
|
+
# Calculate human-readable bundle size with optional gzip compression
|
|
147
|
+
def calculate_bundle_size(config)
|
|
148
|
+
outdir = config['outdir']
|
|
149
|
+
return 'unknown' unless outdir && Dir.exist?(outdir)
|
|
145
150
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
total_size = 0
|
|
152
|
+
Dir.glob("#{outdir}/**/*.{js,css,map}").each do |file|
|
|
153
|
+
total_size += File.size(file) if File.file?(file)
|
|
154
|
+
end
|
|
150
155
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
# Include gzip size if analyze_bundle is enabled
|
|
157
|
+
if config['analyze_bundle']
|
|
158
|
+
gzip_size = calculate_gzip_size(outdir)
|
|
159
|
+
"#{human_size(total_size)} (#{human_size(gzip_size)} gzipped)"
|
|
160
|
+
else
|
|
161
|
+
human_size(total_size)
|
|
162
|
+
end
|
|
163
|
+
rescue => error
|
|
164
|
+
Railpack.logger.debug "Bundle size calculation failed: #{error.message}"
|
|
165
|
+
'unknown'
|
|
157
166
|
end
|
|
158
|
-
rescue => error
|
|
159
|
-
Railpack.logger.debug "Bundle size calculation failed: #{error.message}"
|
|
160
|
-
'unknown'
|
|
161
|
-
end
|
|
162
167
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
+
# Calculate total gzip-compressed size of assets
|
|
169
|
+
def calculate_gzip_size(outdir)
|
|
170
|
+
Dir.glob("#{outdir}/**/*.{js,css}").sum do |file|
|
|
171
|
+
next 0 unless File.file?(file)
|
|
172
|
+
Zlib::Deflate.deflate(File.read(file)).bytesize
|
|
173
|
+
end
|
|
174
|
+
rescue => error
|
|
175
|
+
Railpack.logger.debug "Gzip size calculation failed: #{error.message}"
|
|
176
|
+
0
|
|
168
177
|
end
|
|
169
|
-
rescue => error
|
|
170
|
-
Railpack.logger.debug "Gzip size calculation failed: #{error.message}"
|
|
171
|
-
0
|
|
172
|
-
end
|
|
173
178
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
# Convert bytes to human-readable format (B, KB, MB, GB)
|
|
180
|
+
def human_size(bytes)
|
|
181
|
+
units = %w[B KB MB GB]
|
|
182
|
+
size = bytes.to_f
|
|
183
|
+
units.each do |unit|
|
|
184
|
+
return "#{(size).round(2)} #{unit}" if size < 1024
|
|
185
|
+
size /= 1024
|
|
186
|
+
end
|
|
181
187
|
end
|
|
182
|
-
end
|
|
183
188
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
189
|
+
def generate_asset_manifest(config)
|
|
190
|
+
outdir = config['outdir']
|
|
191
|
+
return unless outdir && Dir.exist?(outdir)
|
|
187
192
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
193
|
+
# Detect asset pipeline type and delegate to appropriate manifest generator
|
|
194
|
+
pipeline_type = detect_asset_pipeline
|
|
195
|
+
manifest_class = Railpack::Manifest.const_get(pipeline_type.capitalize)
|
|
191
196
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
manifest_class.generate(config)
|
|
198
|
+
rescue => error
|
|
199
|
+
# Enhanced error logging with context
|
|
200
|
+
asset_files = Dir.glob("#{outdir}/**/*.{js,css}").length rescue 0
|
|
201
|
+
Railpack.logger.warn "⚠️ Failed to generate #{pipeline_type} asset manifest for #{outdir} (#{asset_files} assets): #{error.message}"
|
|
202
|
+
end
|
|
198
203
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
204
|
+
# Validate output directory exists and is writable before build
|
|
205
|
+
def validate_output_directory(config)
|
|
206
|
+
outdir = config['outdir']
|
|
207
|
+
return unless outdir
|
|
203
208
|
|
|
204
|
-
|
|
205
|
-
|
|
209
|
+
unless Dir.exist?(outdir)
|
|
210
|
+
Railpack.logger.warn "⚠️ Output directory #{outdir} does not exist - assets will be created on first build"
|
|
211
|
+
# Ensure directory exists to prevent early build failures
|
|
212
|
+
FileUtils.mkdir_p(outdir)
|
|
213
|
+
end
|
|
206
214
|
end
|
|
207
|
-
end
|
|
208
215
|
|
|
209
|
-
|
|
216
|
+
def detect_asset_pipeline
|
|
217
|
+
# Check Rails.application.config.assets class directly (more reliable)
|
|
218
|
+
if defined?(Rails) && Rails.respond_to?(:application) && Rails.application
|
|
219
|
+
assets_config = Rails.application.config.assets
|
|
220
|
+
if assets_config.is_a?(Propshaft::Assembler) || defined?(Propshaft::Assembler)
|
|
221
|
+
:propshaft
|
|
222
|
+
elsif defined?(Sprockets::Manifest)
|
|
223
|
+
:sprockets
|
|
224
|
+
end
|
|
225
|
+
end
|
|
210
226
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if defined?(Rails) && Rails.respond_to?(:application) && Rails.application
|
|
214
|
-
assets_config = Rails.application.config.assets
|
|
215
|
-
if assets_config.is_a?(Propshaft::Assembler) || defined?(Propshaft::Assembler)
|
|
227
|
+
# Fallback to version-based detection
|
|
228
|
+
if defined?(Rails) && Rails.version.to_f >= 7.0
|
|
216
229
|
:propshaft
|
|
217
|
-
elsif defined?(Sprockets
|
|
230
|
+
elsif defined?(Rails) && Rails.version.to_f < 7.0 && defined?(Sprockets)
|
|
218
231
|
:sprockets
|
|
232
|
+
else
|
|
233
|
+
# Safe default for modern Rails
|
|
234
|
+
:propshaft
|
|
219
235
|
end
|
|
220
236
|
end
|
|
221
|
-
|
|
222
|
-
# Fallback to version-based detection
|
|
223
|
-
if defined?(Rails) && Rails.version.to_f >= 7.0
|
|
224
|
-
:propshaft
|
|
225
|
-
elsif defined?(Rails) && Rails.version.to_f < 7.0 && defined?(Sprockets)
|
|
226
|
-
:sprockets
|
|
227
|
-
else
|
|
228
|
-
# Safe default for modern Rails
|
|
229
|
-
:propshaft
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
|
|
234
237
|
end
|
|
235
|
-
end
|
|
238
|
+
end
|
data/lib/railpack/version.rb
CHANGED