railpack 1.2.6 → 1.2.8
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 +9 -8
- data/lib/railpack/bundler.rb +1 -1
- data/lib/railpack/manager.rb +74 -2
- data/lib/railpack/version.rb +1 -1
- data/test/bundler_test.rb +173 -0
- data/test/config_test.rb +178 -0
- data/test/manager_test.rb +254 -0
- data/test/railpack_test.rb +0 -97
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 78f1e4155bf62341ff89f8740ae745ad8d661a4268d6770bd9c7c5117ec1c516
|
|
4
|
+
data.tar.gz: 9f940702b52d4b4d2d6e17a62292cad384cf1c3a37ef73b34d94271bdb160bbc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 73e1eb2404abc24a6ca389019012bb43aa26f37de80efc7db5f66bc56a41e3b9ca4c12f9b830957df9265baf31a915d52326690b844596e1fd269faba038be3a
|
|
7
|
+
data.tar.gz: c1eafb1385dc6eaeeacb0e589964cb1d2de997642e5cccba4e77ba72bb6ef11318e45a1d0d7e625100412da47ed96aca895ea90324c8bb80aa70f30f9ad05806
|
data/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
-
## [1.2.
|
|
4
|
-
|
|
5
|
-
- Add
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
3
|
+
## [1.2.8] - 2026-01-26
|
|
4
|
+
|
|
5
|
+
- Add Sprockets compatibility for older Rails applications
|
|
6
|
+
- Automatic asset pipeline detection (Propshaft vs Sprockets)
|
|
7
|
+
- Generate appropriate manifest format based on Rails version
|
|
8
|
+
- Propshaft manifest: .manifest.json (Rails 7+ default)
|
|
9
|
+
- Sprockets manifest: .sprockets-manifest-*.json (Rails < 7)
|
|
10
|
+
- Enhanced Rails integration for broader compatibility
|
|
11
|
+
- All 46 tests passing with 147 assertions
|
|
11
12
|
|
|
12
13
|
## [1.2.4] - 2026-01-26
|
|
13
14
|
|
data/lib/railpack/bundler.rb
CHANGED
data/lib/railpack/manager.rb
CHANGED
|
@@ -128,6 +128,39 @@ module Railpack
|
|
|
128
128
|
outdir = config['outdir']
|
|
129
129
|
return unless outdir && Dir.exist?(outdir)
|
|
130
130
|
|
|
131
|
+
# Detect asset pipeline type
|
|
132
|
+
pipeline_type = detect_asset_pipeline
|
|
133
|
+
|
|
134
|
+
case pipeline_type
|
|
135
|
+
when :propshaft
|
|
136
|
+
generate_propshaft_manifest(config)
|
|
137
|
+
when :sprockets
|
|
138
|
+
generate_sprockets_manifest(config)
|
|
139
|
+
else
|
|
140
|
+
# Default to Propshaft for Rails 7+
|
|
141
|
+
generate_propshaft_manifest(config)
|
|
142
|
+
end
|
|
143
|
+
rescue => error
|
|
144
|
+
Railpack.logger.warn "⚠️ Failed to generate asset manifest: #{error.message}"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
def detect_asset_pipeline
|
|
150
|
+
# Check for Propshaft (Rails 7+ default)
|
|
151
|
+
if defined?(Propshaft) || (defined?(Rails) && Rails.version.to_f >= 7.0)
|
|
152
|
+
:propshaft
|
|
153
|
+
# Check for Sprockets
|
|
154
|
+
elsif defined?(Sprockets)
|
|
155
|
+
:sprockets
|
|
156
|
+
else
|
|
157
|
+
# Default to Propshaft for modern Rails
|
|
158
|
+
:propshaft
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def generate_propshaft_manifest(config)
|
|
163
|
+
outdir = config['outdir']
|
|
131
164
|
manifest = {}
|
|
132
165
|
|
|
133
166
|
# Find built assets - Propshaft format
|
|
@@ -155,8 +188,47 @@ module Railpack
|
|
|
155
188
|
manifest_path = "#{outdir}/.manifest.json"
|
|
156
189
|
File.write(manifest_path, JSON.pretty_generate(manifest))
|
|
157
190
|
Railpack.logger.debug "📄 Generated Propshaft manifest: #{manifest_path}"
|
|
158
|
-
|
|
159
|
-
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def generate_sprockets_manifest(config)
|
|
194
|
+
outdir = config['outdir']
|
|
195
|
+
manifest = {
|
|
196
|
+
'files' => {},
|
|
197
|
+
'assets' => {}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# Find built assets - Sprockets format
|
|
201
|
+
Dir.glob("#{outdir}/**/*.{js,css}").each do |file|
|
|
202
|
+
next unless File.file?(file)
|
|
203
|
+
relative_path = Pathname.new(file).relative_path_from(Pathname.new(outdir)).to_s
|
|
204
|
+
|
|
205
|
+
# Generate digest for Sprockets format
|
|
206
|
+
digest = Digest::MD5.file(file).hexdigest
|
|
207
|
+
logical_path = relative_path
|
|
208
|
+
|
|
209
|
+
# Map logical names (Sprockets style)
|
|
210
|
+
if relative_path.include?('application') && relative_path.end_with?('.js')
|
|
211
|
+
manifest['assets']['application.js'] = "#{digest}-#{File.basename(relative_path)}"
|
|
212
|
+
logical_path = 'application.js'
|
|
213
|
+
elsif relative_path.include?('application') && relative_path.end_with?('.css')
|
|
214
|
+
manifest['assets']['application.css'] = "#{digest}-#{File.basename(relative_path)}"
|
|
215
|
+
logical_path = 'application.css'
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Add file entry
|
|
219
|
+
manifest['files']["#{digest}-#{File.basename(relative_path)}"] = {
|
|
220
|
+
'logical_path' => logical_path,
|
|
221
|
+
'pathname' => relative_path,
|
|
222
|
+
'digest' => digest,
|
|
223
|
+
'size' => File.size(file),
|
|
224
|
+
'mtime' => File.mtime(file).iso8601
|
|
225
|
+
}
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Write manifest for Sprockets (Rails < 7)
|
|
229
|
+
manifest_path = "#{outdir}/.sprockets-manifest-#{Digest::MD5.hexdigest(outdir)}.json"
|
|
230
|
+
File.write(manifest_path, JSON.pretty_generate(manifest))
|
|
231
|
+
Railpack.logger.debug "📄 Generated Sprockets manifest: #{manifest_path}"
|
|
160
232
|
end
|
|
161
233
|
end
|
|
162
234
|
end
|
data/lib/railpack/version.rb
CHANGED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'minitest/autorun'
|
|
4
|
+
require 'railpack'
|
|
5
|
+
|
|
6
|
+
class BundlerTest < Minitest::Test
|
|
7
|
+
def test_bundler_base_class
|
|
8
|
+
bundler = Railpack::Bundler.new({})
|
|
9
|
+
|
|
10
|
+
assert_respond_to bundler, :build!
|
|
11
|
+
assert_respond_to bundler, :watch
|
|
12
|
+
assert_respond_to bundler, :install!
|
|
13
|
+
assert_respond_to bundler, :name
|
|
14
|
+
assert_respond_to bundler, :commands
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_bun_bundler_initialization
|
|
18
|
+
bundler = Railpack::BunBundler.new({})
|
|
19
|
+
assert_instance_of Railpack::BunBundler, bundler
|
|
20
|
+
assert_equal 'bun', bundler.name
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_bun_bundler_commands
|
|
24
|
+
bundler = Railpack::BunBundler.new({})
|
|
25
|
+
commands = bundler.send(:commands)
|
|
26
|
+
|
|
27
|
+
assert_equal 'bun run build', commands[:build]
|
|
28
|
+
assert_equal 'bun run watch', commands[:watch]
|
|
29
|
+
assert_equal 'bun install', commands[:install]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_esbuild_bundler_initialization
|
|
33
|
+
bundler = Railpack::EsbuildBundler.new({})
|
|
34
|
+
assert_instance_of Railpack::EsbuildBundler, bundler
|
|
35
|
+
assert_equal 'esbuild', bundler.name
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_esbuild_bundler_commands
|
|
39
|
+
bundler = Railpack::EsbuildBundler.new({})
|
|
40
|
+
commands = bundler.send(:commands)
|
|
41
|
+
|
|
42
|
+
assert_equal 'esbuild', commands[:build]
|
|
43
|
+
assert_equal 'esbuild --watch', commands[:watch]
|
|
44
|
+
assert_equal 'npm install', commands[:install]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_rollup_bundler_initialization
|
|
48
|
+
bundler = Railpack::RollupBundler.new({})
|
|
49
|
+
assert_instance_of Railpack::RollupBundler, bundler
|
|
50
|
+
assert_equal 'rollup', bundler.name
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_rollup_bundler_commands
|
|
54
|
+
bundler = Railpack::RollupBundler.new({})
|
|
55
|
+
commands = bundler.send(:commands)
|
|
56
|
+
|
|
57
|
+
assert_equal 'rollup', commands[:build]
|
|
58
|
+
assert_equal 'rollup --watch', commands[:watch]
|
|
59
|
+
assert_equal 'npm install', commands[:install]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_webpack_bundler_initialization
|
|
63
|
+
bundler = Railpack::WebpackBundler.new({})
|
|
64
|
+
assert_instance_of Railpack::WebpackBundler, bundler
|
|
65
|
+
assert_equal 'webpack', bundler.name
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_webpack_bundler_commands
|
|
69
|
+
bundler = Railpack::WebpackBundler.new({})
|
|
70
|
+
commands = bundler.send(:commands)
|
|
71
|
+
|
|
72
|
+
assert_equal 'webpack', commands[:build]
|
|
73
|
+
assert_equal 'webpack --watch', commands[:watch]
|
|
74
|
+
assert_equal 'npm install', commands[:install]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_bundler_name_uniqueness
|
|
78
|
+
bundlers = [
|
|
79
|
+
Railpack::BunBundler.new({}),
|
|
80
|
+
Railpack::EsbuildBundler.new({}),
|
|
81
|
+
Railpack::RollupBundler.new({}),
|
|
82
|
+
Railpack::WebpackBundler.new({})
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
names = bundlers.map(&:name)
|
|
86
|
+
assert_equal names.uniq.size, names.size, "All bundler names should be unique"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_bundler_commands_structure
|
|
90
|
+
bundlers = [
|
|
91
|
+
Railpack::BunBundler.new({}),
|
|
92
|
+
Railpack::EsbuildBundler.new({}),
|
|
93
|
+
Railpack::RollupBundler.new({}),
|
|
94
|
+
Railpack::WebpackBundler.new({})
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
bundlers.each do |bundler|
|
|
98
|
+
commands = bundler.send(:commands)
|
|
99
|
+
assert_respond_to commands, :[]
|
|
100
|
+
assert commands.key?(:build)
|
|
101
|
+
assert commands.key?(:watch)
|
|
102
|
+
assert commands.key?(:install)
|
|
103
|
+
|
|
104
|
+
# All commands should be strings
|
|
105
|
+
assert commands[:build].is_a?(String)
|
|
106
|
+
assert commands[:watch].is_a?(String)
|
|
107
|
+
assert commands[:install].is_a?(String)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def test_bundler_inheritance
|
|
112
|
+
bundlers = [
|
|
113
|
+
Railpack::BunBundler,
|
|
114
|
+
Railpack::EsbuildBundler,
|
|
115
|
+
Railpack::RollupBundler,
|
|
116
|
+
Railpack::WebpackBundler
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
bundlers.each do |bundler_class|
|
|
120
|
+
assert bundler_class < Railpack::Bundler, "#{bundler_class} should inherit from Railpack::Bundler"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def test_bundler_config_passing
|
|
125
|
+
config = { 'target' => 'node', 'format' => 'cjs' }
|
|
126
|
+
|
|
127
|
+
bundler = Railpack::BunBundler.new(config)
|
|
128
|
+
assert_equal config, bundler.instance_variable_get(:@config)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def test_bundler_error_handling
|
|
132
|
+
bundler = Railpack::BunBundler.new({})
|
|
133
|
+
|
|
134
|
+
# Mock system to return false (command failure)
|
|
135
|
+
bundler.define_singleton_method(:execute!) do |*args|
|
|
136
|
+
raise Railpack::Error, "Command failed"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# This should raise an error
|
|
140
|
+
assert_raises(Railpack::Error) do
|
|
141
|
+
bundler.build!([])
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def test_bundler_watch_method
|
|
146
|
+
bundler = Railpack::BunBundler.new({})
|
|
147
|
+
|
|
148
|
+
# Mock system to avoid actual execution
|
|
149
|
+
bundler.define_singleton_method(:system) do |*args|
|
|
150
|
+
true
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Watch should not raise an error
|
|
154
|
+
begin
|
|
155
|
+
bundler.watch([])
|
|
156
|
+
assert true # If we get here, no exception was raised
|
|
157
|
+
rescue
|
|
158
|
+
flunk "watch method should not raise an error"
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def test_bundler_install_method
|
|
163
|
+
bundler = Railpack::BunBundler.new({})
|
|
164
|
+
|
|
165
|
+
# Mock system to return true (command success)
|
|
166
|
+
bundler.define_singleton_method(:system) do |*args|
|
|
167
|
+
true
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
result = bundler.install!
|
|
171
|
+
assert result
|
|
172
|
+
end
|
|
173
|
+
end
|
data/test/config_test.rb
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'minitest/autorun'
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'pathname'
|
|
7
|
+
require 'railpack'
|
|
8
|
+
|
|
9
|
+
class ConfigTest < Minitest::Test
|
|
10
|
+
def setup
|
|
11
|
+
@temp_dir = Dir.mktmpdir
|
|
12
|
+
@original_rails_root = nil
|
|
13
|
+
if defined?(Rails) && Rails.respond_to?(:root)
|
|
14
|
+
@original_rails_root = Rails.singleton_class.instance_method(:root)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def teardown
|
|
19
|
+
FileUtils.remove_entry(@temp_dir) if @temp_dir && Dir.exist?(@temp_dir)
|
|
20
|
+
# Restore original Rails.root method if it was overridden
|
|
21
|
+
if @original_rails_root && defined?(Rails)
|
|
22
|
+
Rails.singleton_class.define_method(:root, @original_rails_root)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_config_initialization
|
|
27
|
+
config = Railpack::Config.new
|
|
28
|
+
assert_instance_of Railpack::Config, config
|
|
29
|
+
assert_respond_to config, :bundler
|
|
30
|
+
assert_respond_to config, :entrypoint
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_config_default_values
|
|
34
|
+
config = Railpack::Config.new
|
|
35
|
+
assert_equal 'bun', config.bundler
|
|
36
|
+
assert_equal './app/javascript/application.js', config.entrypoint
|
|
37
|
+
assert_equal 'app/assets/builds', config.outdir
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_config_build_flags_unit
|
|
41
|
+
config = Railpack::Config.new
|
|
42
|
+
|
|
43
|
+
# Test build_flags with different environments
|
|
44
|
+
dev_flags = config.build_flags('development')
|
|
45
|
+
prod_flags = config.build_flags('production')
|
|
46
|
+
|
|
47
|
+
# Development should have sourcemap
|
|
48
|
+
assert_includes dev_flags, '--sourcemap'
|
|
49
|
+
# Production should have minify
|
|
50
|
+
assert_includes prod_flags, '--minify'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_config_build_args_unit
|
|
54
|
+
config = Railpack::Config.new
|
|
55
|
+
|
|
56
|
+
args = config.build_args('development')
|
|
57
|
+
assert_includes args, './app/javascript/application.js'
|
|
58
|
+
assert_includes args, '--outdir=app/assets/builds'
|
|
59
|
+
assert_includes args, '--target=browser'
|
|
60
|
+
assert_includes args, '--format=esm'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_config_bundler_method
|
|
64
|
+
config = Railpack::Config.new
|
|
65
|
+
|
|
66
|
+
# Test bundler method with different environments
|
|
67
|
+
assert_equal 'bun', config.bundler('development')
|
|
68
|
+
assert_equal 'bun', config.bundler('production')
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_config_for_environment_unit
|
|
72
|
+
config = Railpack::Config.new
|
|
73
|
+
|
|
74
|
+
dev_config = config.for_environment('development')
|
|
75
|
+
prod_config = config.for_environment('production')
|
|
76
|
+
|
|
77
|
+
# Check that environment-specific settings are applied
|
|
78
|
+
assert_equal true, dev_config['sourcemap']
|
|
79
|
+
assert_equal true, prod_config['minify']
|
|
80
|
+
assert_equal false, prod_config['sourcemap']
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_config_yaml_file_loading
|
|
84
|
+
# Test that Railpack can load config from a YAML file
|
|
85
|
+
config_dir = File.join(@temp_dir, 'config')
|
|
86
|
+
FileUtils.mkdir_p(config_dir)
|
|
87
|
+
config_file = File.join(config_dir, 'railpack.yml')
|
|
88
|
+
|
|
89
|
+
File.write(config_file, <<~YAML)
|
|
90
|
+
default:
|
|
91
|
+
bundler: rollup
|
|
92
|
+
target: node
|
|
93
|
+
format: cjs
|
|
94
|
+
entrypoint: "./server.js"
|
|
95
|
+
outdir: "dist"
|
|
96
|
+
minify: false
|
|
97
|
+
development:
|
|
98
|
+
sourcemap: true
|
|
99
|
+
production:
|
|
100
|
+
minify: true
|
|
101
|
+
sourcemap: false
|
|
102
|
+
YAML
|
|
103
|
+
|
|
104
|
+
# Verify the file was created
|
|
105
|
+
assert File.exist?(config_file), "Config file should exist at #{config_file}"
|
|
106
|
+
|
|
107
|
+
# Mock Rails.root to point to our temp directory
|
|
108
|
+
mock_rails_root(@temp_dir)
|
|
109
|
+
|
|
110
|
+
# Create a fresh config instance to test file loading
|
|
111
|
+
config = Railpack::Config.new
|
|
112
|
+
|
|
113
|
+
# Test that the YAML file was loaded correctly
|
|
114
|
+
assert_equal 'rollup', config.bundler
|
|
115
|
+
assert_equal './server.js', config.entrypoint
|
|
116
|
+
assert_equal 'dist', config.outdir
|
|
117
|
+
assert_equal 'node', config.target
|
|
118
|
+
assert_equal 'cjs', config.format
|
|
119
|
+
assert_equal false, config.minify
|
|
120
|
+
|
|
121
|
+
# Test environment overrides
|
|
122
|
+
dev_config = config.for_environment('development')
|
|
123
|
+
prod_config = config.for_environment('production')
|
|
124
|
+
|
|
125
|
+
assert_equal true, dev_config['sourcemap']
|
|
126
|
+
assert_equal true, prod_config['minify']
|
|
127
|
+
assert_equal false, prod_config['sourcemap']
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def test_config_environment_overrides
|
|
131
|
+
# Test environment override logic with default config
|
|
132
|
+
config = Railpack::Config.new
|
|
133
|
+
dev_config = config.for_environment('development')
|
|
134
|
+
prod_config = config.for_environment('production')
|
|
135
|
+
|
|
136
|
+
# Development should have sourcemap enabled by default
|
|
137
|
+
assert_equal true, dev_config['sourcemap']
|
|
138
|
+
# Production should have minify enabled by default
|
|
139
|
+
assert_equal true, prod_config['minify']
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def test_config_error_handling
|
|
143
|
+
# Test config error handling for invalid YAML
|
|
144
|
+
config_dir = File.join(@temp_dir, 'config')
|
|
145
|
+
FileUtils.mkdir_p(config_dir)
|
|
146
|
+
config_file = File.join(config_dir, 'railpack.yml')
|
|
147
|
+
File.write(config_file, "invalid: yaml: content: [")
|
|
148
|
+
|
|
149
|
+
mock_rails_root(@temp_dir)
|
|
150
|
+
|
|
151
|
+
# This should raise an error for invalid YAML
|
|
152
|
+
assert_raises(Railpack::Config::Error) do
|
|
153
|
+
Railpack::Config.new
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def test_config_method_missing
|
|
158
|
+
config = Railpack::Config.new
|
|
159
|
+
|
|
160
|
+
# Test that config responds to dynamic methods
|
|
161
|
+
assert_respond_to config, :target
|
|
162
|
+
assert_respond_to config, :format
|
|
163
|
+
assert_equal 'browser', config.target
|
|
164
|
+
assert_equal 'esm', config.format
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
private
|
|
168
|
+
|
|
169
|
+
def mock_rails_root(path)
|
|
170
|
+
rails_module = if defined?(Rails)
|
|
171
|
+
Rails
|
|
172
|
+
else
|
|
173
|
+
Object.const_set(:Rails, Module.new)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
rails_module.define_singleton_method(:root) { Pathname.new(path) }
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'minitest/autorun'
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'pathname'
|
|
7
|
+
require 'railpack'
|
|
8
|
+
|
|
9
|
+
class ManagerTest < Minitest::Test
|
|
10
|
+
def setup
|
|
11
|
+
@temp_dir = Dir.mktmpdir
|
|
12
|
+
@original_rails_root = nil
|
|
13
|
+
if defined?(Rails) && Rails.respond_to?(:root)
|
|
14
|
+
@original_rails_root = Rails.singleton_class.instance_method(:root)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def teardown
|
|
19
|
+
FileUtils.remove_entry(@temp_dir) if @temp_dir && Dir.exist?(@temp_dir)
|
|
20
|
+
# Restore original Rails.root method if it was overridden
|
|
21
|
+
if @original_rails_root && defined?(Rails)
|
|
22
|
+
Rails.singleton_class.define_method(:root, @original_rails_root)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_manager_initialization
|
|
27
|
+
manager = Railpack::Manager.new
|
|
28
|
+
assert_instance_of Railpack::Manager, manager
|
|
29
|
+
assert_respond_to manager, :build!
|
|
30
|
+
assert_respond_to manager, :watch
|
|
31
|
+
assert_respond_to manager, :install!
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_manager_bundler_creation
|
|
35
|
+
manager = Railpack::Manager.new
|
|
36
|
+
bundler = manager.send(:create_bundler)
|
|
37
|
+
assert_instance_of Railpack::BunBundler, bundler
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_manager_bundle_size_calculation
|
|
41
|
+
# Create test output directory with fake assets
|
|
42
|
+
outdir = File.join(@temp_dir, 'builds')
|
|
43
|
+
FileUtils.mkdir_p(outdir)
|
|
44
|
+
|
|
45
|
+
# Create fake JS and CSS files
|
|
46
|
+
File.write(File.join(outdir, 'app.js'), 'console.log("test");')
|
|
47
|
+
File.write(File.join(outdir, 'app.css'), 'body { color: red; }')
|
|
48
|
+
File.write(File.join(outdir, 'app.js.map'), '{"version":3}')
|
|
49
|
+
|
|
50
|
+
config = { 'outdir' => outdir }
|
|
51
|
+
manager = Railpack::Manager.new
|
|
52
|
+
|
|
53
|
+
size = manager.send(:calculate_bundle_size, config)
|
|
54
|
+
assert size.is_a?(Float)
|
|
55
|
+
assert size > 0
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def test_manager_bundle_size_calculation_empty_directory
|
|
59
|
+
# Test with empty directory
|
|
60
|
+
outdir = File.join(@temp_dir, 'empty_builds')
|
|
61
|
+
FileUtils.mkdir_p(outdir)
|
|
62
|
+
|
|
63
|
+
config = { 'outdir' => outdir }
|
|
64
|
+
manager = Railpack::Manager.new
|
|
65
|
+
|
|
66
|
+
size = manager.send(:calculate_bundle_size, config)
|
|
67
|
+
assert_equal 0.0, size
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_manager_bundle_size_calculation_nonexistent_directory
|
|
71
|
+
manager = Railpack::Manager.new
|
|
72
|
+
config = { 'outdir' => '/nonexistent/directory' }
|
|
73
|
+
|
|
74
|
+
size = manager.send(:calculate_bundle_size, config)
|
|
75
|
+
assert_equal 'unknown', size
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_manager_asset_manifest_generation
|
|
79
|
+
outdir = File.join(@temp_dir, 'builds')
|
|
80
|
+
FileUtils.mkdir_p(outdir)
|
|
81
|
+
|
|
82
|
+
# Create fake built assets
|
|
83
|
+
File.write(File.join(outdir, 'application.js'), 'console.log("app");')
|
|
84
|
+
File.write(File.join(outdir, 'application.css'), 'body { color: blue; }')
|
|
85
|
+
|
|
86
|
+
config = { 'outdir' => outdir }
|
|
87
|
+
manager = Railpack::Manager.new
|
|
88
|
+
|
|
89
|
+
manager.send(:generate_asset_manifest, config)
|
|
90
|
+
|
|
91
|
+
manifest_path = File.join(outdir, '.manifest.json')
|
|
92
|
+
assert File.exist?(manifest_path)
|
|
93
|
+
|
|
94
|
+
manifest = JSON.parse(File.read(manifest_path))
|
|
95
|
+
assert manifest.key?('application.js')
|
|
96
|
+
assert manifest.key?('application.css')
|
|
97
|
+
assert manifest['application.js']['logical_path'] == 'application.js'
|
|
98
|
+
assert manifest['application.js']['pathname'].end_with?('application.js')
|
|
99
|
+
assert manifest['application.js']['digest']
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_manager_asset_manifest_generation_no_assets
|
|
103
|
+
outdir = File.join(@temp_dir, 'empty_builds')
|
|
104
|
+
FileUtils.mkdir_p(outdir)
|
|
105
|
+
|
|
106
|
+
config = { 'outdir' => outdir }
|
|
107
|
+
manager = Railpack::Manager.new
|
|
108
|
+
|
|
109
|
+
# Ensure Propshaft detection for this test
|
|
110
|
+
def manager.detect_asset_pipeline
|
|
111
|
+
:propshaft
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
manager.send(:generate_asset_manifest, config)
|
|
115
|
+
|
|
116
|
+
manifest_path = File.join(outdir, '.manifest.json')
|
|
117
|
+
assert File.exist?(manifest_path)
|
|
118
|
+
|
|
119
|
+
manifest = JSON.parse(File.read(manifest_path))
|
|
120
|
+
assert_empty manifest
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_manager_build_with_config
|
|
124
|
+
manager = Railpack::Manager.new
|
|
125
|
+
|
|
126
|
+
# Mock the bundler to avoid actual command execution
|
|
127
|
+
mock_bundler = Minitest::Mock.new
|
|
128
|
+
mock_bundler.expect(:build!, true, [[]])
|
|
129
|
+
manager.instance_variable_set(:@bundler, mock_bundler)
|
|
130
|
+
|
|
131
|
+
# Mock Rails.env to avoid dependency
|
|
132
|
+
rails_module = if defined?(Rails)
|
|
133
|
+
Rails
|
|
134
|
+
else
|
|
135
|
+
Object.const_set(:Rails, Module.new)
|
|
136
|
+
end
|
|
137
|
+
rails_module.define_singleton_method(:env) { 'development' }
|
|
138
|
+
|
|
139
|
+
result = manager.build!
|
|
140
|
+
assert result
|
|
141
|
+
|
|
142
|
+
mock_bundler.verify
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def test_manager_install_with_config
|
|
146
|
+
manager = Railpack::Manager.new
|
|
147
|
+
|
|
148
|
+
# Mock the bundler to avoid actual command execution
|
|
149
|
+
mock_bundler = Minitest::Mock.new
|
|
150
|
+
mock_bundler.expect(:install!, true, [[]])
|
|
151
|
+
manager.instance_variable_set(:@bundler, mock_bundler)
|
|
152
|
+
|
|
153
|
+
result = manager.install!
|
|
154
|
+
assert result
|
|
155
|
+
|
|
156
|
+
mock_bundler.verify
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def test_manager_watch_with_config
|
|
160
|
+
manager = Railpack::Manager.new
|
|
161
|
+
|
|
162
|
+
# Mock the bundler to avoid actual command execution
|
|
163
|
+
mock_bundler = Minitest::Mock.new
|
|
164
|
+
mock_bundler.expect(:watch, nil, [[]])
|
|
165
|
+
manager.instance_variable_set(:@bundler, mock_bundler)
|
|
166
|
+
|
|
167
|
+
manager.watch
|
|
168
|
+
|
|
169
|
+
mock_bundler.verify
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def test_manager_bundler_constants
|
|
173
|
+
assert_equal Railpack::BunBundler, Railpack::Manager::BUNDLERS['bun']
|
|
174
|
+
assert_equal Railpack::EsbuildBundler, Railpack::Manager::BUNDLERS['esbuild']
|
|
175
|
+
assert_equal Railpack::RollupBundler, Railpack::Manager::BUNDLERS['rollup']
|
|
176
|
+
assert_equal Railpack::WebpackBundler, Railpack::Manager::BUNDLERS['webpack']
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def test_detect_asset_pipeline_propshaft
|
|
180
|
+
manager = Railpack::Manager.new
|
|
181
|
+
|
|
182
|
+
# Mock Rails version for Propshaft detection
|
|
183
|
+
rails_module = if defined?(Rails)
|
|
184
|
+
Rails
|
|
185
|
+
else
|
|
186
|
+
Object.const_set(:Rails, Module.new)
|
|
187
|
+
end
|
|
188
|
+
rails_module.define_singleton_method(:version) { '7.0.0' }
|
|
189
|
+
|
|
190
|
+
pipeline = manager.send(:detect_asset_pipeline)
|
|
191
|
+
assert_equal :propshaft, pipeline
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def test_detect_asset_pipeline_sprockets
|
|
195
|
+
manager = Railpack::Manager.new
|
|
196
|
+
|
|
197
|
+
# Mock Sprockets being available
|
|
198
|
+
Object.const_set(:Sprockets, Module.new) unless defined?(Sprockets)
|
|
199
|
+
|
|
200
|
+
# Mock Rails version for Sprockets detection
|
|
201
|
+
rails_module = if defined?(Rails)
|
|
202
|
+
Rails
|
|
203
|
+
else
|
|
204
|
+
Object.const_set(:Rails, Module.new)
|
|
205
|
+
end
|
|
206
|
+
rails_module.define_singleton_method(:version) { '6.1.0' }
|
|
207
|
+
|
|
208
|
+
pipeline = manager.send(:detect_asset_pipeline)
|
|
209
|
+
assert_equal :sprockets, pipeline
|
|
210
|
+
ensure
|
|
211
|
+
Object.send(:remove_const, :Sprockets) if defined?(Sprockets) && Sprockets.name.nil?
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def test_generate_sprockets_manifest
|
|
215
|
+
outdir = File.join(@temp_dir, 'builds')
|
|
216
|
+
FileUtils.mkdir_p(outdir)
|
|
217
|
+
|
|
218
|
+
# Create fake built assets
|
|
219
|
+
File.write(File.join(outdir, 'application.js'), 'console.log("app");')
|
|
220
|
+
File.write(File.join(outdir, 'application.css'), 'body { color: blue; }')
|
|
221
|
+
|
|
222
|
+
config = { 'outdir' => outdir }
|
|
223
|
+
manager = Railpack::Manager.new
|
|
224
|
+
|
|
225
|
+
manager.send(:generate_sprockets_manifest, config)
|
|
226
|
+
|
|
227
|
+
manifest_path = Dir.glob("#{outdir}/.sprockets-manifest-*.json").first
|
|
228
|
+
assert manifest_path
|
|
229
|
+
assert File.exist?(manifest_path)
|
|
230
|
+
|
|
231
|
+
manifest = JSON.parse(File.read(manifest_path))
|
|
232
|
+
assert manifest.key?('files')
|
|
233
|
+
assert manifest.key?('assets')
|
|
234
|
+
assert manifest['assets'].key?('application.js')
|
|
235
|
+
assert manifest['assets'].key?('application.css')
|
|
236
|
+
|
|
237
|
+
# Check file entries
|
|
238
|
+
js_digest = manifest['assets']['application.js']
|
|
239
|
+
assert manifest['files'].key?(js_digest)
|
|
240
|
+
assert_equal 'application.js', manifest['files'][js_digest]['logical_path']
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
private
|
|
244
|
+
|
|
245
|
+
def mock_rails_root(path)
|
|
246
|
+
rails_module = if defined?(Rails)
|
|
247
|
+
Rails
|
|
248
|
+
else
|
|
249
|
+
Object.const_set(:Rails, Module.new)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
rails_module.define_singleton_method(:root) { Pathname.new(path) }
|
|
253
|
+
end
|
|
254
|
+
end
|
data/test/railpack_test.rb
CHANGED
|
@@ -38,104 +38,7 @@ class RailpackTest < Minitest::Test
|
|
|
38
38
|
assert_instance_of Railpack::Manager, Railpack.manager
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def test_bundler_support
|
|
42
|
-
assert_includes Railpack::Manager::BUNDLERS.keys, 'bun'
|
|
43
|
-
assert_includes Railpack::Manager::BUNDLERS.keys, 'esbuild'
|
|
44
|
-
assert_includes Railpack::Manager::BUNDLERS.keys, 'rollup'
|
|
45
|
-
assert_includes Railpack::Manager::BUNDLERS.keys, 'webpack'
|
|
46
|
-
assert_equal Railpack::BunBundler, Railpack::Manager::BUNDLERS['bun']
|
|
47
|
-
assert_equal Railpack::EsbuildBundler, Railpack::Manager::BUNDLERS['esbuild']
|
|
48
|
-
assert_equal Railpack::RollupBundler, Railpack::Manager::BUNDLERS['rollup']
|
|
49
|
-
assert_equal Railpack::WebpackBundler, Railpack::Manager::BUNDLERS['webpack']
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def test_manager_bundle_size_calculation
|
|
55
|
-
# Create test output directory with fake assets
|
|
56
|
-
outdir = File.join(@temp_dir, 'builds')
|
|
57
|
-
FileUtils.mkdir_p(outdir)
|
|
58
|
-
|
|
59
|
-
# Create fake JS and CSS files
|
|
60
|
-
File.write(File.join(outdir, 'app.js'), 'console.log("test");')
|
|
61
|
-
File.write(File.join(outdir, 'app.css'), 'body { color: red; }')
|
|
62
|
-
File.write(File.join(outdir, 'app.js.map'), '{"version":3}')
|
|
63
|
-
|
|
64
|
-
config = { 'outdir' => outdir }
|
|
65
|
-
manager = Railpack::Manager.new
|
|
66
|
-
|
|
67
|
-
size = manager.send(:calculate_bundle_size, config)
|
|
68
|
-
assert size.is_a?(Float)
|
|
69
|
-
assert size > 0
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def test_manager_asset_manifest_generation
|
|
73
|
-
outdir = File.join(@temp_dir, 'builds')
|
|
74
|
-
FileUtils.mkdir_p(outdir)
|
|
75
|
-
|
|
76
|
-
# Create fake built assets
|
|
77
|
-
File.write(File.join(outdir, 'application.js'), 'console.log("app");')
|
|
78
|
-
File.write(File.join(outdir, 'application.css'), 'body { color: blue; }')
|
|
79
|
-
|
|
80
|
-
config = { 'outdir' => outdir }
|
|
81
|
-
manager = Railpack::Manager.new
|
|
82
|
-
|
|
83
|
-
manager.send(:generate_asset_manifest, config)
|
|
84
41
|
|
|
85
|
-
manifest_path = File.join(outdir, '.manifest.json')
|
|
86
|
-
assert File.exist?(manifest_path)
|
|
87
|
-
|
|
88
|
-
manifest = JSON.parse(File.read(manifest_path))
|
|
89
|
-
assert manifest.key?('application.js')
|
|
90
|
-
assert manifest.key?('application.css')
|
|
91
|
-
assert manifest['application.js']['logical_path'] == 'application.js'
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def test_bundler_base_class
|
|
95
|
-
bundler = Railpack::Bundler.new({})
|
|
96
|
-
|
|
97
|
-
assert_respond_to bundler, :build!
|
|
98
|
-
assert_respond_to bundler, :watch
|
|
99
|
-
assert_respond_to bundler, :install!
|
|
100
|
-
assert_respond_to bundler, :name
|
|
101
|
-
assert_respond_to bundler, :commands
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def test_bun_bundler_commands
|
|
105
|
-
bundler = Railpack::BunBundler.new({})
|
|
106
|
-
commands = bundler.send(:commands)
|
|
107
|
-
|
|
108
|
-
assert_equal 'bun run build', commands[:build]
|
|
109
|
-
assert_equal 'bun run watch', commands[:watch]
|
|
110
|
-
assert_equal 'bun install', commands[:install]
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def test_esbuild_bundler_commands
|
|
114
|
-
bundler = Railpack::EsbuildBundler.new({})
|
|
115
|
-
commands = bundler.send(:commands)
|
|
116
|
-
|
|
117
|
-
assert_equal 'esbuild', commands[:build]
|
|
118
|
-
assert_equal 'esbuild --watch', commands[:watch]
|
|
119
|
-
assert_equal 'npm install', commands[:install]
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def test_rollup_bundler_commands
|
|
123
|
-
bundler = Railpack::RollupBundler.new({})
|
|
124
|
-
commands = bundler.send(:commands)
|
|
125
|
-
|
|
126
|
-
assert_equal 'rollup', commands[:build]
|
|
127
|
-
assert_equal 'rollup --watch', commands[:watch]
|
|
128
|
-
assert_equal 'npm install', commands[:install]
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def test_webpack_bundler_commands
|
|
132
|
-
bundler = Railpack::WebpackBundler.new({})
|
|
133
|
-
commands = bundler.send(:commands)
|
|
134
|
-
|
|
135
|
-
assert_equal 'webpack', commands[:build]
|
|
136
|
-
assert_equal 'webpack --watch', commands[:watch]
|
|
137
|
-
assert_equal 'npm install', commands[:install]
|
|
138
|
-
end
|
|
139
42
|
|
|
140
43
|
def test_event_hooks
|
|
141
44
|
events = []
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: railpack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- 21tycoons LLC
|
|
@@ -48,6 +48,9 @@ files:
|
|
|
48
48
|
- lib/railpack/version.rb
|
|
49
49
|
- lib/tasks/railpack.rake
|
|
50
50
|
- sig/railpack.rbs
|
|
51
|
+
- test/bundler_test.rb
|
|
52
|
+
- test/config_test.rb
|
|
53
|
+
- test/manager_test.rb
|
|
51
54
|
- test/railpack_test.rb
|
|
52
55
|
homepage: https://github.com/21tycoons/railpack
|
|
53
56
|
licenses:
|