shakapacker 10.1.0 → 10.3.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/CHANGELOG.md +43 -1
- data/README.md +117 -1368
- data/lib/install/bin/diff-bundler-config +113 -40
- data/lib/install/bin/shakapacker-config +113 -40
- data/lib/install/config/shakapacker.yml +10 -2
- data/lib/install/package.json +6 -4
- data/lib/install/template.rb +91 -12
- data/lib/shakapacker/base_strategy.rb +10 -4
- data/lib/shakapacker/bundler_switcher.rb +22 -6
- data/lib/shakapacker/compiler.rb +38 -8
- data/lib/shakapacker/compiler_strategy.rb +4 -4
- data/lib/shakapacker/configuration.rb +214 -38
- data/lib/shakapacker/dev_server_runner.rb +44 -19
- data/lib/shakapacker/digest_strategy.rb +3 -3
- data/lib/shakapacker/doctor.rb +501 -79
- data/lib/shakapacker/helper.rb +3 -3
- data/lib/shakapacker/install/env.rb +50 -0
- data/lib/shakapacker/instance.rb +1 -1
- data/lib/shakapacker/mtime_strategy.rb +1 -1
- data/lib/shakapacker/runner.rb +93 -55
- data/lib/shakapacker/utils/misc.rb +38 -0
- data/lib/shakapacker/version.rb +1 -1
- data/lib/shakapacker/version_checker.rb +16 -4
- data/lib/tasks/shakapacker/export_bundler_config.rake +30 -21
- data/lib/tasks/shakapacker/install.rake +5 -3
- data/lib/tasks/shakapacker.rake +1 -1
- data/package.json +16 -12
- data/sig/shakapacker/configuration.rbs +3 -0
- metadata +3 -3
|
@@ -19,12 +19,13 @@ module Shakapacker
|
|
|
19
19
|
prod: %w[webpack-merge]
|
|
20
20
|
}.freeze
|
|
21
21
|
|
|
22
|
-
# Default dependencies for each bundler
|
|
22
|
+
# Default dependencies for each bundler. Rspack entries include install-time
|
|
23
|
+
# version ranges; package_names strips them before removal and display.
|
|
23
24
|
# Note: Excludes independent/optional dependencies like @swc/core, swc-loader (user-configured
|
|
24
25
|
# transpilers)
|
|
25
26
|
DEFAULT_RSPACK_DEPS = {
|
|
26
|
-
dev: %w[@rspack/cli @rspack/plugin-react-refresh],
|
|
27
|
-
prod: %w[@rspack/core rspack-manifest-plugin]
|
|
27
|
+
dev: %w[@rspack/cli@^2.0.0 @rspack/dev-server@^2.0.0 @rspack/plugin-react-refresh@^2.0.0],
|
|
28
|
+
prod: %w[@rspack/core@^2.0.0 rspack-manifest-plugin@^5.2.2]
|
|
28
29
|
}.freeze
|
|
29
30
|
|
|
30
31
|
DEFAULT_WEBPACK_DEPS = {
|
|
@@ -267,8 +268,8 @@ module Shakapacker
|
|
|
267
268
|
# Show what will be removed (only when switching and not no_uninstall)
|
|
268
269
|
if switching && !no_uninstall && (!deps_to_remove[:dev].empty? || !deps_to_remove[:prod].empty?)
|
|
269
270
|
puts " 🗑️ Removing:"
|
|
270
|
-
deps_to_remove[:dev].each { |dep| puts " - #{dep} (dev)" }
|
|
271
|
-
deps_to_remove[:prod].each { |dep| puts " - #{dep} (prod)" }
|
|
271
|
+
package_names(deps_to_remove[:dev]).each { |dep| puts " - #{dep} (dev)" }
|
|
272
|
+
package_names(deps_to_remove[:prod]).each { |dep| puts " - #{dep} (prod)" }
|
|
272
273
|
puts ""
|
|
273
274
|
elsif switching && no_uninstall
|
|
274
275
|
puts " ⏭️ Skipping uninstall (--no-uninstall)"
|
|
@@ -302,7 +303,7 @@ module Shakapacker
|
|
|
302
303
|
|
|
303
304
|
# Combine dev and prod dependencies into a single list for removal
|
|
304
305
|
# Package managers remove packages from both dependencies and devDependencies sections if present
|
|
305
|
-
all_deps = deps[:dev] + deps[:prod]
|
|
306
|
+
all_deps = package_names(deps[:dev] + deps[:prod])
|
|
306
307
|
|
|
307
308
|
unless all_deps.empty?
|
|
308
309
|
unless package_json.manager.remove(all_deps)
|
|
@@ -381,6 +382,11 @@ module Shakapacker
|
|
|
381
382
|
end
|
|
382
383
|
|
|
383
384
|
def print_uninstall_commands(package_manager, deps)
|
|
385
|
+
deps = {
|
|
386
|
+
dev: package_names(deps[:dev]),
|
|
387
|
+
prod: package_names(deps[:prod])
|
|
388
|
+
}
|
|
389
|
+
|
|
384
390
|
case package_manager
|
|
385
391
|
when "yarn"
|
|
386
392
|
puts " yarn remove #{deps[:dev].join(' ')}" unless deps[:dev].empty?
|
|
@@ -397,6 +403,16 @@ module Shakapacker
|
|
|
397
403
|
end
|
|
398
404
|
end
|
|
399
405
|
|
|
406
|
+
def package_names(dependencies)
|
|
407
|
+
dependencies.map do |dependency|
|
|
408
|
+
if dependency.start_with?("@")
|
|
409
|
+
dependency.count("@") > 1 ? dependency.sub(/@[^@]+\z/, "") : dependency
|
|
410
|
+
else
|
|
411
|
+
dependency.sub(/@[^@]+\z/, "")
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
400
416
|
# Load YAML config file with Ruby version compatibility
|
|
401
417
|
# Ruby 3.1+ supports aliases: keyword, older versions need YAML.safe_load
|
|
402
418
|
def load_yaml_config(path)
|
data/lib/shakapacker/compiler.rb
CHANGED
|
@@ -5,6 +5,9 @@ require "shellwords"
|
|
|
5
5
|
require_relative "compiler_strategy"
|
|
6
6
|
|
|
7
7
|
class Shakapacker::Compiler
|
|
8
|
+
SpawnFailure = Class.new(StandardError)
|
|
9
|
+
private_constant :SpawnFailure
|
|
10
|
+
|
|
8
11
|
# Additional environment variables that the compiler is being run with
|
|
9
12
|
# Shakapacker::Compiler.env['FRONTEND_API_KEY'] = 'your_secret_key'
|
|
10
13
|
cattr_accessor(:env) { {} }
|
|
@@ -36,9 +39,16 @@ class Shakapacker::Compiler
|
|
|
36
39
|
else
|
|
37
40
|
acquire_ipc_lock do
|
|
38
41
|
run_precompile_hook if should_run_precompile_hook?
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
spawn_failed = false
|
|
43
|
+
begin
|
|
44
|
+
success = run_webpack
|
|
45
|
+
rescue SpawnFailure
|
|
46
|
+
spawn_failed = true
|
|
47
|
+
success = false
|
|
41
48
|
end
|
|
49
|
+
|
|
50
|
+
after_compile_hook unless spawn_failed
|
|
51
|
+
success
|
|
42
52
|
end
|
|
43
53
|
end
|
|
44
54
|
end
|
|
@@ -83,8 +93,9 @@ class Shakapacker::Compiler
|
|
|
83
93
|
config.root_path.join("tmp/shakapacker.lock")
|
|
84
94
|
end
|
|
85
95
|
|
|
96
|
+
# Returns one executable path for array-form Open3, not a shell command snippet.
|
|
86
97
|
def optional_ruby_runner
|
|
87
|
-
first_line = File.readlines(bin_shakapacker_path).first
|
|
98
|
+
first_line = File.readlines(bin_shakapacker_path).first&.chomp || ""
|
|
88
99
|
/ruby/.match?(first_line) ? RbConfig.ruby : ""
|
|
89
100
|
end
|
|
90
101
|
|
|
@@ -176,11 +187,21 @@ class Shakapacker::Compiler
|
|
|
176
187
|
def run_webpack
|
|
177
188
|
logger.info "Compiling..."
|
|
178
189
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
190
|
+
# Fetch compile flags before the spawn rescue so configuration errors stay explicit.
|
|
191
|
+
compile_flags = config.webpack_compile_flags
|
|
192
|
+
|
|
193
|
+
begin
|
|
194
|
+
command = shakapacker_command(compile_flags)
|
|
195
|
+
stdout, stderr, status = Open3.capture3(
|
|
196
|
+
webpack_env,
|
|
197
|
+
*command,
|
|
198
|
+
chdir: File.expand_path(config.root_path)
|
|
199
|
+
)
|
|
200
|
+
rescue Errno::EACCES, Errno::ENOENT, Errno::ENOEXEC, Errno::EPERM, Errno::ENOTDIR => e
|
|
201
|
+
logger.error "\nCOMPILATION FAILED:\n#{e.class}: #{e.message}"
|
|
202
|
+
show_doctor_hint_once
|
|
203
|
+
raise SpawnFailure
|
|
204
|
+
end
|
|
184
205
|
|
|
185
206
|
if status.success?
|
|
186
207
|
logger.info "Compiled all packs in #{config.public_output_path}"
|
|
@@ -211,6 +232,15 @@ class Shakapacker::Compiler
|
|
|
211
232
|
config.root_path.join("bin/shakapacker")
|
|
212
233
|
end
|
|
213
234
|
|
|
235
|
+
def shakapacker_command(compile_flags)
|
|
236
|
+
runner = optional_ruby_runner
|
|
237
|
+
bin_path = bin_shakapacker_path.to_s
|
|
238
|
+
flags_part = compile_flags.any? ? ["--", *compile_flags] : []
|
|
239
|
+
|
|
240
|
+
# Use the [cmd, argv0] form so Open3 never routes a lone binstub path through the shell.
|
|
241
|
+
runner.empty? ? [[bin_path, bin_path], *flags_part] : [runner, bin_path, *flags_part]
|
|
242
|
+
end
|
|
243
|
+
|
|
214
244
|
# Fires only after a failed compile, so users in a healthy loop never see the tip.
|
|
215
245
|
def show_doctor_hint_once
|
|
216
246
|
return if self.class.doctor_hint_shown
|
|
@@ -3,14 +3,14 @@ require_relative "digest_strategy"
|
|
|
3
3
|
|
|
4
4
|
module Shakapacker
|
|
5
5
|
class CompilerStrategy
|
|
6
|
-
def self.from_config
|
|
7
|
-
strategy_from_config =
|
|
6
|
+
def self.from_config(instance = Shakapacker.instance)
|
|
7
|
+
strategy_from_config = instance.config.compiler_strategy
|
|
8
8
|
|
|
9
9
|
case strategy_from_config
|
|
10
10
|
when "mtime"
|
|
11
|
-
Shakapacker::MtimeStrategy.new
|
|
11
|
+
Shakapacker::MtimeStrategy.new(instance)
|
|
12
12
|
when "digest"
|
|
13
|
-
Shakapacker::DigestStrategy.new
|
|
13
|
+
Shakapacker::DigestStrategy.new(instance)
|
|
14
14
|
else
|
|
15
15
|
raise "Unknown strategy '#{strategy_from_config}'. " \
|
|
16
16
|
"Available options are 'mtime' and 'digest'."
|
|
@@ -27,6 +27,41 @@ require "active_support/core_ext/hash/indifferent_access"
|
|
|
27
27
|
#
|
|
28
28
|
# @see https://github.com/shakacode/shakapacker/blob/main/docs/shakapacker.yml.md
|
|
29
29
|
class Shakapacker::Configuration
|
|
30
|
+
# Shared Ruby source of truth for Shakapacker-owned Node flags; Runner aliases this constant.
|
|
31
|
+
SHAKAPACKER_NODE_FLAGS = %w[--debug-shakapacker --trace-deprecation --no-deprecation].freeze
|
|
32
|
+
|
|
33
|
+
SHAKAPACKER_RUNNER_COMMANDS = %w[help h --help -h --help=verbose version v --version -v info i].freeze
|
|
34
|
+
private_constant :SHAKAPACKER_RUNNER_COMMANDS
|
|
35
|
+
|
|
36
|
+
SHAKAPACKER_HELP_FLAG_PATTERN = /\A(?:--help|-h)(?:=.*)?\z/
|
|
37
|
+
private_constant :SHAKAPACKER_HELP_FLAG_PATTERN
|
|
38
|
+
|
|
39
|
+
SHAKAPACKER_WATCH_FLAGS = %w[--watch -w].freeze
|
|
40
|
+
private_constant :SHAKAPACKER_WATCH_FLAGS
|
|
41
|
+
|
|
42
|
+
SHAKAPACKER_WATCH_FLAG_PATTERN = /\A(?:--watch|-w)(?:=.*)?\z/
|
|
43
|
+
private_constant :SHAKAPACKER_WATCH_FLAG_PATTERN
|
|
44
|
+
|
|
45
|
+
SHAKAPACKER_MANAGED_COMPILE_FLAGS =
|
|
46
|
+
%w[--config -c --node-env --nodeEnv --bundler --build --init --list-builds].freeze
|
|
47
|
+
private_constant :SHAKAPACKER_MANAGED_COMPILE_FLAGS
|
|
48
|
+
|
|
49
|
+
SHAKAPACKER_MANAGED_COMPILE_FLAG_PATTERN =
|
|
50
|
+
/\A(?:--config|-c|--node-env|--nodeEnv|--bundler|--build|--init|--list-builds)(?:=.*)?\z/
|
|
51
|
+
private_constant :SHAKAPACKER_MANAGED_COMPILE_FLAG_PATTERN
|
|
52
|
+
|
|
53
|
+
IMPLICIT_SWC_BABEL_FALLBACK_WARNING =
|
|
54
|
+
"`javascript_transpiler` is not set in config/shakapacker.yml. " \
|
|
55
|
+
"Shakapacker defaults to SWC, but swc-loader is not installed and Babel was detected, so Babel will be used. " \
|
|
56
|
+
"Set `javascript_transpiler: babel` (or `swc`) explicitly to silence this message. " \
|
|
57
|
+
"See https://github.com/shakacode/shakapacker/blob/main/docs/transpiler-migration.md"
|
|
58
|
+
private_constant :IMPLICIT_SWC_BABEL_FALLBACK_WARNING
|
|
59
|
+
|
|
60
|
+
DISALLOWED_WEBPACK_COMPILE_FLAGS =
|
|
61
|
+
(SHAKAPACKER_NODE_FLAGS + SHAKAPACKER_RUNNER_COMMANDS + SHAKAPACKER_WATCH_FLAGS +
|
|
62
|
+
SHAKAPACKER_MANAGED_COMPILE_FLAGS).freeze
|
|
63
|
+
private_constant :DISALLOWED_WEBPACK_COMPILE_FLAGS
|
|
64
|
+
|
|
30
65
|
class << self
|
|
31
66
|
# Flag indicating whether Shakapacker is currently being installed
|
|
32
67
|
# Used to suppress certain validations during installation
|
|
@@ -233,6 +268,25 @@ class Shakapacker::Configuration
|
|
|
233
268
|
fetch(:webpack_compile_output)
|
|
234
269
|
end
|
|
235
270
|
|
|
271
|
+
# Returns extra command-line flags passed to the webpack/rspack compile command
|
|
272
|
+
#
|
|
273
|
+
# @return [Array<String>] bundler CLI flags
|
|
274
|
+
def webpack_compile_flags
|
|
275
|
+
flags = fetch(:webpack_compile_flags)
|
|
276
|
+
return [] if flags.nil?
|
|
277
|
+
|
|
278
|
+
valid_flags = flags.is_a?(Array) && flags.all? { |flag| valid_webpack_compile_flag?(flag) }
|
|
279
|
+
|
|
280
|
+
unless valid_flags
|
|
281
|
+
disallowed_flags = DISALLOWED_WEBPACK_COMPILE_FLAGS.join(", ")
|
|
282
|
+
raise "Shakapacker configuration error: compile flags (webpack_compile_flags) must be an array of " \
|
|
283
|
+
"non-empty strings and must not include \"--\" or Shakapacker-specific " \
|
|
284
|
+
"wrapper/short-circuit/watch/managed flags (#{disallowed_flags})"
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
flags
|
|
288
|
+
end
|
|
289
|
+
|
|
236
290
|
# Returns the compiler strategy for determining staleness
|
|
237
291
|
#
|
|
238
292
|
# Options:
|
|
@@ -310,24 +364,54 @@ class Shakapacker::Configuration
|
|
|
310
364
|
# Resolution order:
|
|
311
365
|
# 1. javascript_transpiler setting in config file
|
|
312
366
|
# 2. webpack_loader setting in config file (deprecated)
|
|
313
|
-
# 3.
|
|
367
|
+
# 3. Bundled defaults
|
|
368
|
+
# 4. Babel fallback for implicit webpack/SWC defaults when swc-loader is missing
|
|
314
369
|
#
|
|
315
370
|
# Validates that the configured transpiler matches installed packages.
|
|
316
371
|
#
|
|
317
372
|
# @return [String] "babel", "swc", or "esbuild"
|
|
318
373
|
def javascript_transpiler
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
374
|
+
return @javascript_transpiler if defined?(@javascript_transpiler)
|
|
375
|
+
|
|
376
|
+
@javascript_transpiler =
|
|
377
|
+
begin
|
|
378
|
+
javascript_transpiler_configured = config_value_configured?(:javascript_transpiler)
|
|
379
|
+
webpack_loader_configured = config_value_present?(:webpack_loader)
|
|
323
380
|
|
|
324
|
-
|
|
325
|
-
|
|
381
|
+
# Show deprecation warning if using old 'webpack_loader' key
|
|
382
|
+
if webpack_loader_configured && !javascript_transpiler_configured
|
|
383
|
+
$stderr.puts "⚠️ DEPRECATION WARNING: The 'webpack_loader' configuration option is deprecated. Please use 'javascript_transpiler' instead as it better reflects its purpose of configuring JavaScript transpilation regardless of the bundler used."
|
|
384
|
+
end
|
|
326
385
|
|
|
327
|
-
|
|
328
|
-
|
|
386
|
+
# Use explicit config if set, otherwise default based on bundler
|
|
387
|
+
current_javascript_transpiler =
|
|
388
|
+
if javascript_transpiler_configured
|
|
389
|
+
fetch(:javascript_transpiler)
|
|
390
|
+
elsif data.has_key?(:javascript_transpiler)
|
|
391
|
+
defaults[:javascript_transpiler]
|
|
392
|
+
else
|
|
393
|
+
fetch(:javascript_transpiler)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
transpiler =
|
|
397
|
+
if webpack_loader_configured && !javascript_transpiler_configured
|
|
398
|
+
fetch(:webpack_loader) || default_javascript_transpiler
|
|
399
|
+
else
|
|
400
|
+
current_javascript_transpiler || fetch(:webpack_loader) || default_javascript_transpiler
|
|
401
|
+
end
|
|
329
402
|
|
|
330
|
-
|
|
403
|
+
if !javascript_transpiler_configured &&
|
|
404
|
+
!webpack_loader_configured &&
|
|
405
|
+
implicit_swc_to_babel_fallback?(transpiler)
|
|
406
|
+
$stderr.puts IMPLICIT_SWC_BABEL_FALLBACK_WARNING
|
|
407
|
+
transpiler = "babel"
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# Validate transpiler configuration
|
|
411
|
+
validate_transpiler_configuration(transpiler) unless self.class.installing
|
|
412
|
+
|
|
413
|
+
transpiler
|
|
414
|
+
end
|
|
331
415
|
end
|
|
332
416
|
|
|
333
417
|
# Deprecated alias for {#javascript_transpiler}
|
|
@@ -399,47 +483,139 @@ class Shakapacker::Configuration
|
|
|
399
483
|
|
|
400
484
|
private
|
|
401
485
|
|
|
486
|
+
def valid_webpack_compile_flag?(flag)
|
|
487
|
+
flag.is_a?(String) &&
|
|
488
|
+
!flag.empty? &&
|
|
489
|
+
flag != "--" &&
|
|
490
|
+
!DISALLOWED_WEBPACK_COMPILE_FLAGS.include?(flag) &&
|
|
491
|
+
!SHAKAPACKER_HELP_FLAG_PATTERN.match?(flag) &&
|
|
492
|
+
!SHAKAPACKER_WATCH_FLAG_PATTERN.match?(flag) &&
|
|
493
|
+
!SHAKAPACKER_MANAGED_COMPILE_FLAG_PATTERN.match?(flag)
|
|
494
|
+
end
|
|
495
|
+
|
|
402
496
|
def default_javascript_transpiler
|
|
403
497
|
# RSpack has built-in SWC support, use it by default
|
|
404
498
|
rspack? ? "swc" : "babel"
|
|
405
499
|
end
|
|
406
500
|
|
|
501
|
+
def implicit_swc_to_babel_fallback?(transpiler)
|
|
502
|
+
webpack? &&
|
|
503
|
+
transpiler == "swc" &&
|
|
504
|
+
!package_dependency?("swc-loader") &&
|
|
505
|
+
package_dependency?("babel-loader")
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def package_dependency?(package_name)
|
|
509
|
+
declared_package_dependencies.key?(package_name)
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
def config_value_present?(key)
|
|
513
|
+
return false unless data.has_key?(key)
|
|
514
|
+
|
|
515
|
+
value = data[key]
|
|
516
|
+
value.is_a?(String) && !value.strip.empty?
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
def config_value_configured?(key)
|
|
520
|
+
return false unless data.has_key?(key)
|
|
521
|
+
|
|
522
|
+
value = data[key]
|
|
523
|
+
return false if value.nil?
|
|
524
|
+
return false if value.is_a?(String) && value.strip.empty?
|
|
525
|
+
|
|
526
|
+
true
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
def declared_package_dependencies
|
|
530
|
+
return @declared_package_dependencies if defined?(@declared_package_dependencies)
|
|
531
|
+
|
|
532
|
+
@declared_package_dependencies =
|
|
533
|
+
package_json_paths.reverse_each.each_with_object({}) do |path, dependencies|
|
|
534
|
+
package_json = parse_package_json(path)
|
|
535
|
+
next unless package_json
|
|
536
|
+
|
|
537
|
+
dependencies.merge!(installable_package_dependencies(package_json))
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
def installable_package_dependencies(package_json)
|
|
542
|
+
(package_json["optionalDependencies"] || {})
|
|
543
|
+
.merge(package_json["devDependencies"] || {})
|
|
544
|
+
.merge(package_json["dependencies"] || {})
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
def package_json_paths
|
|
548
|
+
@package_json_paths ||= package_root_paths
|
|
549
|
+
.map { |path| path.join("package.json") }
|
|
550
|
+
.select(&:exist?)
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
def parse_package_json(path)
|
|
554
|
+
JSON.parse(File.read(path))
|
|
555
|
+
rescue JSON::ParserError, SystemCallError
|
|
556
|
+
nil
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def package_root_paths
|
|
560
|
+
@package_root_paths ||= [javascript_package_root_path, root_path].uniq
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
def javascript_package_root_path
|
|
564
|
+
@javascript_package_root_path ||= begin
|
|
565
|
+
resolved_source_path = source_path.expand_path
|
|
566
|
+
app_root = root_path.expand_path
|
|
567
|
+
|
|
568
|
+
if path_within?(resolved_source_path, app_root)
|
|
569
|
+
current = resolved_source_path
|
|
570
|
+
loop do
|
|
571
|
+
break current if current.join("package.json").exist?
|
|
572
|
+
break root_path if current == app_root
|
|
573
|
+
|
|
574
|
+
parent = current.dirname
|
|
575
|
+
break root_path if parent == current
|
|
576
|
+
|
|
577
|
+
current = parent
|
|
578
|
+
end
|
|
579
|
+
else
|
|
580
|
+
root_path
|
|
581
|
+
end
|
|
582
|
+
rescue StandardError
|
|
583
|
+
root_path
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
def path_within?(path, parent)
|
|
588
|
+
path.to_s == parent.to_s || path.to_s.start_with?("#{parent}#{File::SEPARATOR}")
|
|
589
|
+
end
|
|
590
|
+
|
|
407
591
|
def validate_transpiler_configuration(transpiler)
|
|
408
592
|
return unless ENV["NODE_ENV"] != "test" # Skip validation in test environment
|
|
409
593
|
|
|
410
594
|
# Skip validation if transpiler is set to 'none' (custom webpack config)
|
|
411
595
|
return if transpiler == "none"
|
|
412
596
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
return unless package_json_path.exist?
|
|
597
|
+
all_deps = declared_package_dependencies
|
|
598
|
+
return if all_deps.empty?
|
|
416
599
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
when "esbuild"
|
|
436
|
-
if !has_esbuild && (has_babel || has_swc)
|
|
437
|
-
other = has_babel ? "Babel" : "SWC"
|
|
438
|
-
warn_transpiler_mismatch("esbuild", "#{other} packages found but esbuild is configured")
|
|
439
|
-
end
|
|
600
|
+
# Check for transpiler mismatch
|
|
601
|
+
has_babel = all_deps.keys.any? { |pkg| pkg.start_with?("@babel/", "babel-") }
|
|
602
|
+
has_swc = all_deps.keys.any? { |pkg| pkg.include?("swc") }
|
|
603
|
+
has_esbuild = all_deps.keys.any? { |pkg| pkg.include?("esbuild") }
|
|
604
|
+
|
|
605
|
+
case transpiler
|
|
606
|
+
when "babel"
|
|
607
|
+
if !has_babel && has_swc
|
|
608
|
+
warn_transpiler_mismatch("Babel", "SWC packages found but Babel is configured")
|
|
609
|
+
end
|
|
610
|
+
when "swc"
|
|
611
|
+
if !has_swc && has_babel
|
|
612
|
+
warn_transpiler_mismatch("SWC", "Babel packages found but SWC is configured")
|
|
613
|
+
end
|
|
614
|
+
when "esbuild"
|
|
615
|
+
if !has_esbuild && (has_babel || has_swc)
|
|
616
|
+
other = has_babel ? "Babel" : "SWC"
|
|
617
|
+
warn_transpiler_mismatch("esbuild", "#{other} packages found but esbuild is configured")
|
|
440
618
|
end
|
|
441
|
-
rescue JSON::ParserError
|
|
442
|
-
# Ignore if package.json is malformed
|
|
443
619
|
end
|
|
444
620
|
end
|
|
445
621
|
|
|
@@ -9,11 +9,13 @@ require_relative "version"
|
|
|
9
9
|
module Shakapacker
|
|
10
10
|
class DevServerRunner < Shakapacker::Runner
|
|
11
11
|
def self.run(argv)
|
|
12
|
+
runner_argv, passthrough_argv = split_passthrough_argv(argv)
|
|
13
|
+
|
|
12
14
|
# Show Shakapacker help and exit (don't call bundler)
|
|
13
|
-
if
|
|
15
|
+
if runner_argv.include?("--help") || runner_argv.include?("-h")
|
|
14
16
|
print_help
|
|
15
17
|
exit(0)
|
|
16
|
-
elsif
|
|
18
|
+
elsif runner_argv.include?("--version") || runner_argv.include?("-v")
|
|
17
19
|
print_version
|
|
18
20
|
exit(0)
|
|
19
21
|
end
|
|
@@ -21,9 +23,9 @@ module Shakapacker
|
|
|
21
23
|
Shakapacker.ensure_node_env!
|
|
22
24
|
|
|
23
25
|
# Check for --build flag
|
|
24
|
-
build_index =
|
|
26
|
+
build_index = runner_argv.index("--build")
|
|
25
27
|
if build_index
|
|
26
|
-
build_name =
|
|
28
|
+
build_name = runner_argv[build_index + 1]
|
|
27
29
|
|
|
28
30
|
unless build_name
|
|
29
31
|
$stderr.puts "[Shakapacker] Error: --build requires a build name"
|
|
@@ -51,11 +53,11 @@ module Shakapacker
|
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
# Remove --build and build name from argv
|
|
54
|
-
remaining_argv =
|
|
56
|
+
remaining_argv = runner_argv.dup
|
|
55
57
|
remaining_argv.delete_at(build_index + 1)
|
|
56
58
|
remaining_argv.delete_at(build_index)
|
|
57
59
|
|
|
58
|
-
run_with_build_config(remaining_argv, build_config)
|
|
60
|
+
run_with_build_config(remaining_argv, build_config, passthrough_argv)
|
|
59
61
|
return
|
|
60
62
|
rescue ArgumentError => e
|
|
61
63
|
$stderr.puts "[Shakapacker] #{e.message}"
|
|
@@ -63,10 +65,10 @@ module Shakapacker
|
|
|
63
65
|
end
|
|
64
66
|
end
|
|
65
67
|
|
|
66
|
-
new(
|
|
68
|
+
new(runner_argv, nil, nil, passthrough_argv).run
|
|
67
69
|
end
|
|
68
70
|
|
|
69
|
-
def self.run_with_build_config(argv, build_config)
|
|
71
|
+
def self.run_with_build_config(argv, build_config, passthrough_argv = [])
|
|
70
72
|
Shakapacker.ensure_node_env!
|
|
71
73
|
|
|
72
74
|
# Apply build config environment variables
|
|
@@ -84,7 +86,7 @@ module Shakapacker
|
|
|
84
86
|
puts "[Shakapacker] Config file: #{build_config[:config_file]}" if build_config[:config_file]
|
|
85
87
|
|
|
86
88
|
# Pass bundler override so Configuration.assets_bundler reflects the build
|
|
87
|
-
new(argv, build_config, build_config[:bundler]).run
|
|
89
|
+
new(argv, build_config, build_config[:bundler], passthrough_argv).run
|
|
88
90
|
end
|
|
89
91
|
|
|
90
92
|
def self.print_help
|
|
@@ -99,8 +101,14 @@ module Shakapacker
|
|
|
99
101
|
-h, --help Show this help message
|
|
100
102
|
-v, --version Show Shakapacker version
|
|
101
103
|
--debug-shakapacker Enable Node.js debugging (--inspect-brk)
|
|
104
|
+
--trace-deprecation Show stack traces for Node.js deprecations
|
|
105
|
+
--no-deprecation Silence Node.js deprecation warnings
|
|
102
106
|
--build <name> Run a specific build configuration
|
|
103
107
|
|
|
108
|
+
Put Shakapacker-specific options before --. Arguments after -- are
|
|
109
|
+
passed directly to the selected bundler, except --host and --port,
|
|
110
|
+
which remain managed by config/shakapacker.yml.
|
|
111
|
+
|
|
104
112
|
Build configurations (config/shakapacker-builds.yml):
|
|
105
113
|
bin/shakapacker-dev-server --build dev-hmr # Run the 'dev-hmr' build
|
|
106
114
|
|
|
@@ -116,6 +124,7 @@ module Shakapacker
|
|
|
116
124
|
bin/shakapacker-dev-server --no-hot # Disable HMR
|
|
117
125
|
bin/shakapacker-dev-server --open # Open browser automatically
|
|
118
126
|
bin/shakapacker-dev-server --debug-shakapacker # Debug with Node inspector
|
|
127
|
+
bin/shakapacker-dev-server --trace-deprecation # Show Node deprecation traces
|
|
119
128
|
|
|
120
129
|
HELP
|
|
121
130
|
|
|
@@ -126,12 +135,13 @@ module Shakapacker
|
|
|
126
135
|
Options managed by Shakapacker (configured in config/shakapacker.yml):
|
|
127
136
|
--host Set from dev_server.host (default: localhost)
|
|
128
137
|
--port Set from dev_server.port (default: 3035)
|
|
129
|
-
--https
|
|
138
|
+
--https Requires dev_server.server: https before forwarding
|
|
130
139
|
--config Set automatically to config/webpack/webpack.config.js
|
|
131
140
|
or config/rspack/rspack.config.js
|
|
132
141
|
|
|
133
|
-
Note: CLI flags for --host
|
|
134
|
-
Configure these in config/shakapacker.yml instead.
|
|
142
|
+
Note: CLI flags for --host and --port are NOT supported.
|
|
143
|
+
Configure these in config/shakapacker.yml instead. --https is accepted
|
|
144
|
+
only when dev_server.server is already set to https.
|
|
135
145
|
HELP
|
|
136
146
|
end
|
|
137
147
|
|
|
@@ -260,15 +270,19 @@ module Shakapacker
|
|
|
260
270
|
UNSUPPORTED_SWITCHES = %w[--host --port]
|
|
261
271
|
private_constant :UNSUPPORTED_SWITCHES
|
|
262
272
|
def detect_unsupported_switches!
|
|
263
|
-
|
|
273
|
+
# Host/port stay config-owned even after -- because Shakapacker assembles the dev-server command.
|
|
274
|
+
unsupported_switches = UNSUPPORTED_SWITCHES & bundler_argv
|
|
264
275
|
if unsupported_switches.any?
|
|
265
|
-
|
|
266
|
-
|
|
276
|
+
log_output.puts(
|
|
277
|
+
"The following CLI switches are not supported by Shakapacker: #{unsupported_switches.join(' ')}. " \
|
|
278
|
+
"Please set dev_server.host or dev_server.port in shakapacker.yml instead."
|
|
279
|
+
)
|
|
280
|
+
exit_after_shakapacker_flag_error(1)
|
|
267
281
|
end
|
|
268
282
|
|
|
269
|
-
if
|
|
270
|
-
|
|
271
|
-
|
|
283
|
+
if bundler_argv.include?("--https") && !@https
|
|
284
|
+
log_output.puts "--https requires that 'server' in shakapacker.yml is set to 'https'"
|
|
285
|
+
exit_after_shakapacker_flag_error(1)
|
|
272
286
|
end
|
|
273
287
|
end
|
|
274
288
|
|
|
@@ -289,10 +303,21 @@ module Shakapacker
|
|
|
289
303
|
|
|
290
304
|
cmd = build_cmd
|
|
291
305
|
|
|
306
|
+
detect_shakapacker_flags_in_passthrough!
|
|
307
|
+
|
|
308
|
+
# Shakapacker-owned Node flags must appear before --; passthrough args belong to the bundler.
|
|
292
309
|
if @argv.delete("--debug-shakapacker")
|
|
293
310
|
env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --inspect-brk --trace-warnings"
|
|
294
311
|
end
|
|
295
312
|
|
|
313
|
+
if @argv.delete("--trace-deprecation")
|
|
314
|
+
env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --trace-deprecation"
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
if @argv.delete("--no-deprecation")
|
|
318
|
+
env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --no-deprecation"
|
|
319
|
+
end
|
|
320
|
+
|
|
296
321
|
# Add config file
|
|
297
322
|
cmd += ["--config", @webpack_config]
|
|
298
323
|
|
|
@@ -307,7 +332,7 @@ module Shakapacker
|
|
|
307
332
|
cmd += ["--hot"] if @hot && @hot != false
|
|
308
333
|
end
|
|
309
334
|
|
|
310
|
-
cmd +=
|
|
335
|
+
cmd += bundler_argv
|
|
311
336
|
|
|
312
337
|
Dir.chdir(@app_path) do
|
|
313
338
|
exec(env, *cmd)
|
|
@@ -30,7 +30,7 @@ module Shakapacker
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def watched_files_digest
|
|
33
|
-
if
|
|
33
|
+
if env.development?
|
|
34
34
|
warn <<~MSG.strip
|
|
35
35
|
Shakapacker::Compiler - Slow setup for development
|
|
36
36
|
Prepare JS assets with either:
|
|
@@ -46,7 +46,7 @@ module Shakapacker
|
|
|
46
46
|
files = Dir[*expanded_paths].reject { |f| File.directory?(f) }
|
|
47
47
|
file_ids = files.sort.map { |f| "#{File.basename(f)}/#{Digest::SHA1.file(f).hexdigest}" }
|
|
48
48
|
|
|
49
|
-
asset_host =
|
|
49
|
+
asset_host = config.asset_host.to_s
|
|
50
50
|
Digest::SHA1.hexdigest(file_ids.join("/").concat(asset_host))
|
|
51
51
|
end
|
|
52
52
|
|
|
@@ -56,7 +56,7 @@ module Shakapacker
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def compilation_digest_path
|
|
59
|
-
config.cache_path.join("last-compilation-digest-#{
|
|
59
|
+
config.cache_path.join("last-compilation-digest-#{env}")
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
end
|