shakapacker 8.0.2 → 9.2.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.
Files changed (198) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintignore +1 -0
  3. data/.eslintrc.fast.js +40 -0
  4. data/.eslintrc.js +48 -0
  5. data/.github/STATUS.md +1 -0
  6. data/.github/workflows/claude-code-review.yml +54 -0
  7. data/.github/workflows/claude.yml +50 -0
  8. data/.github/workflows/dummy.yml +9 -4
  9. data/.github/workflows/generator.yml +32 -10
  10. data/.github/workflows/node.yml +23 -1
  11. data/.github/workflows/ruby.yml +33 -2
  12. data/.github/workflows/test-bundlers.yml +170 -0
  13. data/.gitignore +20 -0
  14. data/.husky/pre-commit +2 -0
  15. data/.npmignore +56 -0
  16. data/.prettierignore +3 -0
  17. data/.rubocop.yml +1 -0
  18. data/.yalcignore +26 -0
  19. data/CHANGELOG.md +302 -16
  20. data/CLAUDE.md +29 -0
  21. data/CONTRIBUTING.md +138 -20
  22. data/Gemfile.lock +83 -89
  23. data/README.md +343 -105
  24. data/Rakefile +39 -4
  25. data/TODO.md +50 -0
  26. data/TODO_v9.md +87 -0
  27. data/bin/export-bundler-config +11 -0
  28. data/conductor-setup.sh +70 -0
  29. data/conductor.json +7 -0
  30. data/docs/cdn_setup.md +379 -0
  31. data/docs/common-upgrades.md +615 -0
  32. data/docs/css-modules-export-mode.md +512 -0
  33. data/docs/deployment.md +62 -9
  34. data/docs/optional-peer-dependencies.md +198 -0
  35. data/docs/peer-dependencies.md +60 -0
  36. data/docs/react.md +6 -14
  37. data/docs/releasing.md +197 -0
  38. data/docs/rspack.md +190 -0
  39. data/docs/rspack_migration_guide.md +305 -0
  40. data/docs/subresource_integrity.md +54 -0
  41. data/docs/transpiler-migration.md +209 -0
  42. data/docs/transpiler-performance.md +179 -0
  43. data/docs/troubleshooting.md +157 -22
  44. data/docs/typescript-migration.md +379 -0
  45. data/docs/typescript.md +99 -0
  46. data/docs/using_esbuild_loader.md +3 -3
  47. data/docs/using_swc_loader.md +112 -10
  48. data/docs/v6_upgrade.md +10 -0
  49. data/docs/v8_upgrade.md +3 -5
  50. data/docs/v9_upgrade.md +458 -0
  51. data/gemfiles/Gemfile-rails.6.0.x +2 -1
  52. data/gemfiles/Gemfile-rails.6.1.x +1 -1
  53. data/gemfiles/Gemfile-rails.7.0.x +2 -2
  54. data/gemfiles/Gemfile-rails.7.1.x +1 -2
  55. data/gemfiles/Gemfile-rails.7.2.x +11 -0
  56. data/gemfiles/Gemfile-rails.8.0.x +11 -0
  57. data/lib/install/bin/export-bundler-config +11 -0
  58. data/lib/install/bin/shakapacker +4 -6
  59. data/lib/install/bin/shakapacker-dev-server +1 -1
  60. data/lib/install/config/rspack/rspack.config.js +6 -0
  61. data/lib/install/config/rspack/rspack.config.ts +7 -0
  62. data/lib/install/config/shakapacker.yml +25 -5
  63. data/lib/install/config/webpack/webpack.config.ts +7 -0
  64. data/lib/install/package.json +38 -0
  65. data/lib/install/template.rb +194 -44
  66. data/lib/shakapacker/bundler_switcher.rb +329 -0
  67. data/lib/shakapacker/compiler.rb +2 -1
  68. data/lib/shakapacker/compiler_strategy.rb +2 -2
  69. data/lib/shakapacker/configuration.rb +173 -2
  70. data/lib/shakapacker/dev_server_runner.rb +29 -8
  71. data/lib/shakapacker/digest_strategy.rb +2 -1
  72. data/lib/shakapacker/doctor.rb +905 -0
  73. data/lib/shakapacker/helper.rb +64 -16
  74. data/lib/shakapacker/manifest.rb +10 -3
  75. data/lib/shakapacker/mtime_strategy.rb +1 -1
  76. data/lib/shakapacker/railtie.rb +4 -4
  77. data/lib/shakapacker/rspack_runner.rb +19 -0
  78. data/lib/shakapacker/runner.rb +159 -10
  79. data/lib/shakapacker/swc_migrator.rb +384 -0
  80. data/lib/shakapacker/utils/manager.rb +15 -2
  81. data/lib/shakapacker/version.rb +1 -1
  82. data/lib/shakapacker/version_checker.rb +2 -2
  83. data/lib/shakapacker/webpack_runner.rb +6 -43
  84. data/lib/shakapacker.rb +22 -11
  85. data/lib/tasks/shakapacker/doctor.rake +8 -0
  86. data/lib/tasks/shakapacker/export_bundler_config.rake +72 -0
  87. data/lib/tasks/shakapacker/install.rake +12 -2
  88. data/lib/tasks/shakapacker/migrate_to_swc.rake +13 -0
  89. data/lib/tasks/shakapacker/switch_bundler.rake +82 -0
  90. data/lib/tasks/shakapacker.rake +2 -0
  91. data/package/.npmignore +4 -0
  92. data/package/babel/preset.ts +56 -0
  93. data/package/config.ts +175 -0
  94. data/package/configExporter/cli.ts +683 -0
  95. data/package/configExporter/configDocs.ts +102 -0
  96. data/package/configExporter/fileWriter.ts +92 -0
  97. data/package/configExporter/index.ts +5 -0
  98. data/package/configExporter/types.ts +36 -0
  99. data/package/configExporter/yamlSerializer.ts +266 -0
  100. data/package/{dev_server.js → dev_server.ts} +8 -5
  101. data/package/env.ts +92 -0
  102. data/package/environments/__type-tests__/rspack-plugin-compatibility.ts +30 -0
  103. data/package/environments/{base.js → base.ts} +56 -60
  104. data/package/environments/development.ts +90 -0
  105. data/package/environments/production.ts +80 -0
  106. data/package/environments/test.ts +53 -0
  107. data/package/environments/types.ts +98 -0
  108. data/package/esbuild/index.ts +42 -0
  109. data/package/index.d.ts +3 -60
  110. data/package/index.ts +55 -0
  111. data/package/loaders.d.ts +28 -0
  112. data/package/optimization/rspack.ts +36 -0
  113. data/package/optimization/webpack.ts +57 -0
  114. data/package/plugins/rspack.ts +103 -0
  115. data/package/plugins/webpack.ts +62 -0
  116. data/package/rspack/index.ts +64 -0
  117. data/package/rules/{babel.js → babel.ts} +2 -2
  118. data/package/rules/{coffee.js → coffee.ts} +1 -1
  119. data/package/rules/css.ts +3 -0
  120. data/package/rules/{erb.js → erb.ts} +1 -1
  121. data/package/rules/esbuild.ts +10 -0
  122. data/package/rules/file.ts +40 -0
  123. data/package/rules/{jscommon.js → jscommon.ts} +4 -4
  124. data/package/rules/{less.js → less.ts} +4 -4
  125. data/package/rules/raw.ts +25 -0
  126. data/package/rules/rspack.ts +176 -0
  127. data/package/rules/{sass.js → sass.ts} +7 -3
  128. data/package/rules/{stylus.js → stylus.ts} +4 -8
  129. data/package/rules/swc.ts +10 -0
  130. data/package/rules/webpack.ts +16 -0
  131. data/package/swc/index.ts +56 -0
  132. data/package/types/README.md +88 -0
  133. data/package/types/index.ts +61 -0
  134. data/package/types.ts +108 -0
  135. data/package/utils/configPath.ts +6 -0
  136. data/package/utils/debug.ts +49 -0
  137. data/package/utils/defaultConfigPath.ts +4 -0
  138. data/package/utils/errorCodes.ts +219 -0
  139. data/package/utils/errorHelpers.ts +143 -0
  140. data/package/utils/getStyleRule.ts +64 -0
  141. data/package/utils/helpers.ts +85 -0
  142. data/package/utils/{inliningCss.js → inliningCss.ts} +3 -3
  143. data/package/utils/pathValidation.ts +139 -0
  144. data/package/utils/requireOrError.ts +15 -0
  145. data/package/utils/snakeToCamelCase.ts +5 -0
  146. data/package/utils/typeGuards.ts +342 -0
  147. data/package/utils/validateDependencies.ts +61 -0
  148. data/package/webpack-types.d.ts +33 -0
  149. data/package/webpackDevServerConfig.ts +117 -0
  150. data/package-lock.json +13047 -0
  151. data/package.json +154 -18
  152. data/scripts/remove-use-strict.js +45 -0
  153. data/scripts/type-check-no-emit.js +27 -0
  154. data/test/helpers.js +1 -1
  155. data/test/package/config.test.js +43 -0
  156. data/test/package/env.test.js +42 -7
  157. data/test/package/environments/base.test.js +5 -1
  158. data/test/package/rules/babel.test.js +16 -0
  159. data/test/package/rules/esbuild.test.js +1 -1
  160. data/test/package/rules/raw.test.js +40 -7
  161. data/test/package/rules/swc.test.js +1 -1
  162. data/test/package/rules/webpack.test.js +35 -0
  163. data/test/package/staging.test.js +4 -3
  164. data/test/package/transpiler-defaults.test.js +127 -0
  165. data/test/peer-dependencies.sh +85 -0
  166. data/test/scripts/remove-use-strict.test.js +125 -0
  167. data/test/typescript/build.test.js +118 -0
  168. data/test/typescript/environments.test.js +107 -0
  169. data/test/typescript/pathValidation.test.js +142 -0
  170. data/test/typescript/securityValidation.test.js +182 -0
  171. data/tools/README.md +124 -0
  172. data/tools/css-modules-v9-codemod.js +179 -0
  173. data/tsconfig.eslint.json +16 -0
  174. data/tsconfig.json +38 -0
  175. data/yarn.lock +4165 -2706
  176. metadata +129 -41
  177. data/package/babel/preset.js +0 -37
  178. data/package/config.js +0 -54
  179. data/package/env.js +0 -48
  180. data/package/environments/development.js +0 -13
  181. data/package/environments/production.js +0 -88
  182. data/package/environments/test.js +0 -3
  183. data/package/esbuild/index.js +0 -40
  184. data/package/index.js +0 -40
  185. data/package/rules/css.js +0 -3
  186. data/package/rules/esbuild.js +0 -10
  187. data/package/rules/file.js +0 -29
  188. data/package/rules/index.js +0 -20
  189. data/package/rules/raw.js +0 -5
  190. data/package/rules/swc.js +0 -10
  191. data/package/swc/index.js +0 -50
  192. data/package/utils/configPath.js +0 -4
  193. data/package/utils/defaultConfigPath.js +0 -2
  194. data/package/utils/getStyleRule.js +0 -40
  195. data/package/utils/helpers.js +0 -58
  196. data/package/utils/snakeToCamelCase.js +0 -5
  197. data/package/webpackDevServerConfig.js +0 -71
  198. data/test/package/rules/index.test.js +0 -16
@@ -95,22 +95,25 @@ module Shakapacker::Helper
95
95
  #
96
96
  # <%= javascript_pack_tag 'calendar' %>
97
97
  # <%= javascript_pack_tag 'map' %>
98
- def javascript_pack_tag(*names, defer: true, **options)
98
+ def javascript_pack_tag(*names, defer: true, async: false, **options)
99
99
  if @javascript_pack_tag_loaded
100
100
  raise "To prevent duplicated chunks on the page, you should call javascript_pack_tag only once on the page. " \
101
101
  "Please refer to https://github.com/shakacode/shakapacker/blob/main/README.md#view-helpers-javascript_pack_tag-and-stylesheet_pack_tag for the usage guide"
102
102
  end
103
103
 
104
- append_javascript_pack_tag(*names, defer: defer)
105
- non_deferred = sources_from_manifest_entrypoints(javascript_pack_tag_queue[:non_deferred], type: :javascript)
106
- deferred = sources_from_manifest_entrypoints(javascript_pack_tag_queue[:deferred], type: :javascript) - non_deferred
104
+ append_javascript_pack_tag(*names, defer: defer, async: async)
105
+ sync = sources_from_manifest_entrypoints(javascript_pack_tag_queue[:sync], type: :javascript)
106
+ async = sources_from_manifest_entrypoints(javascript_pack_tag_queue[:async], type: :javascript) - sync
107
+ deferred = sources_from_manifest_entrypoints(javascript_pack_tag_queue[:deferred], type: :javascript) - sync - async
107
108
 
108
109
  @javascript_pack_tag_loaded = true
109
110
 
110
111
  capture do
111
- concat javascript_include_tag(*deferred, **options.tap { |o| o[:defer] = true })
112
- concat "\n" if non_deferred.any? && deferred.any?
113
- concat javascript_include_tag(*non_deferred, **options.tap { |o| o[:defer] = false })
112
+ render_tags(async, :javascript, **options.dup.tap { |o| o[:async] = true })
113
+ concat "\n" if async.any? && deferred.any?
114
+ render_tags(deferred, :javascript, **options.dup.tap { |o| o[:defer] = true })
115
+ concat "\n" if sync.any? && deferred.any?
116
+ render_tags(sync, :javascript, options)
114
117
  end
115
118
  end
116
119
 
@@ -163,7 +166,9 @@ module Shakapacker::Helper
163
166
 
164
167
  @stylesheet_pack_tag_loaded = true
165
168
 
166
- stylesheet_link_tag(*(requested_packs | appended_packs), **options)
169
+ capture do
170
+ render_tags(requested_packs | appended_packs, :stylesheet, options)
171
+ end
167
172
  end
168
173
 
169
174
  def append_stylesheet_pack_tag(*names)
@@ -179,27 +184,35 @@ module Shakapacker::Helper
179
184
  nil
180
185
  end
181
186
 
182
- def append_javascript_pack_tag(*names, defer: true)
183
- update_javascript_pack_tag_queue(defer: defer) do |hash_key|
187
+ def append_javascript_pack_tag(*names, defer: true, async: false)
188
+ update_javascript_pack_tag_queue(defer: defer, async: async) do |hash_key|
184
189
  javascript_pack_tag_queue[hash_key] |= names
185
190
  end
186
191
  end
187
192
 
188
- def prepend_javascript_pack_tag(*names, defer: true)
189
- update_javascript_pack_tag_queue(defer: defer) do |hash_key|
193
+ def prepend_javascript_pack_tag(*names, defer: true, async: false)
194
+ update_javascript_pack_tag_queue(defer: defer, async: async) do |hash_key|
190
195
  javascript_pack_tag_queue[hash_key].unshift(*names)
191
196
  end
192
197
  end
193
198
 
194
199
  private
195
200
 
196
- def update_javascript_pack_tag_queue(defer:)
201
+ def update_javascript_pack_tag_queue(defer:, async:)
197
202
  if @javascript_pack_tag_loaded
198
- raise "You can only call #{caller_locations(1..1).first.label} before javascript_pack_tag helper. " \
203
+ raise "You can only call #{caller_locations(1..1).first.base_label} before javascript_pack_tag helper. " \
199
204
  "Please refer to https://github.com/shakacode/shakapacker/blob/main/README.md#view-helper-append_javascript_pack_tag-prepend_javascript_pack_tag-and-append_stylesheet_pack_tag for the usage guide"
200
205
  end
201
206
 
202
- yield(defer ? :deferred : :non_deferred)
207
+ # When both async and defer are specified, async takes precedence per HTML5 spec
208
+ hash_key = if async
209
+ :async
210
+ elsif defer
211
+ :deferred
212
+ else
213
+ :sync
214
+ end
215
+ yield(hash_key)
203
216
 
204
217
  # prevent rendering Array#to_s representation when used with <%= … %> syntax
205
218
  nil
@@ -207,8 +220,9 @@ module Shakapacker::Helper
207
220
 
208
221
  def javascript_pack_tag_queue
209
222
  @javascript_pack_tag_queue ||= {
223
+ async: [],
210
224
  deferred: [],
211
- non_deferred: []
225
+ sync: []
212
226
  }
213
227
  end
214
228
 
@@ -226,4 +240,38 @@ module Shakapacker::Helper
226
240
  rescue
227
241
  path_to_asset(current_shakapacker_instance.manifest.lookup!(name), options)
228
242
  end
243
+
244
+ def lookup_integrity(source)
245
+ (source.respond_to?(:dig) && source.dig("integrity")) || nil
246
+ end
247
+
248
+ def lookup_source(source)
249
+ (source.respond_to?(:dig) && source.dig("src")) || source
250
+ end
251
+
252
+ # Handles rendering javascript and stylesheet tags with integrity, if that's enabled.
253
+ def render_tags(sources, type, options)
254
+ return unless sources.present? || type.present?
255
+
256
+ sources.each.with_index do |source, index|
257
+ tag_source = lookup_source(source)
258
+
259
+ if current_shakapacker_instance.config.integrity[:enabled]
260
+ integrity = lookup_integrity(source)
261
+
262
+ if integrity.present?
263
+ options[:integrity] = integrity
264
+ options[:crossorigin] = current_shakapacker_instance.config.integrity[:cross_origin]
265
+ end
266
+ end
267
+
268
+ if type == :javascript
269
+ concat javascript_include_tag(tag_source, **options)
270
+ else
271
+ concat stylesheet_link_tag(tag_source, **options)
272
+ end
273
+
274
+ concat "\n" unless index == sources.size - 1
275
+ end
276
+ end
229
277
  end
@@ -67,7 +67,12 @@ class Shakapacker::Manifest
67
67
  end
68
68
 
69
69
  def find(name)
70
- data[name.to_s].presence
70
+ return nil unless data[name.to_s].present?
71
+
72
+ return data[name.to_s] unless data[name.to_s].respond_to?(:dig)
73
+
74
+ # Try to return src, if that fails, (ex. entrypoints object) return the whole object.
75
+ data[name.to_s].dig("src") || data[name.to_s]
71
76
  end
72
77
 
73
78
  def full_pack_name(name, pack_type)
@@ -103,15 +108,17 @@ class Shakapacker::Manifest
103
108
  end
104
109
 
105
110
  def missing_file_from_manifest_error(bundle_name)
111
+ bundler_name = config.assets_bundler
106
112
  <<-MSG
107
113
  Shakapacker can't find #{bundle_name} in #{config.manifest_path}. Possible causes:
108
114
  1. You forgot to install javascript packages or are running an incompatible javascript runtime version
109
115
  2. Your app has code with a non-standard extension (like a `.jsx` file) but the extension is not in the `extensions` config in `config/shakapacker.yml`
110
116
  3. You have set compile: false (see `config/shakapacker.yml`) for this environment
111
117
  (unless you are using the `bin/shakapacker -w` or the `bin/shakapacker-dev-server`, in which case maybe you aren't running the dev server in the background?)
112
- 4. webpack has not yet FINISHED running to reflect updates.
118
+ 4. Your #{bundler_name} has not yet FINISHED running to reflect updates.
113
119
  5. You have misconfigured Shakapacker's `config/shakapacker.yml` file.
114
- 6. Your webpack configuration is not creating a manifest.
120
+ 6. Your #{bundler_name} configuration is not creating a manifest with the expected structure.
121
+ 7. Ensure the 'assets_bundler' in config/shakapacker.yml is set correctly (currently: #{bundler_name}).
115
122
 
116
123
  Your manifest contains:
117
124
  #{JSON.pretty_generate(@data)}
@@ -1,4 +1,4 @@
1
- require "shakapacker/base_strategy"
1
+ require_relative "base_strategy"
2
2
 
3
3
  module Shakapacker
4
4
  class MtimeStrategy < BaseStrategy
@@ -1,9 +1,9 @@
1
1
  require "rails/railtie"
2
2
 
3
- require "shakapacker/helper"
4
- require "shakapacker/dev_server_proxy"
5
- require "shakapacker/version_checker"
6
- require "shakapacker/utils/manager"
3
+ require_relative "helper"
4
+ require_relative "dev_server_proxy"
5
+ require_relative "version_checker"
6
+ require_relative "utils/manager"
7
7
 
8
8
  class Shakapacker::Engine < ::Rails::Engine
9
9
  # Allows Shakapacker config values to be set via Rails env config files
@@ -0,0 +1,19 @@
1
+ require "shellwords"
2
+
3
+ require_relative "runner"
4
+
5
+ module Shakapacker
6
+ class RspackRunner < Shakapacker::Runner
7
+ def self.run(argv)
8
+ $stdout.sync = true
9
+ Shakapacker.ensure_node_env!
10
+ new(argv).run
11
+ end
12
+
13
+ private
14
+
15
+ def build_cmd
16
+ package_json.manager.native_exec_command("rspack")
17
+ end
18
+ end
19
+ end
@@ -1,26 +1,73 @@
1
- require "shakapacker/utils/misc"
2
- require "shakapacker/utils/manager"
1
+ require_relative "utils/misc"
2
+ require_relative "utils/manager"
3
+ require_relative "configuration"
4
+
3
5
  require "package_json"
6
+ require "pathname"
4
7
 
5
8
  module Shakapacker
6
9
  class Runner
10
+ attr_reader :config
11
+
12
+ # Common commands that don't work with --config option
13
+ BASE_COMMANDS = [
14
+ "help",
15
+ "h",
16
+ "--help",
17
+ "-h",
18
+ "version",
19
+ "v",
20
+ "--version",
21
+ "-v",
22
+ "info",
23
+ "i"
24
+ ].freeze
7
25
  def self.run(argv)
8
26
  $stdout.sync = true
9
- ENV["NODE_ENV"] ||= (ENV["RAILS_ENV"] == "production") ? "production" : "development"
10
- new(argv).run
27
+ Shakapacker.ensure_node_env!
28
+
29
+ # Create a single runner instance to avoid loading configuration twice.
30
+ # We extend it with the appropriate build command based on the bundler type.
31
+ runner = new(argv)
32
+
33
+ if runner.config.rspack?
34
+ require_relative "rspack_runner"
35
+ # Extend the runner instance with rspack-specific methods
36
+ # This avoids creating a new RspackRunner which would reload the configuration
37
+ runner.extend(Module.new do
38
+ def build_cmd
39
+ package_json.manager.native_exec_command("rspack")
40
+ end
41
+
42
+ def assets_bundler_commands
43
+ BASE_COMMANDS + %w[build watch]
44
+ end
45
+ end)
46
+ runner.run
47
+ else
48
+ require_relative "webpack_runner"
49
+ # Extend the runner instance with webpack-specific methods
50
+ # This avoids creating a new WebpackRunner which would reload the configuration
51
+ runner.extend(Module.new do
52
+ def build_cmd
53
+ package_json.manager.native_exec_command("webpack")
54
+ end
55
+ end)
56
+ runner.run
57
+ end
11
58
  end
12
59
 
13
60
  def initialize(argv)
14
61
  @argv = argv
15
62
 
16
63
  @app_path = File.expand_path(".", Dir.pwd)
17
- @webpack_config = File.join(@app_path, "config/webpack/webpack.config.js")
18
64
  @shakapacker_config = ENV["SHAKAPACKER_CONFIG"] || File.join(@app_path, "config/shakapacker.yml")
19
-
20
- unless File.exist?(@webpack_config)
21
- $stderr.puts "webpack config #{@webpack_config} not found, please run 'bundle exec rails shakapacker:install' to install Shakapacker with default configs or add the missing config file for your custom environment."
22
- exit!
23
- end
65
+ @config = Configuration.new(
66
+ root_path: Pathname.new(@app_path),
67
+ config_path: Pathname.new(@shakapacker_config),
68
+ env: ENV["RAILS_ENV"] || ENV["NODE_ENV"] || "development"
69
+ )
70
+ @webpack_config = find_assets_bundler_config
24
71
 
25
72
  Shakapacker::Utils::Manager.error_unless_package_manager_is_obvious!
26
73
  end
@@ -28,5 +75,107 @@ module Shakapacker
28
75
  def package_json
29
76
  @package_json ||= PackageJson.read(@app_path)
30
77
  end
78
+
79
+ def run
80
+ puts "[Shakapacker] Preparing environment for assets bundler execution..."
81
+ env = Shakapacker::Compiler.env
82
+ env["SHAKAPACKER_CONFIG"] = @shakapacker_config
83
+ env["NODE_OPTIONS"] = ENV["NODE_OPTIONS"] || ""
84
+
85
+ cmd = build_cmd
86
+ puts "[Shakapacker] Base command: #{cmd.join(" ")}"
87
+
88
+ if @argv.delete("--debug-shakapacker")
89
+ puts "[Shakapacker] Debug mode enabled (--debug-shakapacker)"
90
+ env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --inspect-brk"
91
+ end
92
+
93
+ if @argv.delete "--trace-deprecation"
94
+ puts "[Shakapacker] Trace deprecation enabled (--trace-deprecation)"
95
+ env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --trace-deprecation"
96
+ end
97
+
98
+ if @argv.delete "--no-deprecation"
99
+ puts "[Shakapacker] Deprecation warnings disabled (--no-deprecation)"
100
+ env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --no-deprecation"
101
+ end
102
+
103
+ # Commands are not compatible with --config option.
104
+ if (@argv & assets_bundler_commands).empty?
105
+ puts "[Shakapacker] Adding config file: #{@webpack_config}"
106
+ cmd += ["--config", @webpack_config]
107
+ else
108
+ puts "[Shakapacker] Skipping config file (running assets bundler command: #{(@argv & assets_bundler_commands).join(", ")})"
109
+ end
110
+
111
+ cmd += @argv
112
+ puts "[Shakapacker] Final command: #{cmd.join(" ")}"
113
+ puts "[Shakapacker] Working directory: #{@app_path}"
114
+
115
+ Dir.chdir(@app_path) do
116
+ Kernel.exec env, *cmd
117
+ end
118
+ end
119
+
120
+ protected
121
+
122
+ def assets_bundler_commands
123
+ BASE_COMMANDS
124
+ end
125
+
126
+ private
127
+ def find_assets_bundler_config
128
+ if @config.rspack?
129
+ find_rspack_config_with_fallback
130
+ else
131
+ find_webpack_config
132
+ end
133
+ end
134
+
135
+ def find_rspack_config_with_fallback
136
+ # First try rspack-specific paths
137
+ rspack_paths = %w[ts js].map do |ext|
138
+ File.join(@app_path, "config/rspack/rspack.config.#{ext}")
139
+ end
140
+
141
+ puts "[Shakapacker] Looking for Rspack config in: #{rspack_paths.join(", ")}"
142
+ rspack_path = rspack_paths.find { |f| File.exist?(f) }
143
+ if rspack_path
144
+ puts "[Shakapacker] Found Rspack config: #{rspack_path}"
145
+ return rspack_path
146
+ end
147
+
148
+ # Fallback to webpack config with deprecation warning
149
+ webpack_paths = %w[ts js].map do |ext|
150
+ File.join(@app_path, "config/webpack/webpack.config.#{ext}")
151
+ end
152
+
153
+ puts "[Shakapacker] Rspack config not found, checking for webpack config fallback..."
154
+ webpack_path = webpack_paths.find { |f| File.exist?(f) }
155
+ if webpack_path
156
+ $stderr.puts "⚠️ DEPRECATION WARNING: Using webpack config file for Rspack assets bundler."
157
+ $stderr.puts " Please create config/rspack/rspack.config.js and migrate your configuration."
158
+ $stderr.puts " Using: #{webpack_path}"
159
+ return webpack_path
160
+ end
161
+
162
+ # No config found
163
+ $stderr.puts "[Shakapacker] ERROR: rspack config #{rspack_paths.last} not found, please run 'bundle exec rails shakapacker:install' to install Shakapacker with default configs or create the missing config file."
164
+ exit(1)
165
+ end
166
+
167
+ def find_webpack_config
168
+ possible_paths = %w[ts js].map do |ext|
169
+ File.join(@app_path, "config/webpack/webpack.config.#{ext}")
170
+ end
171
+ puts "[Shakapacker] Looking for Webpack config in: #{possible_paths.join(", ")}"
172
+ path = possible_paths.find { |f| File.exist?(f) }
173
+ unless path
174
+ $stderr.puts "[Shakapacker] ERROR: webpack config #{possible_paths.last} not found, please run 'bundle exec rails shakapacker:install' to install Shakapacker with default configs or add the missing config file for your custom environment."
175
+ exit(1)
176
+ end
177
+ puts "[Shakapacker] Found Webpack config: #{path}"
178
+ path
179
+ end
31
180
  end
32
181
  end