shakapacker 9.3.0.beta.2 → 9.3.0.beta.4
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/ESLINT_TECHNICAL_DEBT.md +13 -14
- data/Gemfile.lock +1 -1
- data/README.md +9 -6
- data/docs/configuration.md +101 -0
- data/docs/preventing_fouc.md +132 -0
- data/docs/troubleshooting.md +4 -0
- data/eslint.config.js +2 -6
- data/lib/shakapacker/build_config_loader.rb +147 -0
- data/lib/shakapacker/configuration.rb +6 -2
- data/lib/shakapacker/dev_server_runner.rb +73 -0
- data/lib/shakapacker/runner.rb +239 -14
- data/lib/shakapacker/version.rb +1 -1
- data/package/configExporter/buildValidator.ts +2 -2
- data/package/configExporter/cli.ts +251 -160
- data/package/configExporter/configFile.ts +182 -46
- data/package/configExporter/fileWriter.ts +8 -1
- data/package/configExporter/types.ts +2 -0
- data/package/utils/pathValidation.ts +3 -3
- data/package-lock.json +2 -2
- data/package.json +1 -1
- data/test/configExporter/configFile.test.js +3 -2
- data/test/configExporter/integration.test.js +14 -27
- metadata +6 -4
- /data/bin/{export-bundler-config → shakapacker-config} +0 -0
- /data/lib/install/bin/{export-bundler-config → shakapacker-config} +0 -0
@@ -18,9 +18,71 @@ module Shakapacker
|
|
18
18
|
exit(0)
|
19
19
|
end
|
20
20
|
|
21
|
+
# Check for --build flag
|
22
|
+
build_index = argv.index("--build")
|
23
|
+
if build_index
|
24
|
+
build_name = argv[build_index + 1]
|
25
|
+
|
26
|
+
unless build_name
|
27
|
+
$stderr.puts "[Shakapacker] Error: --build requires a build name"
|
28
|
+
$stderr.puts "Usage: bin/shakapacker-dev-server --build <name>"
|
29
|
+
exit(1)
|
30
|
+
end
|
31
|
+
|
32
|
+
loader = BuildConfigLoader.new
|
33
|
+
|
34
|
+
unless loader.exists?
|
35
|
+
$stderr.puts "[Shakapacker] Config file not found: #{loader.config_file_path}"
|
36
|
+
$stderr.puts "Run 'bin/shakapacker --init' to create one"
|
37
|
+
exit(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
build_config = loader.resolve_build_config(build_name)
|
42
|
+
|
43
|
+
# Check if this build is meant for dev server
|
44
|
+
unless loader.uses_dev_server?(build_config)
|
45
|
+
$stderr.puts "[Shakapacker] Error: Build '#{build_name}' is not configured for dev server (dev_server: false)"
|
46
|
+
$stderr.puts "[Shakapacker] Use this command instead:"
|
47
|
+
$stderr.puts " bin/shakapacker --build #{build_name}"
|
48
|
+
exit(1)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Remove --build and build name from argv
|
52
|
+
remaining_argv = argv.dup
|
53
|
+
remaining_argv.delete_at(build_index + 1)
|
54
|
+
remaining_argv.delete_at(build_index)
|
55
|
+
|
56
|
+
run_with_build_config(remaining_argv, build_config)
|
57
|
+
return
|
58
|
+
rescue ArgumentError => e
|
59
|
+
$stderr.puts "[Shakapacker] #{e.message}"
|
60
|
+
exit(1)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
21
64
|
new(argv).run
|
22
65
|
end
|
23
66
|
|
67
|
+
def self.run_with_build_config(argv, build_config)
|
68
|
+
# Apply build config environment variables
|
69
|
+
build_config[:environment].each do |key, value|
|
70
|
+
ENV[key] = value.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
# Set SHAKAPACKER_ASSETS_BUNDLER so JS/TS config files use the correct bundler
|
74
|
+
# This ensures the bundler override (from --bundler or build config) is respected
|
75
|
+
ENV["SHAKAPACKER_ASSETS_BUNDLER"] = build_config[:bundler]
|
76
|
+
|
77
|
+
puts "[Shakapacker] Running dev server for build: #{build_config[:name]}"
|
78
|
+
puts "[Shakapacker] Description: #{build_config[:description]}" if build_config[:description]
|
79
|
+
puts "[Shakapacker] Bundler: #{build_config[:bundler]}"
|
80
|
+
puts "[Shakapacker] Config file: #{build_config[:config_file]}" if build_config[:config_file]
|
81
|
+
|
82
|
+
# Pass bundler override so Configuration.assets_bundler reflects the build
|
83
|
+
new(argv, build_config, build_config[:bundler]).run
|
84
|
+
end
|
85
|
+
|
24
86
|
def self.print_help
|
25
87
|
puts <<~HELP
|
26
88
|
================================================================================
|
@@ -33,6 +95,17 @@ module Shakapacker
|
|
33
95
|
-h, --help Show this help message
|
34
96
|
-v, --version Show Shakapacker version
|
35
97
|
--debug-shakapacker Enable Node.js debugging (--inspect-brk)
|
98
|
+
--build <name> Run a specific build configuration
|
99
|
+
|
100
|
+
Build configurations (config/shakapacker-builds.yml):
|
101
|
+
bin/shakapacker-dev-server --build dev-hmr # Run the 'dev-hmr' build
|
102
|
+
|
103
|
+
To manage builds:
|
104
|
+
bin/shakapacker --init # Create config file
|
105
|
+
bin/shakapacker --list-builds # List available builds
|
106
|
+
|
107
|
+
Note: You can also use bin/shakapacker --build with a build that has
|
108
|
+
WEBPACK_SERVE=true, and it will automatically use the dev server.
|
36
109
|
|
37
110
|
Examples:
|
38
111
|
bin/shakapacker-dev-server # Start dev server
|
data/lib/shakapacker/runner.rb
CHANGED
@@ -2,6 +2,7 @@ require_relative "utils/misc"
|
|
2
2
|
require_relative "utils/manager"
|
3
3
|
require_relative "configuration"
|
4
4
|
require_relative "version"
|
5
|
+
require_relative "build_config_loader"
|
5
6
|
|
6
7
|
require "package_json"
|
7
8
|
require "pathname"
|
@@ -34,15 +35,109 @@ module Shakapacker
|
|
34
35
|
elsif argv.include?("--version") || argv.include?("-v")
|
35
36
|
print_version
|
36
37
|
exit(0)
|
38
|
+
elsif argv.include?("--init")
|
39
|
+
init_config_file
|
40
|
+
exit(0)
|
41
|
+
elsif argv.include?("--list-builds")
|
42
|
+
list_builds
|
43
|
+
exit(0)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Check for --bundler flag
|
47
|
+
bundler_override = nil
|
48
|
+
bundler_index = argv.index("--bundler")
|
49
|
+
if bundler_index
|
50
|
+
bundler_value = argv[bundler_index + 1]
|
51
|
+
unless bundler_value && %w[webpack rspack].include?(bundler_value)
|
52
|
+
$stderr.puts "[Shakapacker] Error: --bundler requires 'webpack' or 'rspack'"
|
53
|
+
$stderr.puts "Usage: bin/shakapacker --bundler <webpack|rspack>"
|
54
|
+
exit(1)
|
55
|
+
end
|
56
|
+
bundler_override = bundler_value
|
57
|
+
end
|
58
|
+
|
59
|
+
# Check for --build flag
|
60
|
+
build_index = argv.index("--build")
|
61
|
+
if build_index
|
62
|
+
build_name = argv[build_index + 1]
|
63
|
+
|
64
|
+
unless build_name
|
65
|
+
$stderr.puts "[Shakapacker] Error: --build requires a build name"
|
66
|
+
$stderr.puts "Usage: bin/shakapacker --build <name>"
|
67
|
+
exit(1)
|
68
|
+
end
|
69
|
+
|
70
|
+
loader = BuildConfigLoader.new
|
71
|
+
|
72
|
+
unless loader.exists?
|
73
|
+
$stderr.puts "[Shakapacker] Config file not found: #{loader.config_file_path}"
|
74
|
+
$stderr.puts "Run 'bin/shakapacker --init' to create one"
|
75
|
+
exit(1)
|
76
|
+
end
|
77
|
+
|
78
|
+
begin
|
79
|
+
# Pass bundler override to resolve_build_config
|
80
|
+
resolve_opts = {}
|
81
|
+
resolve_opts[:default_bundler] = bundler_override if bundler_override
|
82
|
+
build_config = loader.resolve_build_config(build_name, **resolve_opts)
|
83
|
+
|
84
|
+
# Remove --build and build name from argv
|
85
|
+
remaining_argv = argv.dup
|
86
|
+
remaining_argv.delete_at(build_index + 1)
|
87
|
+
remaining_argv.delete_at(build_index)
|
88
|
+
|
89
|
+
# Remove --bundler and bundler value from argv if present
|
90
|
+
if bundler_index
|
91
|
+
bundler_idx_in_remaining = remaining_argv.index("--bundler")
|
92
|
+
if bundler_idx_in_remaining
|
93
|
+
remaining_argv.delete_at(bundler_idx_in_remaining + 1)
|
94
|
+
remaining_argv.delete_at(bundler_idx_in_remaining)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# If this build uses dev server, delegate to DevServerRunner
|
99
|
+
if loader.uses_dev_server?(build_config)
|
100
|
+
$stdout.puts "[Shakapacker] Build '#{build_name}' requires dev server"
|
101
|
+
$stdout.puts "[Shakapacker] Running: bin/shakapacker-dev-server --build #{build_name}"
|
102
|
+
$stdout.puts ""
|
103
|
+
require_relative "dev_server_runner"
|
104
|
+
DevServerRunner.run_with_build_config(remaining_argv, build_config)
|
105
|
+
return
|
106
|
+
end
|
107
|
+
|
108
|
+
# Otherwise run with this build config
|
109
|
+
run_with_build_config(remaining_argv, build_config)
|
110
|
+
return
|
111
|
+
rescue ArgumentError => e
|
112
|
+
$stderr.puts "[Shakapacker] #{e.message}"
|
113
|
+
exit(1)
|
114
|
+
end
|
37
115
|
end
|
38
116
|
|
39
117
|
Shakapacker.ensure_node_env!
|
40
118
|
|
119
|
+
# Remove --bundler flag from argv if present (not using --build)
|
120
|
+
remaining_argv = argv.dup
|
121
|
+
if bundler_index
|
122
|
+
bundler_idx = remaining_argv.index("--bundler")
|
123
|
+
if bundler_idx
|
124
|
+
remaining_argv.delete_at(bundler_idx + 1)
|
125
|
+
remaining_argv.delete_at(bundler_idx)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Set SHAKAPACKER_ASSETS_BUNDLER if bundler override is specified
|
130
|
+
# This ensures JS/TS config files use the correct bundler
|
131
|
+
ENV["SHAKAPACKER_ASSETS_BUNDLER"] = bundler_override if bundler_override
|
132
|
+
|
41
133
|
# Create a single runner instance to avoid loading configuration twice.
|
42
134
|
# We extend it with the appropriate build command based on the bundler type.
|
43
|
-
runner = new(
|
135
|
+
runner = new(remaining_argv, nil, bundler_override)
|
136
|
+
|
137
|
+
# Determine which bundler to use (override takes precedence)
|
138
|
+
use_rspack = bundler_override ? (bundler_override == "rspack") : runner.config.rspack?
|
44
139
|
|
45
|
-
if
|
140
|
+
if use_rspack
|
46
141
|
require_relative "rspack_runner"
|
47
142
|
# Extend the runner instance with rspack-specific methods
|
48
143
|
# This avoids creating a new RspackRunner which would reload the configuration
|
@@ -69,17 +164,71 @@ module Shakapacker
|
|
69
164
|
end
|
70
165
|
end
|
71
166
|
|
72
|
-
def
|
167
|
+
def self.run_with_build_config(argv, build_config)
|
168
|
+
$stdout.sync = true
|
169
|
+
Shakapacker.ensure_node_env!
|
170
|
+
|
171
|
+
# Apply build config environment variables
|
172
|
+
build_config[:environment].each do |key, value|
|
173
|
+
ENV[key] = value.to_s
|
174
|
+
end
|
175
|
+
|
176
|
+
# Set SHAKAPACKER_ASSETS_BUNDLER so JS/TS config files use the correct bundler
|
177
|
+
# This ensures the bundler override (from --bundler or build config) is respected
|
178
|
+
ENV["SHAKAPACKER_ASSETS_BUNDLER"] = build_config[:bundler]
|
179
|
+
|
180
|
+
puts "[Shakapacker] Running build: #{build_config[:name]}"
|
181
|
+
puts "[Shakapacker] Description: #{build_config[:description]}" if build_config[:description]
|
182
|
+
puts "[Shakapacker] Bundler: #{build_config[:bundler]}"
|
183
|
+
puts "[Shakapacker] Config file: #{build_config[:config_file]}" if build_config[:config_file]
|
184
|
+
|
185
|
+
# Create runner with modified argv and bundler from build_config
|
186
|
+
# The build_config[:bundler] already has any CLI --bundler override applied
|
187
|
+
runner = new(argv, build_config, build_config[:bundler])
|
188
|
+
|
189
|
+
# Use bundler from build_config (which includes CLI override)
|
190
|
+
if build_config[:bundler] == "rspack"
|
191
|
+
require_relative "rspack_runner"
|
192
|
+
runner.extend(Module.new do
|
193
|
+
def build_cmd
|
194
|
+
package_json.manager.native_exec_command("rspack")
|
195
|
+
end
|
196
|
+
|
197
|
+
def assets_bundler_commands
|
198
|
+
BASE_COMMANDS + %w[build watch]
|
199
|
+
end
|
200
|
+
end)
|
201
|
+
runner.run
|
202
|
+
else
|
203
|
+
require_relative "webpack_runner"
|
204
|
+
runner.extend(Module.new do
|
205
|
+
def build_cmd
|
206
|
+
package_json.manager.native_exec_command("webpack")
|
207
|
+
end
|
208
|
+
end)
|
209
|
+
runner.run
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def initialize(argv, build_config = nil, bundler_override = nil)
|
73
214
|
@argv = argv
|
215
|
+
@build_config = build_config
|
216
|
+
@bundler_override = bundler_override
|
217
|
+
|
218
|
+
@app_path = File.expand_path(".", Dir.pwd)
|
219
|
+
@shakapacker_config = ENV["SHAKAPACKER_CONFIG"] || File.join(@app_path, "config/shakapacker.yml")
|
74
220
|
|
75
|
-
|
76
|
-
|
77
|
-
@config = Configuration.new(
|
221
|
+
# Create config with bundler override if provided
|
222
|
+
config_opts = {
|
78
223
|
root_path: Pathname.new(@app_path),
|
79
224
|
config_path: Pathname.new(@shakapacker_config),
|
80
225
|
env: ENV["RAILS_ENV"] || ENV["NODE_ENV"] || "development"
|
81
|
-
|
82
|
-
|
226
|
+
}
|
227
|
+
config_opts[:bundler_override] = bundler_override if bundler_override
|
228
|
+
|
229
|
+
@config = Configuration.new(**config_opts)
|
230
|
+
|
231
|
+
@webpack_config = find_webpack_config_from_build_or_default
|
83
232
|
|
84
233
|
Shakapacker::Utils::Manager.error_unless_package_manager_is_obvious!
|
85
234
|
end
|
@@ -175,13 +324,26 @@ module Shakapacker
|
|
175
324
|
--debug-shakapacker Enable Node.js debugging (--inspect-brk)
|
176
325
|
--trace-deprecation Show stack traces for deprecations
|
177
326
|
--no-deprecation Silence deprecation warnings
|
327
|
+
--bundler <webpack|rspack>
|
328
|
+
Override bundler (defaults to shakapacker.yml)
|
178
329
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
330
|
+
Build configurations (config/shakapacker-builds.yml):
|
331
|
+
--init Create config/shakapacker-builds.yml
|
332
|
+
--list-builds List available builds
|
333
|
+
--build <name> Run a specific build configuration
|
334
|
+
|
335
|
+
Examples (build configs):
|
336
|
+
bin/shakapacker --init # Create config file
|
337
|
+
bin/shakapacker --list-builds # Show available builds
|
338
|
+
bin/shakapacker --build dev-hmr # Run the 'dev-hmr' build
|
339
|
+
bin/shakapacker --build prod # Run the 'prod' build
|
340
|
+
bin/shakapacker --build prod --bundler rspack # Override to use rspack
|
341
|
+
|
342
|
+
Note: If a build has dev_server: true in its config, it will
|
343
|
+
automatically use bin/shakapacker-dev-server instead.
|
344
|
+
|
345
|
+
Advanced: Use bin/shakapacker-config for more config management options
|
346
|
+
(validate builds, export configs, etc.)
|
185
347
|
|
186
348
|
HELP
|
187
349
|
|
@@ -189,6 +351,14 @@ module Shakapacker
|
|
189
351
|
|
190
352
|
puts <<~HELP
|
191
353
|
|
354
|
+
Examples (passing options to webpack/rspack):
|
355
|
+
bin/shakapacker # Build for production
|
356
|
+
bin/shakapacker --bundler rspack # Build with rspack instead of webpack
|
357
|
+
bin/shakapacker --mode development # Build for development
|
358
|
+
bin/shakapacker --watch # Watch mode
|
359
|
+
bin/shakapacker --mode development --analyze # Development build with analysis
|
360
|
+
bin/shakapacker --debug-shakapacker # Debug with Node inspector
|
361
|
+
|
192
362
|
Options managed by Shakapacker (configured via config files):
|
193
363
|
--config Set automatically based on assets_bundler_config_path
|
194
364
|
(defaults to config/webpack or config/rspack)
|
@@ -301,6 +471,52 @@ module Shakapacker
|
|
301
471
|
end
|
302
472
|
end
|
303
473
|
|
474
|
+
def self.init_config_file
|
475
|
+
loader = BuildConfigLoader.new
|
476
|
+
config_path = loader.config_file_path
|
477
|
+
|
478
|
+
if loader.exists?
|
479
|
+
puts "[Shakapacker] Config file already exists: #{config_path}"
|
480
|
+
puts "Use --list-builds to see available builds"
|
481
|
+
return
|
482
|
+
end
|
483
|
+
|
484
|
+
# Delegate to bin/shakapacker-config
|
485
|
+
app_path = File.expand_path(".", Dir.pwd)
|
486
|
+
shakapacker_config_path = File.join(app_path, "bin", "shakapacker-config")
|
487
|
+
|
488
|
+
unless File.exist?(shakapacker_config_path)
|
489
|
+
$stderr.puts "[Shakapacker] Error: bin/shakapacker-config not found"
|
490
|
+
$stderr.puts "Please ensure Shakapacker is properly installed"
|
491
|
+
exit(1)
|
492
|
+
end
|
493
|
+
|
494
|
+
# Run the init command and check if it succeeded
|
495
|
+
unless system(shakapacker_config_path, "--init")
|
496
|
+
exit_code = $?.exitstatus || 1
|
497
|
+
$stderr.puts "[Shakapacker] Error: Failed to run: #{shakapacker_config_path} --init"
|
498
|
+
$stderr.puts "[Shakapacker] Command exited with status: #{exit_code}"
|
499
|
+
exit(exit_code)
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
def self.list_builds
|
504
|
+
loader = BuildConfigLoader.new
|
505
|
+
|
506
|
+
unless loader.exists?
|
507
|
+
puts "[Shakapacker] No config file found: #{loader.config_file_path}"
|
508
|
+
puts "Run 'bin/shakapacker --init' to create one"
|
509
|
+
return
|
510
|
+
end
|
511
|
+
|
512
|
+
begin
|
513
|
+
loader.list_builds
|
514
|
+
rescue ArgumentError => e
|
515
|
+
$stderr.puts "[Shakapacker] Error: #{e.message}"
|
516
|
+
exit(1)
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
304
520
|
def self.get_bundler_version
|
305
521
|
execute_bundler_command("--version") { |stdout| stdout.strip }
|
306
522
|
end
|
@@ -356,6 +572,15 @@ module Shakapacker
|
|
356
572
|
end
|
357
573
|
|
358
574
|
private
|
575
|
+
|
576
|
+
def find_webpack_config_from_build_or_default
|
577
|
+
if @build_config && @build_config[:config_file]
|
578
|
+
File.join(@app_path, @build_config[:config_file])
|
579
|
+
else
|
580
|
+
find_assets_bundler_config
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
359
584
|
def find_assets_bundler_config
|
360
585
|
if @config.rspack?
|
361
586
|
find_rspack_config_with_fallback
|
data/lib/shakapacker/version.rb
CHANGED
@@ -865,13 +865,13 @@ export class BuildValidator {
|
|
865
865
|
const failedBuilds = results.filter((r) => !r.success)
|
866
866
|
failedBuilds.forEach((result) => {
|
867
867
|
lines.push(
|
868
|
-
` bin/
|
868
|
+
` bin/shakapacker-config --validate-build ${result.buildName} --verbose`
|
869
869
|
)
|
870
870
|
})
|
871
871
|
|
872
872
|
lines.push("")
|
873
873
|
lines.push(
|
874
|
-
" Or validate all builds with full output: bin/
|
874
|
+
" Or validate all builds with full output: bin/shakapacker-config --validate --verbose"
|
875
875
|
)
|
876
876
|
lines.push("=".repeat(80))
|
877
877
|
}
|