shakapacker 9.2.0 → 9.3.0.beta.0
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/.github/ISSUE_TEMPLATE/bug_report.md +6 -9
- data/.github/ISSUE_TEMPLATE/feature_request.md +6 -8
- data/.github/workflows/claude-code-review.yml +4 -5
- data/.github/workflows/claude.yml +1 -2
- data/.github/workflows/dummy.yml +4 -4
- data/.github/workflows/generator.yml +9 -9
- data/.github/workflows/node.yml +11 -2
- data/.github/workflows/ruby.yml +16 -16
- data/.github/workflows/test-bundlers.yml +9 -9
- data/.gitignore +4 -0
- data/CHANGELOG.md +19 -4
- data/CLAUDE.md +6 -1
- data/CONTRIBUTING.md +0 -1
- data/Gemfile.lock +1 -1
- data/README.md +14 -14
- data/TODO.md +10 -2
- data/TODO_v9.md +13 -3
- data/bin/export-bundler-config +1 -1
- data/conductor-setup.sh +1 -1
- data/conductor.json +1 -1
- data/docs/cdn_setup.md +13 -8
- data/docs/common-upgrades.md +2 -1
- data/docs/configuration.md +630 -0
- data/docs/css-modules-export-mode.md +120 -100
- data/docs/customizing_babel_config.md +16 -16
- data/docs/deployment.md +18 -0
- data/docs/developing_shakapacker.md +6 -0
- data/docs/optional-peer-dependencies.md +9 -4
- data/docs/peer-dependencies.md +17 -6
- data/docs/precompile_hook.md +342 -0
- data/docs/react.md +57 -47
- data/docs/releasing.md +0 -2
- data/docs/rspack.md +25 -21
- data/docs/rspack_migration_guide.md +335 -8
- data/docs/sprockets.md +1 -0
- data/docs/style_loader_vs_mini_css.md +12 -12
- data/docs/subresource_integrity.md +13 -7
- data/docs/transpiler-performance.md +40 -19
- data/docs/troubleshooting.md +0 -2
- data/docs/typescript-migration.md +48 -39
- data/docs/typescript.md +12 -8
- data/docs/using_esbuild_loader.md +10 -10
- data/docs/v6_upgrade.md +33 -20
- data/docs/v7_upgrade.md +8 -6
- data/docs/v8_upgrade.md +13 -12
- data/docs/v9_upgrade.md +2 -1
- data/eslint.config.fast.js +134 -0
- data/eslint.config.js +140 -0
- data/knip.ts +54 -0
- data/lib/install/bin/export-bundler-config +1 -1
- data/lib/install/config/shakapacker.yml +16 -5
- data/lib/shakapacker/compiler.rb +80 -0
- data/lib/shakapacker/configuration.rb +33 -5
- data/lib/shakapacker/dev_server_runner.rb +140 -1
- data/lib/shakapacker/doctor.rb +294 -65
- data/lib/shakapacker/instance.rb +8 -3
- data/lib/shakapacker/runner.rb +244 -8
- data/lib/shakapacker/version.rb +1 -1
- data/lib/tasks/shakapacker/doctor.rake +42 -2
- data/package/babel/preset.ts +7 -4
- data/package/config.ts +42 -30
- data/package/configExporter/cli.ts +799 -208
- data/package/configExporter/configFile.ts +520 -0
- data/package/configExporter/fileWriter.ts +12 -8
- data/package/configExporter/index.ts +9 -1
- data/package/configExporter/types.ts +36 -2
- data/package/configExporter/yamlSerializer.ts +22 -8
- data/package/dev_server.ts +1 -1
- data/package/environments/__type-tests__/rspack-plugin-compatibility.ts +11 -5
- data/package/environments/base.ts +18 -13
- data/package/environments/development.ts +1 -1
- data/package/environments/production.ts +4 -1
- data/package/index.d.ts +50 -3
- data/package/index.d.ts.template +50 -0
- data/package/index.ts +7 -7
- data/package/loaders.d.ts +2 -2
- data/package/optimization/rspack.ts +1 -1
- data/package/plugins/rspack.ts +15 -4
- data/package/plugins/webpack.ts +7 -3
- data/package/rspack/index.ts +10 -2
- data/package/rules/raw.ts +3 -2
- data/package/rules/sass.ts +1 -1
- data/package/types/README.md +15 -13
- data/package/types/index.ts +5 -5
- data/package/types.ts +0 -1
- data/package/utils/defaultConfigPath.ts +4 -1
- data/package/utils/errorCodes.ts +129 -100
- data/package/utils/errorHelpers.ts +34 -29
- data/package/utils/getStyleRule.ts +5 -2
- data/package/utils/helpers.ts +21 -11
- data/package/utils/pathValidation.ts +43 -35
- data/package/utils/requireOrError.ts +1 -1
- data/package/utils/snakeToCamelCase.ts +1 -1
- data/package/utils/typeGuards.ts +132 -83
- data/package/utils/validateDependencies.ts +1 -1
- data/package/webpack-types.d.ts +3 -3
- data/package/webpackDevServerConfig.ts +22 -10
- data/package-lock.json +2 -2
- data/package.json +36 -28
- data/scripts/type-check-no-emit.js +1 -1
- data/test/configExporter/configFile.test.js +392 -0
- data/test/configExporter/integration.test.js +275 -0
- data/test/helpers.js +1 -1
- data/test/package/configExporter.test.js +154 -0
- data/test/package/helpers.test.js +2 -2
- data/test/package/rules/sass-version-parsing.test.js +71 -0
- data/test/package/rules/sass.test.js +2 -4
- data/test/package/rules/sass1.test.js +1 -3
- data/test/package/rules/sass16.test.js +23 -0
- data/tools/README.md +15 -5
- data/tsconfig.eslint.json +2 -9
- data/yarn.lock +1894 -1492
- metadata +19 -3
- data/.eslintignore +0 -5
data/lib/shakapacker/runner.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require_relative "utils/misc"
|
2
2
|
require_relative "utils/manager"
|
3
3
|
require_relative "configuration"
|
4
|
+
require_relative "version"
|
4
5
|
|
5
6
|
require "package_json"
|
6
7
|
require "pathname"
|
8
|
+
require "stringio"
|
7
9
|
|
8
10
|
module Shakapacker
|
9
11
|
class Runner
|
@@ -24,6 +26,16 @@ module Shakapacker
|
|
24
26
|
].freeze
|
25
27
|
def self.run(argv)
|
26
28
|
$stdout.sync = true
|
29
|
+
|
30
|
+
# Show Shakapacker help and exit (don't call bundler)
|
31
|
+
if argv.include?("--help") || argv.include?("-h")
|
32
|
+
print_help
|
33
|
+
exit(0)
|
34
|
+
elsif argv.include?("--version") || argv.include?("-v")
|
35
|
+
print_version
|
36
|
+
exit(0)
|
37
|
+
end
|
38
|
+
|
27
39
|
Shakapacker.ensure_node_env!
|
28
40
|
|
29
41
|
# Create a single runner instance to avoid loading configuration twice.
|
@@ -112,9 +124,22 @@ module Shakapacker
|
|
112
124
|
puts "[Shakapacker] Final command: #{cmd.join(" ")}"
|
113
125
|
puts "[Shakapacker] Working directory: #{@app_path}"
|
114
126
|
|
127
|
+
watch_mode = @argv.include?("--watch") || @argv.include?("-w")
|
128
|
+
start_time = Time.now unless watch_mode
|
129
|
+
|
115
130
|
Dir.chdir(@app_path) do
|
116
|
-
|
131
|
+
system(env, *cmd)
|
117
132
|
end
|
133
|
+
|
134
|
+
if !watch_mode && start_time
|
135
|
+
bundler_name = @config.rspack? ? "rspack" : "webpack"
|
136
|
+
elapsed_time = Time.now - start_time
|
137
|
+
minutes = (elapsed_time / 60).floor
|
138
|
+
seconds = (elapsed_time % 60).round(2)
|
139
|
+
time_display = minutes > 0 ? "#{minutes}:#{format('%05.2f', seconds)}s" : "#{elapsed_time.round(2)}s"
|
140
|
+
puts "[Shakapacker] Completed #{bundler_name} build in #{time_display} (#{elapsed_time.round(2)}s)"
|
141
|
+
end
|
142
|
+
exit($?.exitstatus || 1) unless $?.success?
|
118
143
|
end
|
119
144
|
|
120
145
|
protected
|
@@ -123,6 +148,213 @@ module Shakapacker
|
|
123
148
|
BASE_COMMANDS
|
124
149
|
end
|
125
150
|
|
151
|
+
def print_config_not_found_error(bundler_type, config_path, config_dir)
|
152
|
+
$stderr.puts "[Shakapacker] ERROR: #{bundler_type} config #{config_path} not found."
|
153
|
+
$stderr.puts ""
|
154
|
+
$stderr.puts "Please run 'bundle exec rails shakapacker:install' to install Shakapacker with default configs,"
|
155
|
+
$stderr.puts "or create the missing config file."
|
156
|
+
$stderr.puts ""
|
157
|
+
$stderr.puts "If your config file is in a different location, you can configure it in config/shakapacker.yml:"
|
158
|
+
$stderr.puts ""
|
159
|
+
$stderr.puts " assets_bundler_config_path: your/custom/path"
|
160
|
+
$stderr.puts ""
|
161
|
+
$stderr.puts "Current configured path: #{config_dir}"
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.print_help
|
165
|
+
puts <<~HELP
|
166
|
+
================================================================================
|
167
|
+
SHAKAPACKER - Rails Webpack/Rspack Integration
|
168
|
+
================================================================================
|
169
|
+
|
170
|
+
Usage: bin/shakapacker [options]
|
171
|
+
|
172
|
+
Shakapacker-specific options:
|
173
|
+
-h, --help Show this help message
|
174
|
+
-v, --version Show Shakapacker version
|
175
|
+
--debug-shakapacker Enable Node.js debugging (--inspect-brk)
|
176
|
+
--trace-deprecation Show stack traces for deprecations
|
177
|
+
--no-deprecation Silence deprecation warnings
|
178
|
+
|
179
|
+
Examples:
|
180
|
+
bin/shakapacker # Build for production
|
181
|
+
bin/shakapacker --mode development # Build for development
|
182
|
+
bin/shakapacker --watch # Watch mode
|
183
|
+
bin/shakapacker --mode development --analyze # Development build with analysis
|
184
|
+
bin/shakapacker --debug-shakapacker # Debug with Node inspector
|
185
|
+
|
186
|
+
HELP
|
187
|
+
|
188
|
+
print_bundler_help
|
189
|
+
|
190
|
+
puts <<~HELP
|
191
|
+
|
192
|
+
Options managed by Shakapacker (configured via config files):
|
193
|
+
--config Set automatically based on assets_bundler_config_path
|
194
|
+
(defaults to config/webpack or config/rspack)
|
195
|
+
--node-env Set from RAILS_ENV or NODE_ENV
|
196
|
+
HELP
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.print_bundler_help
|
200
|
+
bundler_type, bundler_help = get_bundler_help
|
201
|
+
|
202
|
+
if bundler_help
|
203
|
+
bundler_name = bundler_type == :rspack ? "RSPACK" : "WEBPACK"
|
204
|
+
puts "=" * 80
|
205
|
+
puts "AVAILABLE #{bundler_name} OPTIONS (Passed directly to #{bundler_name.downcase})"
|
206
|
+
puts "=" * 80
|
207
|
+
puts
|
208
|
+
puts filter_managed_options(bundler_help)
|
209
|
+
puts
|
210
|
+
puts "For complete documentation:"
|
211
|
+
if bundler_type == :rspack
|
212
|
+
puts " https://rspack.dev/api/cli"
|
213
|
+
else
|
214
|
+
puts " https://webpack.js.org/api/cli/"
|
215
|
+
end
|
216
|
+
else
|
217
|
+
puts "For complete documentation:"
|
218
|
+
puts " Webpack: https://webpack.js.org/api/cli/"
|
219
|
+
puts " Rspack: https://rspack.dev/api/cli"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.get_bundler_help
|
224
|
+
execute_bundler_command("--help") { |stdout| stdout }
|
225
|
+
end
|
226
|
+
|
227
|
+
# Filter bundler help output to remove Shakapacker-managed options
|
228
|
+
#
|
229
|
+
# This method processes the raw help output from webpack/rspack and removes:
|
230
|
+
# 1. Command sections (e.g., "Commands: webpack build")
|
231
|
+
# 2. Options that Shakapacker manages automatically (--config, --nodeEnv, etc.)
|
232
|
+
# 3. Help/version flags (shown separately in Shakapacker's help)
|
233
|
+
#
|
234
|
+
# The filtering uses stateful line-by-line processing:
|
235
|
+
# - in_commands_section: tracks when we're inside a Commands: block
|
236
|
+
# - skip_until_blank: tracks multi-line option descriptions to skip entirely
|
237
|
+
#
|
238
|
+
# Note: This relies on bundler help format conventions. If webpack/rspack
|
239
|
+
# significantly changes their help output format, this may need adjustment.
|
240
|
+
def self.filter_managed_options(help_text)
|
241
|
+
lines = help_text.lines
|
242
|
+
filtered_lines = []
|
243
|
+
skip_until_blank = false
|
244
|
+
in_commands_section = false
|
245
|
+
|
246
|
+
lines.each do |line|
|
247
|
+
# Skip the [options] line and Commands section headers
|
248
|
+
# These appear in formats like "[options]" or "Commands:"
|
249
|
+
if line.match?(/^\[options\]/) || line.match?(/^Commands:/)
|
250
|
+
in_commands_section = true
|
251
|
+
next
|
252
|
+
end
|
253
|
+
|
254
|
+
# Continue skipping until we exit the commands section
|
255
|
+
# Exit when we hit "Options:" header or double blank lines
|
256
|
+
if in_commands_section
|
257
|
+
if line.match?(/^Options:/) || (line.strip.empty? && filtered_lines.last&.strip&.empty?)
|
258
|
+
in_commands_section = false
|
259
|
+
else
|
260
|
+
next
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Skip options that Shakapacker manages and their descriptions
|
265
|
+
# These options are shown in the "Options managed by Shakapacker" section
|
266
|
+
if line.match?(/^\s*(-c,\s*)?--config\b/) ||
|
267
|
+
line.match?(/^\s*--configName\b/) ||
|
268
|
+
line.match?(/^\s*--configLoader\b/) ||
|
269
|
+
line.match?(/^\s*--nodeEnv\b/) ||
|
270
|
+
line.match?(/^\s*(-h,\s*)?--help\b/) ||
|
271
|
+
line.match?(/^\s*(-v,\s*)?--version\b/)
|
272
|
+
skip_until_blank = true
|
273
|
+
next
|
274
|
+
end
|
275
|
+
|
276
|
+
# Continue skipping lines that are part of a filtered option's description
|
277
|
+
# Reset when we hit a blank line or the start of a new option (starts with -)
|
278
|
+
if skip_until_blank
|
279
|
+
if line.strip.empty? || line.match?(/^\s*-/)
|
280
|
+
skip_until_blank = false
|
281
|
+
else
|
282
|
+
next
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
filtered_lines << line
|
287
|
+
end
|
288
|
+
|
289
|
+
filtered_lines.join
|
290
|
+
end
|
291
|
+
|
292
|
+
def self.print_version
|
293
|
+
puts "Shakapacker #{Shakapacker::VERSION}"
|
294
|
+
puts "Framework: Rails #{Rails.version}" if defined?(Rails)
|
295
|
+
|
296
|
+
# Try to get bundler version
|
297
|
+
bundler_type, bundler_version = get_bundler_version
|
298
|
+
if bundler_version
|
299
|
+
bundler_name = bundler_type == :rspack ? "Rspack" : "Webpack"
|
300
|
+
puts "Bundler: #{bundler_name} #{bundler_version}"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def self.get_bundler_version
|
305
|
+
execute_bundler_command("--version") { |stdout| stdout.strip }
|
306
|
+
end
|
307
|
+
|
308
|
+
# Shared helper to execute bundler commands with output suppression
|
309
|
+
# Returns [bundler_type, processed_output] or [nil, nil] on error
|
310
|
+
#
|
311
|
+
# @param bundler_args [String, Array<String>] Arguments to pass to bundler command
|
312
|
+
# @yield [stdout] Block to process the command output
|
313
|
+
# @yieldparam stdout [String] The raw stdout from the bundler command
|
314
|
+
# @yieldreturn [Object] The processed output to return
|
315
|
+
def self.execute_bundler_command(*bundler_args)
|
316
|
+
# Check if we're in a Rails project with necessary files
|
317
|
+
app_path = File.expand_path(".", Dir.pwd)
|
318
|
+
config_path = ENV["SHAKAPACKER_CONFIG"] || File.join(app_path, "config/shakapacker.yml")
|
319
|
+
return [nil, nil] unless File.exist?(config_path)
|
320
|
+
|
321
|
+
original_stdout = $stdout
|
322
|
+
original_stderr = $stderr
|
323
|
+
|
324
|
+
begin
|
325
|
+
# Suppress any output during config loading
|
326
|
+
$stdout = StringIO.new
|
327
|
+
$stderr = StringIO.new
|
328
|
+
|
329
|
+
# Try to detect bundler type
|
330
|
+
runner = new([])
|
331
|
+
return [nil, nil] unless runner.config
|
332
|
+
|
333
|
+
bundler_type = runner.config.rspack? ? :rspack : :webpack
|
334
|
+
bundler_name = bundler_type == :rspack ? "rspack" : "webpack"
|
335
|
+
cmd = runner.package_json.manager.native_exec_command(bundler_name, bundler_args.flatten)
|
336
|
+
|
337
|
+
# Restore output before running command
|
338
|
+
$stdout = original_stdout
|
339
|
+
$stderr = original_stderr
|
340
|
+
|
341
|
+
# Capture command output
|
342
|
+
require "open3"
|
343
|
+
stdout, _stderr, status = Open3.capture3(*cmd)
|
344
|
+
return [nil, nil] unless status.success?
|
345
|
+
|
346
|
+
# Process output using the provided block
|
347
|
+
processed_output = yield(stdout)
|
348
|
+
[bundler_type, processed_output]
|
349
|
+
rescue StandardError => e
|
350
|
+
[nil, nil]
|
351
|
+
ensure
|
352
|
+
# Always restore output streams
|
353
|
+
$stdout = original_stdout
|
354
|
+
$stderr = original_stderr
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
126
358
|
private
|
127
359
|
def find_assets_bundler_config
|
128
360
|
if @config.rspack?
|
@@ -133,9 +365,11 @@ module Shakapacker
|
|
133
365
|
end
|
134
366
|
|
135
367
|
def find_rspack_config_with_fallback
|
136
|
-
|
368
|
+
config_dir = @config.assets_bundler_config_path
|
369
|
+
|
370
|
+
# First try rspack-specific paths in the configured directory
|
137
371
|
rspack_paths = %w[ts js].map do |ext|
|
138
|
-
File.join(@app_path, "
|
372
|
+
File.join(@app_path, config_dir, "rspack.config.#{ext}")
|
139
373
|
end
|
140
374
|
|
141
375
|
puts "[Shakapacker] Looking for Rspack config in: #{rspack_paths.join(", ")}"
|
@@ -147,31 +381,33 @@ module Shakapacker
|
|
147
381
|
|
148
382
|
# Fallback to webpack config with deprecation warning
|
149
383
|
webpack_paths = %w[ts js].map do |ext|
|
150
|
-
File.join(@app_path, "
|
384
|
+
File.join(@app_path, config_dir, "webpack.config.#{ext}")
|
151
385
|
end
|
152
386
|
|
153
387
|
puts "[Shakapacker] Rspack config not found, checking for webpack config fallback..."
|
154
388
|
webpack_path = webpack_paths.find { |f| File.exist?(f) }
|
155
389
|
if webpack_path
|
156
390
|
$stderr.puts "⚠️ DEPRECATION WARNING: Using webpack config file for Rspack assets bundler."
|
157
|
-
$stderr.puts " Please create
|
391
|
+
$stderr.puts " Please create #{config_dir}/rspack.config.js and migrate your configuration."
|
158
392
|
$stderr.puts " Using: #{webpack_path}"
|
159
393
|
return webpack_path
|
160
394
|
end
|
161
395
|
|
162
396
|
# No config found
|
163
|
-
|
397
|
+
print_config_not_found_error("rspack", rspack_paths.last, config_dir)
|
164
398
|
exit(1)
|
165
399
|
end
|
166
400
|
|
167
401
|
def find_webpack_config
|
402
|
+
config_dir = @config.assets_bundler_config_path
|
403
|
+
|
168
404
|
possible_paths = %w[ts js].map do |ext|
|
169
|
-
File.join(@app_path, "
|
405
|
+
File.join(@app_path, config_dir, "webpack.config.#{ext}")
|
170
406
|
end
|
171
407
|
puts "[Shakapacker] Looking for Webpack config in: #{possible_paths.join(", ")}"
|
172
408
|
path = possible_paths.find { |f| File.exist?(f) }
|
173
409
|
unless path
|
174
|
-
|
410
|
+
print_config_not_found_error("webpack", possible_paths.last, config_dir)
|
175
411
|
exit(1)
|
176
412
|
end
|
177
413
|
puts "[Shakapacker] Found Webpack config: #{path}"
|
data/lib/shakapacker/version.rb
CHANGED
@@ -1,8 +1,48 @@
|
|
1
1
|
require "shakapacker/doctor"
|
2
2
|
|
3
3
|
namespace :shakapacker do
|
4
|
-
desc
|
4
|
+
desc <<~DESC
|
5
|
+
Checks for common Shakapacker configuration issues and missing dependencies
|
6
|
+
|
7
|
+
Performs comprehensive diagnostics including:
|
8
|
+
• Configuration file validity and deprecated settings
|
9
|
+
• Entry points, output paths, and asset compilation status
|
10
|
+
• Node.js and package manager installation
|
11
|
+
• Required and optional npm dependencies
|
12
|
+
• JavaScript transpiler (Babel, SWC, esbuild) configuration
|
13
|
+
• CSS, CSS Modules, and stylesheet preprocessor setup
|
14
|
+
• Binstubs presence (shakapacker, shakapacker-dev-server, export-bundler-config)
|
15
|
+
• Version consistency between gem and npm package
|
16
|
+
• Legacy Webpacker file detection
|
17
|
+
|
18
|
+
Options:
|
19
|
+
--help Show detailed help and usage information
|
20
|
+
--verbose Display additional diagnostic details (paths, versions, environment)
|
21
|
+
|
22
|
+
Examples:
|
23
|
+
bin/rails shakapacker:doctor
|
24
|
+
bin/rails shakapacker:doctor -- --verbose
|
25
|
+
bin/rails shakapacker:doctor -- --help
|
26
|
+
|
27
|
+
Exit codes:
|
28
|
+
0 - No issues found
|
29
|
+
1 - Issues or warnings detected (see output for details)
|
30
|
+
DESC
|
5
31
|
task doctor: :environment do
|
6
|
-
|
32
|
+
# Parse command-line options
|
33
|
+
options = {}
|
34
|
+
ARGV.each do |arg|
|
35
|
+
case arg
|
36
|
+
when "--help", "-h"
|
37
|
+
options[:help] = true
|
38
|
+
when "--verbose", "-v"
|
39
|
+
options[:verbose] = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Shakapacker::Doctor.new(nil, nil, options).run
|
44
|
+
|
45
|
+
# Prevent rake from treating options as task names
|
46
|
+
ARGV.each { |arg| task arg.to_sym do; end if arg.start_with?("--", "-") }
|
7
47
|
end
|
8
48
|
end
|
data/package/babel/preset.ts
CHANGED
@@ -17,7 +17,10 @@ const coreJsVersion = (): string => {
|
|
17
17
|
}
|
18
18
|
}
|
19
19
|
|
20
|
-
export = function config(api: ConfigAPI): {
|
20
|
+
export = function config(api: ConfigAPI): {
|
21
|
+
presets: PluginItem[]
|
22
|
+
plugins: PluginItem[]
|
23
|
+
} {
|
21
24
|
const validEnv = ["development", "test", "production"]
|
22
25
|
const currentEnv = api.env()
|
23
26
|
const isDevelopmentEnv = api.env("development")
|
@@ -45,9 +48,9 @@ export = function config(api: ConfigAPI): { presets: PluginItem[]; plugins: Plug
|
|
45
48
|
moduleExists("@babel/preset-typescript") && "@babel/preset-typescript"
|
46
49
|
].filter(Boolean) as PluginItem[]
|
47
50
|
|
48
|
-
const plugins: PluginItem[] = [
|
49
|
-
|
50
|
-
) as PluginItem[]
|
51
|
+
const plugins: PluginItem[] = [
|
52
|
+
["@babel/plugin-transform-runtime", { helpers: false }]
|
53
|
+
].filter(Boolean) as PluginItem[]
|
51
54
|
|
52
55
|
return {
|
53
56
|
presets,
|
data/package/config.ts
CHANGED
@@ -7,17 +7,25 @@ const { railsEnv } = require("./env")
|
|
7
7
|
const configPath = require("./utils/configPath")
|
8
8
|
const defaultConfigPath = require("./utils/defaultConfigPath")
|
9
9
|
import { Config, YamlConfig, LegacyConfig } from "./types"
|
10
|
-
const {
|
11
|
-
|
10
|
+
const {
|
11
|
+
isValidYamlConfig,
|
12
|
+
createConfigValidationError,
|
13
|
+
isPartialConfig,
|
14
|
+
isValidConfig
|
15
|
+
} = require("./utils/typeGuards")
|
16
|
+
const {
|
17
|
+
isFileNotFoundError,
|
18
|
+
createFileOperationError
|
19
|
+
} = require("./utils/errorHelpers")
|
12
20
|
|
13
21
|
const loadAndValidateYaml = (path: string): YamlConfig => {
|
14
22
|
const fileContent = readFileSync(path, "utf8")
|
15
23
|
const yamlContent = load(fileContent)
|
16
|
-
|
24
|
+
|
17
25
|
if (!isValidYamlConfig(yamlContent)) {
|
18
26
|
throw createConfigValidationError(path, railsEnv, "Invalid YAML structure")
|
19
27
|
}
|
20
|
-
|
28
|
+
|
21
29
|
return yamlContent as YamlConfig
|
22
30
|
}
|
23
31
|
|
@@ -28,8 +36,8 @@ const getDefaultConfig = (): Partial<Config> => {
|
|
28
36
|
} catch (error) {
|
29
37
|
if (isFileNotFoundError(error)) {
|
30
38
|
throw createFileOperationError(
|
31
|
-
|
32
|
-
defaultConfigPath,
|
39
|
+
"read",
|
40
|
+
defaultConfigPath,
|
33
41
|
`Default configuration not found at ${defaultConfigPath}. Please ensure Shakapacker is properly installed. You may need to run 'yarn add shakapacker' or 'npm install shakapacker'.`
|
34
42
|
)
|
35
43
|
}
|
@@ -43,34 +51,34 @@ let config: Config
|
|
43
51
|
if (existsSync(configPath)) {
|
44
52
|
try {
|
45
53
|
const appYmlObject = loadAndValidateYaml(configPath)
|
46
|
-
|
54
|
+
|
47
55
|
const envAppConfig = appYmlObject[railsEnv]
|
48
56
|
|
49
57
|
if (!envAppConfig) {
|
50
58
|
/* eslint no-console:0 */
|
51
59
|
console.warn(
|
52
60
|
`[SHAKAPACKER WARNING] Environment '${railsEnv}' not found in ${configPath}\n` +
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
61
|
+
`Available environments: ${Object.keys(appYmlObject).join(", ")}\n` +
|
62
|
+
`Using 'production' configuration as fallback.\n\n` +
|
63
|
+
`To fix this, either:\n` +
|
64
|
+
` - Add a '${railsEnv}' section to your shakapacker.yml\n` +
|
65
|
+
` - Set RAILS_ENV to one of the available environments\n` +
|
66
|
+
` - Copy settings from another environment as a starting point`
|
59
67
|
)
|
60
68
|
}
|
61
69
|
|
62
70
|
// Merge returns the merged type
|
63
71
|
const mergedConfig = merge(defaults, envAppConfig || {})
|
64
|
-
|
72
|
+
|
65
73
|
// Validate merged config before type assertion
|
66
74
|
if (!isPartialConfig(mergedConfig)) {
|
67
75
|
throw createConfigValidationError(
|
68
|
-
configPath,
|
69
|
-
railsEnv,
|
76
|
+
configPath,
|
77
|
+
railsEnv,
|
70
78
|
`Invalid configuration structure in ${configPath}. Please check your shakapacker.yml syntax and ensure all required fields are properly defined.`
|
71
79
|
)
|
72
80
|
}
|
73
|
-
|
81
|
+
|
74
82
|
// After merging with defaults, config should be complete
|
75
83
|
// Use type assertion only after validation
|
76
84
|
config = mergedConfig as Config
|
@@ -79,8 +87,8 @@ if (existsSync(configPath)) {
|
|
79
87
|
// File not found is OK, use defaults
|
80
88
|
if (!isPartialConfig(defaults)) {
|
81
89
|
throw createConfigValidationError(
|
82
|
-
defaultConfigPath,
|
83
|
-
railsEnv,
|
90
|
+
defaultConfigPath,
|
91
|
+
railsEnv,
|
84
92
|
`Invalid default configuration. This may indicate a corrupted Shakapacker installation. Try reinstalling with 'yarn add shakapacker --force'.`
|
85
93
|
)
|
86
94
|
}
|
@@ -94,8 +102,8 @@ if (existsSync(configPath)) {
|
|
94
102
|
// No user config, use defaults
|
95
103
|
if (!isPartialConfig(defaults)) {
|
96
104
|
throw createConfigValidationError(
|
97
|
-
defaultConfigPath,
|
98
|
-
railsEnv,
|
105
|
+
defaultConfigPath,
|
106
|
+
railsEnv,
|
99
107
|
`Invalid default configuration. This may indicate a corrupted Shakapacker installation. Try reinstalling with 'yarn add shakapacker --force'.`
|
100
108
|
)
|
101
109
|
}
|
@@ -122,7 +130,9 @@ if (config.manifest_path) {
|
|
122
130
|
}
|
123
131
|
// Ensure no duplicate hash functions exist in the returned config object
|
124
132
|
if (config.integrity?.hash_functions) {
|
125
|
-
config.integrity.hash_functions = [
|
133
|
+
config.integrity.hash_functions = [
|
134
|
+
...new Set(config.integrity.hash_functions)
|
135
|
+
]
|
126
136
|
}
|
127
137
|
|
128
138
|
// Ensure assets_bundler has a default value
|
@@ -130,7 +140,7 @@ if (!config.assets_bundler) {
|
|
130
140
|
config.assets_bundler = "webpack"
|
131
141
|
}
|
132
142
|
|
133
|
-
// Allow ENV variable to override assets_bundler
|
143
|
+
// Allow ENV variable to override assets_bundler
|
134
144
|
if (process.env.SHAKAPACKER_ASSETS_BUNDLER) {
|
135
145
|
config.assets_bundler = process.env.SHAKAPACKER_ASSETS_BUNDLER
|
136
146
|
}
|
@@ -138,16 +148,18 @@ if (process.env.SHAKAPACKER_ASSETS_BUNDLER) {
|
|
138
148
|
// Define clear defaults
|
139
149
|
// Keep Babel as default for webpack to maintain backward compatibility
|
140
150
|
// Use SWC for rspack as it's a newer bundler where we can set modern defaults
|
141
|
-
const DEFAULT_JAVASCRIPT_TRANSPILER =
|
151
|
+
const DEFAULT_JAVASCRIPT_TRANSPILER =
|
142
152
|
config.assets_bundler === "rspack" ? "swc" : "babel"
|
143
153
|
|
144
154
|
// Backward compatibility: Check for webpack_loader using proper type guard
|
145
|
-
function hasWebpackLoader(
|
155
|
+
function hasWebpackLoader(
|
156
|
+
obj: unknown
|
157
|
+
): obj is Config & { webpack_loader: string } {
|
146
158
|
return (
|
147
|
-
typeof obj ===
|
159
|
+
typeof obj === "object" &&
|
148
160
|
obj !== null &&
|
149
|
-
|
150
|
-
typeof (obj as Record<string, unknown>).webpack_loader ===
|
161
|
+
"webpack_loader" in obj &&
|
162
|
+
typeof (obj as Record<string, unknown>).webpack_loader === "string"
|
151
163
|
)
|
152
164
|
}
|
153
165
|
|
@@ -157,7 +169,7 @@ if (process.env.SHAKAPACKER_JAVASCRIPT_TRANSPILER) {
|
|
157
169
|
} else if (hasWebpackLoader(config) && !config.javascript_transpiler) {
|
158
170
|
console.warn(
|
159
171
|
"[SHAKAPACKER DEPRECATION] The 'webpack_loader' configuration option is deprecated.\n" +
|
160
|
-
|
172
|
+
"Please use 'javascript_transpiler' instead as it better reflects its purpose of configuring JavaScript transpilation regardless of the bundler used."
|
161
173
|
)
|
162
174
|
config.javascript_transpiler = config.webpack_loader
|
163
175
|
} else if (!config.javascript_transpiler) {
|
@@ -165,7 +177,7 @@ if (process.env.SHAKAPACKER_JAVASCRIPT_TRANSPILER) {
|
|
165
177
|
}
|
166
178
|
|
167
179
|
// Ensure webpack_loader is always available for backward compatibility
|
168
|
-
Object.defineProperty(config,
|
180
|
+
Object.defineProperty(config, "webpack_loader", {
|
169
181
|
value: config.javascript_transpiler,
|
170
182
|
writable: true,
|
171
183
|
enumerable: true,
|