shakapacker 10.3.0 → 10.3.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9066233e8c71edd7018db4b397e132013a8dcde79a111acbd6f3a79617fa9367
4
- data.tar.gz: 1e7d899486f7bf0c43cebb923ba4a013bd5bdb7e4348193662872a5b77278208
3
+ metadata.gz: d74b345013f03450e4cd5050bd22f2364e2acf8b00a750acf833b07eda6046c7
4
+ data.tar.gz: 4933ffb9d1feb7acc0bdcb2a06fb492b030ea347976da728dd83a7e4b7f3790f
5
5
  SHA512:
6
- metadata.gz: 6becce7cfd7598aeb8b6cb734882e0dbd6668125e61c711608d81e242724c8b27d613efdf5cecff77e737ca46d8f8c5c727938c5bbb13551f3394f7149d495a0
7
- data.tar.gz: f56d65242942ce8ce7b372af52b28a7a62dd6ce47c7fce5b4268bd638d22691276166796620179682b0b61ad2cc4028d951219d208652f84a99cb60bf0d8757a
6
+ metadata.gz: 1a286328ea129dc5e2c9baad6fae0aaeec4c886533a10489301e3396fd45ac3fb9b3db35455407de79eda6506d983c0a474ba7c69ea2e68eed99b715700ae274
7
+ data.tar.gz: 1411acd0a7475961d10fc0a8e99bfa76e235b1c9e83ff7e9a152f726c578e2ac0cb5654dced3a52a492e62d75fc741cf68f8a6cd0deabc23ed294229e87a874e
data/CHANGELOG.md CHANGED
@@ -10,6 +10,35 @@
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [v10.3.2] - August 28, 2026
14
+
15
+ ### Changed
16
+
17
+ - **Bumped the development and CI pin for Rspack from `2.0.1` to `2.2.0`.** [PR #1258](https://github.com/shakacode/shakapacker/pull/1258) by [justin808](https://github.com/justin808). The `@rspack/core`, `@rspack/cli`, `@rspack/dev-server`, and `@rspack/plugin-react-refresh` peer ranges are unchanged at `^2.0.0`, so applications may stay on any Rspack `2.x` release; only this repository's own development pins and dummy-app lockfiles move, so CI now exercises Rspack 2.2 against the range it already advertises. Annotated config exports (`bin/shakapacker-config --annotate`) also now list the complete `optimization.moduleIds` and `optimization.chunkIds` value sets for both bundlers, including `'compat-hashed'`, which requires Rspack 2.2 or newer and is documented as opt-in rather than made a default.
18
+
19
+ ### Fixed
20
+
21
+ - **Fixed `shakapacker:doctor` not telling Rspack apps that a `.swcrc` is ignored outright.** [PR #1276](https://github.com/shakacode/shakapacker/pull/1276) by [justin808](https://github.com/justin808). Doctor previously told Rspack apps only that moving `.swcrc` settings into `config/swc.config.js` would not help, while deliberately making no claim about the `.swcrc` itself, because the behavior had never been verified. It has now been verified against `@rspack/core` 2.0.1 and 2.2.0: Rspack's `builtin:swc-loader` never reads `.swcrc`. A `.swcrc` setting `jsc.target` and injecting an optimizer global produced byte-identical output to no `.swcrc` at all, while the same options passed inline as loader options did change the output. A `.swcrc` enabling decorator syntax likewise failed to unblock a decorator source, including with empty loader options and with `swcrc`/`configFile` set, so this is not merely inline options taking precedence. Doctor now states that a `.swcrc` is not read on Rspack and that every setting in it is silently inert - the mirror image of the `config/swc.config.js` case in [#1259](https://github.com/shakacode/shakapacker/issues/1259) - and continues to point at overriding the built-in `builtin:swc-loader` rule. Webpack messaging is unchanged. Fixes [#1263](https://github.com/shakacode/shakapacker/issues/1263).
22
+ - **Fixed `shakapacker:doctor` staying silent about SWC configuration on Rspack apps that do not set `javascript_transpiler: swc`.** [PR #1269](https://github.com/shakacode/shakapacker/pull/1269) by [justin808](https://github.com/justin808). Shakapacker's Rspack rules always transpile with `builtin:swc-loader` and never consult `javascript_transpiler`, so `config/swc.config.js` goes unread on an Rspack app configured for Babel or esbuild exactly as it does on one configured for SWC. Doctor's Rspack SWC-configuration warnings were gated on `javascript_transpiler: swc`, so those apps got no warning at all. Those warnings now reach any Rspack app: that `config/swc.config.js` is not read, and, for a `.swcrc`, that moving its settings into `config/swc.config.js` would not affect the build. The webpack-only SWC content checks and the "merged with Shakapacker's defaults" messaging stay gated on `javascript_transpiler: swc`, and apps with `javascript_transpiler: none` remain opted out. Fixes [#1265](https://github.com/shakacode/shakapacker/issues/1265).
23
+ - **Fixed `shakapacker:doctor` and `rake shakapacker:migrate_to_swc` telling Rspack apps that `config/swc.config.js` is merged into their build.** [PR #1260](https://github.com/shakacode/shakapacker/pull/1260) by [justin808](https://github.com/justin808). Rspack builds never read `config/swc.config.js`, because Shakapacker's Rspack rules set their `builtin:swc-loader` options inline. Doctor now warns that the file is unread on Rspack instead of reporting it as merged (and skips its content checks there), and no longer tells Rspack users with a `.swcrc` to migrate those settings into `config/swc.config.js`. The migrator's post-migration guidance and the generated file header instead show how to override the built-in `builtin:swc-loader` rule: apply `webpack-merge`'s `mergeWithRules` to the _output_ of `generateRspackConfig()`, since that function merges with plain `merge`, which concatenates `module.rules`, so an override passed into it is appended alongside the built-in rule rather than replacing it. Webpack apps keep the existing messaging. Fixes [#1259](https://github.com/shakacode/shakapacker/issues/1259).
24
+ - **Fixed post-publish GitHub release failures hiding successful package publication details.** The release task now prints its normal publication summary and the exact `sync_github_release` recovery command before exiting nonzero. [PR #1250](https://github.com/shakacode/shakapacker/pull/1250) by [justin808](https://github.com/justin808).
25
+ - **Fixed helper binstubs to fail closed when `PATH` is unset.** [PR #1240](https://github.com/shakacode/shakapacker/pull/1240) by [justin808](https://github.com/justin808). `bin/shakapacker-config` and `bin/diff-bundler-config` now report the missing-Node error without executing an app-root `node` binary when `PATH` is unset, while explicit `PATH` values retain their existing Node-resolution behavior. Fixes [#1234](https://github.com/shakacode/shakapacker/issues/1234).
26
+ - **Fixed the deprecation warning for the legacy `bundler` config key claiming the value was understood while it was ignored.** [PR #1270](https://github.com/shakacode/shakapacker/pull/1270) by [justin808](https://github.com/justin808). An app whose `config/shakapacker.yml` set only `bundler:` was told the key was deprecated and then built with a different bundler, because `assets_bundler` always resolves from the bundled defaults and the legacy key was never read. The warning now states that the value is ignored, names the bundler actually in use, and tells you to set `assets_bundler` instead. One resolution change accompanies it: a config that leaves `assets_bundler:` blank while setting `bundler:` previously resolved the legacy value in Ruby and now resolves `webpack`, matching what `package/config.ts` already built for it. Fixes [#1262](https://github.com/shakacode/shakapacker/issues/1262).
27
+
28
+ ## [v10.3.1] - August 3, 2026
29
+
30
+ ### Fixed
31
+
32
+ - **Fixed 502 responses for proxied dev server assets under `rack-proxy` v1.** [PR #1222](https://github.com/shakacode/shakapacker/pull/1222) by [jcbpl](https://github.com/jcbpl). Fixes [#1220](https://github.com/shakacode/shakapacker/issues/1220).
33
+ - **Fixed dev-server liveness checks treating refused macOS 27 connections as running.** The Ruby probe now verifies the connected socket's `SO_ERROR` result before proxying asset requests, avoiding false-positive dev-server detection and resulting 502 responses. [PR #1225](https://github.com/shakacode/shakapacker/pull/1225) by [justin808](https://github.com/justin808). Fixes [#1224](https://github.com/shakacode/shakapacker/issues/1224).
34
+ - **Fixed webpack Babel, SWC, and esbuild rules skipping explicitly included `.cjs` files.** [PR #1219](https://github.com/shakacode/shakapacker/pull/1219) by [oiahoon](https://github.com/oiahoon). Fixes [#1218](https://github.com/shakacode/shakapacker/issues/1218).
35
+ - **Added a `shakapacker:doctor` warning for Rspack React Refresh v2 configs that still use the v1 default-export constructor pattern.** [PR #1207](https://github.com/shakacode/shakapacker/pull/1207) by [justin808](https://github.com/justin808). Existing configs with `const ReactRefreshPlugin = require("@rspack/plugin-react-refresh")` followed by `new ReactRefreshPlugin()` can fail after upgrading to `@rspack/plugin-react-refresh` v2 with `ReactRefreshPlugin is not a constructor`; Doctor now points to the affected JS/TS config file and suggests the named-export/default/module compatibility form. Fixes [#1204](https://github.com/shakacode/shakapacker/issues/1204).
36
+ - **Fixed the missing-`@babel/core` failure to report an actionable install message.** [PR #1212](https://github.com/shakacode/shakapacker/pull/1212) by [justin808](https://github.com/justin808). Babel-transpiled builds whose app lacks `@babel/core` previously surfaced a raw module-resolution error from the Babel 8 compatibility check; the rule now explains which package to install and how to switch `javascript_transpiler` instead. Refs [#1163](https://github.com/shakacode/shakapacker/issues/1163).
37
+
38
+ ### Documentation
39
+
40
+ - **Documented the required `css-loader@^7.1.4` in the v10 Rspack upgrade instructions.** [PR #1211](https://github.com/shakacode/shakapacker/pull/1211) by [justin808](https://github.com/justin808). The v10 upgrade guide's copy-paste Rspack v2 commands omitted `css-loader`, so apps following them could upgrade into an unsatisfied peer dependency.
41
+
13
42
  ## [v10.3.0] - July 5, 2026
14
43
 
15
44
  ### Added
@@ -20,7 +49,7 @@
20
49
 
21
50
  - **Fixed implicit SWC defaults for existing webpack/Babel apps without `swc-loader`.** [PR #1206](https://github.com/shakacode/shakapacker/pull/1206) by [justin808](https://github.com/justin808). Webpack apps that omit both `javascript_transpiler` and the deprecated `webpack_loader` now fall back to Babel with a warning when Shakapacker's bundled SWC default is active, `swc-loader` is missing, and Babel is present. Explicit transpiler settings, webpack apps with `swc-loader`, and Rspack's built-in SWC path keep their existing behavior. Closes [#1203](https://github.com/shakacode/shakapacker/issues/1203).
22
51
  - **Fixed JavaScript config loading for missing Rails environments to use the production fallback.** [PR #1206](https://github.com/shakacode/shakapacker/pull/1206) by [justin808](https://github.com/justin808). When `RAILS_ENV` has no matching section in `config/shakapacker.yml`, the Node package config now merges the `production` section instead of only bundled defaults, matching Ruby configuration loading and honoring explicit production `javascript_transpiler`, `source_path`, `dev_server`, and related settings for custom environments such as staging.
23
- - **Fixed helper binstubs delegating Node resolution to Ruby `exec` in unset and empty `PATH` environments.** [PR #1200](https://github.com/shakacode/shakapacker/pull/1200) and [PR #1201](https://github.com/shakacode/shakapacker/pull/1201) by [justin808](https://github.com/justin808). Restores shell-compatible Node lookup for `bin/shakapacker-config` and `bin/diff-bundler-config` after the `v10.2.0` Ruby-binstub regression, while keeping friendly missing-Node errors for `ENOENT` and `EACCES`.
52
+ - **Fixed helper binstub Node resolution after the `v10.2.0` Ruby-binstub regression.** [PR #1200](https://github.com/shakacode/shakapacker/pull/1200) and [PR #1201](https://github.com/shakacode/shakapacker/pull/1201) by [justin808](https://github.com/justin808). Restores shell-compatible Node lookup for `bin/shakapacker-config` and `bin/diff-bundler-config` when `PATH` is empty, while keeping friendly missing-Node errors for `ENOENT` and `EACCES`. For an unset `PATH`, PR #1200 deliberately delegates Node resolution to Ruby `exec`'s default-path behavior; PR #1240 later changed that case to fail closed.
24
53
 
25
54
  ## [v10.2.0] - July 3, 2026
26
55
 
@@ -63,7 +92,7 @@
63
92
  - Optional peers (transpilers, `webpack-dev-server`, CSS preprocessors, react-refresh) stay only if your app uses those features.
64
93
  - Adoption is opt-in: leaving your `package.json` untouched on v10.1 also continues to work.
65
94
 
66
- - **Adopting `shakapacker-webpack` requires `webpack-assets-manifest@^6.0.0`**. Core `shakapacker` still accepts both v5 and v6 (`^5.0.6 || ^6.0.0`), but `shakapacker-webpack` pins `~6.5.1`. Apps still on `webpack-assets-manifest@5.x` must upgrade when switching to the supplemental package; v6 fixed an ENOENT crash on clean builds with `merge: true` and dropped a Node 14 install path. See [the v5→v6 release notes](https://github.com/webdeveric/webpack-assets-manifest/releases) and `packages/shakapacker-webpack/README.md` for details.
95
+ - **Adopting `shakapacker-webpack` requires `webpack-assets-manifest@^6.0.0`**. [PR #1096](https://github.com/shakacode/shakapacker/pull/1096) and [PR #1133](https://github.com/shakacode/shakapacker/pull/1133) by [justin808](https://github.com/justin808). Core `shakapacker` still accepts both v5 and v6 (`^5.0.6 || ^6.0.0`), and `shakapacker-webpack` requires `^6.0.0`. Apps still on `webpack-assets-manifest@5.x` must upgrade when switching to the supplemental package; v6 fixed an ENOENT crash on clean builds with `merge: true` and dropped a Node 14 install path. See [the v5→v6 release notes](https://github.com/webdeveric/webpack-assets-manifest/releases) and `packages/shakapacker-webpack/README.md` for details.
67
96
 
68
97
  ### ⚠️ Breaking Changes
69
98
 
@@ -986,7 +1015,9 @@ Note: [Rubygem is 6.3.0.pre.rc.1](https://rubygems.org/gems/shakapacker/versions
986
1015
 
987
1016
  See [CHANGELOG.md in rails/webpacker (up to v5.4.3)](https://github.com/rails/webpacker/blob/master/CHANGELOG.md)
988
1017
 
989
- [Unreleased]: https://github.com/shakacode/shakapacker/compare/v10.3.0...main
1018
+ [Unreleased]: https://github.com/shakacode/shakapacker/compare/v10.3.2...main
1019
+ [v10.3.2]: https://github.com/shakacode/shakapacker/compare/v10.3.1...v10.3.2
1020
+ [v10.3.1]: https://github.com/shakacode/shakapacker/compare/v10.3.0...v10.3.1
990
1021
  [v10.3.0]: https://github.com/shakacode/shakapacker/compare/v10.2.0...v10.3.0
991
1022
  [v10.2.0]: https://github.com/shakacode/shakapacker/compare/v10.1.0...v10.2.0
992
1023
  [v10.1.0]: https://github.com/shakacode/shakapacker/compare/v10.0.0...v10.1.0
@@ -24,7 +24,7 @@ def shakapacker_warn_missing_node
24
24
  end
25
25
 
26
26
  def shakapacker_exec_env(launch_dir)
27
- return {} unless ENV.key?("PATH")
27
+ return unless ENV.key?("PATH")
28
28
 
29
29
  path_entries = ENV["PATH"].split(File::PATH_SEPARATOR, -1)
30
30
  path_entries = [""] if path_entries.empty?
@@ -38,12 +38,9 @@ end
38
38
 
39
39
  def shakapacker_exec_node(script_path, argv, launch_dir)
40
40
  exec_env = shakapacker_exec_env(launch_dir)
41
+ shakapacker_warn_missing_node unless exec_env
41
42
 
42
- if exec_env.empty?
43
- exec shakapacker_node_binary, script_path, *argv
44
- else
45
- exec exec_env, shakapacker_node_binary, script_path, *argv
46
- end
43
+ exec exec_env, shakapacker_node_binary, script_path, *argv
47
44
  rescue Errno::ENOENT, Errno::EACCES
48
45
  shakapacker_warn_missing_node
49
46
  end
@@ -24,7 +24,7 @@ def shakapacker_warn_missing_node
24
24
  end
25
25
 
26
26
  def shakapacker_exec_env(launch_dir)
27
- return {} unless ENV.key?("PATH")
27
+ return unless ENV.key?("PATH")
28
28
 
29
29
  path_entries = ENV["PATH"].split(File::PATH_SEPARATOR, -1)
30
30
  path_entries = [""] if path_entries.empty?
@@ -38,12 +38,9 @@ end
38
38
 
39
39
  def shakapacker_exec_node(script_path, argv, launch_dir)
40
40
  exec_env = shakapacker_exec_env(launch_dir)
41
+ shakapacker_warn_missing_node unless exec_env
41
42
 
42
- if exec_env.empty?
43
- exec shakapacker_node_binary, script_path, *argv
44
- else
45
- exec exec_env, shakapacker_node_binary, script_path, *argv
46
- end
43
+ exec exec_env, shakapacker_node_binary, script_path, *argv
47
44
  rescue Errno::ENOENT, Errno::EACCES
48
45
  shakapacker_warn_missing_node
49
46
  end
@@ -303,20 +303,30 @@ class Shakapacker::Configuration
303
303
  # Resolution order:
304
304
  # 1. CLI --bundler flag (via bundler_override)
305
305
  # 2. SHAKAPACKER_ASSETS_BUNDLER environment variable
306
- # 3. assets_bundler setting in config file
307
- # 4. bundler setting in config file (deprecated)
308
- # 5. Defaults to "webpack"
306
+ # 3. assets_bundler setting in config file (or the bundled default)
307
+ # 4. Defaults to "webpack"
308
+ #
309
+ # The legacy 'bundler' setting is not consulted; it is only used to warn that
310
+ # its value is ignored.
309
311
  #
310
312
  # @return [String] "webpack" or "rspack"
311
313
  def assets_bundler
312
314
  # CLI --bundler flag takes highest precedence
313
315
  return @bundler_override if @bundler_override
314
316
 
315
- # Show deprecation warning if using old 'bundler' key
317
+ resolved = ENV["SHAKAPACKER_ASSETS_BUNDLER"] || fetch(:assets_bundler) || "webpack"
318
+
319
+ # The legacy 'bundler' key is never read, so warn that its value is ignored
316
320
  if data.has_key?(:bundler) && !data.has_key?(:assets_bundler)
317
- $stderr.puts "⚠️ DEPRECATION WARNING: The 'bundler' configuration option is deprecated. Please use 'assets_bundler' instead to avoid confusion with Ruby's Bundler gem manager."
321
+ legacy_value = data[:bundler].to_s.strip
322
+ described_value = legacy_value.empty? ? "empty" : legacy_value
323
+ # An empty SHAKAPACKER_ASSETS_BUNDLER resolves to an empty string; name that
324
+ # state rather than printing "using ''". Doctor reports it as its own issue.
325
+ described_resolved = resolved.to_s.empty? ? "no bundler (SHAKAPACKER_ASSETS_BUNDLER is set but empty)" : "'#{resolved}'"
326
+ $stderr.puts "⚠️ DEPRECATION WARNING: The 'bundler' configuration option is no longer supported and its value (#{described_value}) is IGNORED. Shakapacker is using #{described_resolved}. Set 'assets_bundler' in your shakapacker.yml instead — it was renamed to avoid confusion with Ruby's Bundler gem manager."
318
327
  end
319
- ENV["SHAKAPACKER_ASSETS_BUNDLER"] || fetch(:assets_bundler) || fetch(:bundler) || "webpack"
328
+
329
+ resolved
320
330
  end
321
331
 
322
332
  # Deprecated alias for {#assets_bundler}
@@ -47,8 +47,13 @@ class Shakapacker::DevServer
47
47
  # @return [Boolean] true if the dev server is running
48
48
  def running?
49
49
  if config.dev_server.present?
50
- Socket.tcp(host, port, connect_timeout: connect_timeout).close
51
- true
50
+ socket = Socket.tcp(host, port, connect_timeout: connect_timeout)
51
+
52
+ begin
53
+ socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).int.zero?
54
+ ensure
55
+ socket.close
56
+ end
52
57
  else
53
58
  false
54
59
  end
@@ -11,6 +11,10 @@ class Shakapacker::DevServerProxy < Rack::Proxy
11
11
 
12
12
  def perform_request(env)
13
13
  if env["PATH_INFO"].start_with?("/#{public_output_uri_path}") && dev_server.running?
14
+ # rack-proxy v1 refuses to derive the backend from the Host header.
15
+ env["rack.backend"] = URI::Generic.build(
16
+ scheme: dev_server.protocol, host: dev_server.host, port: dev_server.port
17
+ )
14
18
  env["HTTP_HOST"] = env["HTTP_X_FORWARDED_HOST"] = dev_server.host
15
19
  env["HTTP_X_FORWARDED_SERVER"] = dev_server.host_with_port
16
20
  env["HTTP_PORT"] = env["HTTP_X_FORWARDED_PORT"] = dev_server.port.to_s
@@ -59,6 +59,9 @@ module Shakapacker
59
59
  "@rspack/plugin-react-refresh" => "^2.0.0"
60
60
  }.freeze
61
61
 
62
+ RSPACK_REACT_REFRESH_PACKAGE = "@rspack/plugin-react-refresh".freeze
63
+ VERSION_UPPER_BOUND_OPERATORS = %w[< <=].freeze
64
+
62
65
  CUSTOM_HYBRID_LOADER_DEPS = %w[
63
66
  babel-loader
64
67
  esbuild-loader
@@ -72,6 +75,25 @@ module Shakapacker
72
75
 
73
76
  PACKAGE_ROOT_MARKERS = (["package.json"] + PACKAGE_MANAGER_LOCKFILES.keys + ["node_modules"]).freeze
74
77
 
78
+ # generateRspackConfig merges with plain webpack-merge `merge` (package/rspack/index.ts),
79
+ # which concatenates `module.rules`, so an override handed to it is appended next to the
80
+ # built-in rule rather than replacing it. mergeWithRules must be applied to its output.
81
+ RSPACK_SWC_OVERRIDE_HINT =
82
+ "Apply webpack-merge's 'mergeWithRules' to the output of generateRspackConfig() in your Rspack config, " \
83
+ "matching on both 'test' and 'use.loader', and using options: 'merge' (not 'replace', which swaps the whole " \
84
+ "options object and drops the built-in parser and transform.react defaults). " \
85
+ "Keep 'test' in the match: matching on 'use.loader' alone makes webpack-merge append 'builtin:swc-loader' to " \
86
+ "every rule's 'use' chain, including the CSS and Sass rules. " \
87
+ "Override the JS (/\\.(js|jsx|mjs)$/) and TypeScript (/\\.(ts|tsx)$/) rules separately, since Shakapacker " \
88
+ "registers a 'builtin:swc-loader' rule for each. " \
89
+ "Passing an override into generateRspackConfig() cannot replace the built-in rule, because it merges with " \
90
+ "plain 'merge', which concatenates 'module.rules' and leaves the built-in 'builtin:swc-loader' rule in place " \
91
+ "alongside yours. Shakapacker re-exports 'mergeWithRules'. " \
92
+ "See: https://github.com/shakacode/shakapacker/blob/main/docs/rspack.md".freeze
93
+
94
+ RSPACK_SWC_OVERRIDE_HINT_BACKREF =
95
+ "See the Rspack 'builtin:swc-loader' override guidance above.".freeze
96
+
75
97
  def initialize(config = nil, root_path = nil, options = {})
76
98
  @config = config || Shakapacker.config
77
99
  @root_path = root_path || (defined?(Rails) ? Rails.root : Pathname.new(Dir.pwd))
@@ -170,6 +192,7 @@ module Shakapacker
170
192
  check_css_modules_configuration
171
193
  check_bundler_dependencies if config_exists?
172
194
  check_rspack_cache_configuration if config_exists?
195
+ check_rspack_react_refresh_plugin_constructor if config_exists?
173
196
  check_file_type_dependencies if config_exists?
174
197
  check_sri_dependencies if config_exists?
175
198
  check_peer_dependencies
@@ -661,8 +684,11 @@ module Shakapacker
661
684
  add_warning("Both esbuild and Babel dependencies are installed. Consider removing Babel dependencies to reduce node_modules size")
662
685
  end
663
686
 
664
- # Check for SWC configuration conflicts
665
- if transpiler == "swc"
687
+ # Check for SWC configuration conflicts. Rspack always transpiles with
688
+ # builtin:swc-loader, so SWC config files go unread there regardless of
689
+ # javascript_transpiler; the webpack-only content checks stay SWC-gated
690
+ # inside check_swc_config_conflicts.
691
+ if transpiler == "swc" || assets_bundler == "rspack"
666
692
  check_swc_config_conflicts
667
693
  end
668
694
  end
@@ -714,16 +740,48 @@ module Shakapacker
714
740
  swcrc_path = root_path.join(".swcrc")
715
741
  swc_config_path = root_path.join("config/swc.config.js")
716
742
 
743
+ rspack = assets_bundler == "rspack"
744
+
717
745
  if swcrc_path.exist?
718
- add_warning("SWC configuration: .swcrc file detected. This file completely overrides Shakapacker's default SWC settings and may cause build failures. " \
719
- "Please migrate to config/swc.config.js which properly merges with Shakapacker defaults. " \
720
- "To migrate: Move your custom settings from .swcrc to config/swc.config.js (see docs for format). " \
721
- "See: https://github.com/shakacode/shakapacker/blob/main/docs/using_swc_loader.md")
746
+ if rspack
747
+ # Verified against @rspack/core 2.0.1 and 2.2.0: 'builtin:swc-loader' never reads .swcrc.
748
+ # A .swcrc setting jsc.target and an optimizer global produced byte-identical output to
749
+ # no .swcrc, and the same options passed inline did change the output. A .swcrc enabling
750
+ # decorator syntax also failed to unblock a decorator source, including with empty loader
751
+ # options and with swcrc/configFile set, so this is not just inline options winning.
752
+ add_warning("SWC configuration: .swcrc is present but is NOT read when assets_bundler is 'rspack'. " \
753
+ "Rspack transpiles with 'builtin:swc-loader', which ignores .swcrc entirely, so every setting in it is silently inert. " \
754
+ "Moving these settings to config/swc.config.js would not help either - Shakapacker's Rspack build does not read that file.")
755
+ add_rspack_swc_override_hint("To apply custom SWC options on Rspack, override the built-in 'builtin:swc-loader' rule.")
756
+ else
757
+ add_warning("SWC configuration: .swcrc file detected. This file completely overrides Shakapacker's default SWC settings and may cause build failures. " \
758
+ "Please migrate to config/swc.config.js which properly merges with Shakapacker defaults. " \
759
+ "To migrate: Move your custom settings from .swcrc to config/swc.config.js (see docs for format). " \
760
+ "See: https://github.com/shakacode/shakapacker/blob/main/docs/using_swc_loader.md")
761
+ end
722
762
  end
723
763
 
724
- if swc_config_path.exist?
725
- @info << "SWC configuration: Using config/swc.config.js (recommended). This config is merged with Shakapacker's defaults."
726
- check_swc_config_settings(swc_config_path)
764
+ return unless swc_config_path.exist?
765
+
766
+ if rspack
767
+ add_warning("SWC configuration: config/swc.config.js is present but is NOT read when assets_bundler is 'rspack'. " \
768
+ "Shakapacker's Rspack config sets its 'builtin:swc-loader' options inline, so nothing in this file reaches your build.")
769
+ add_rspack_swc_override_hint("Customize SWC for Rspack by overriding the built-in 'builtin:swc-loader' rule instead.")
770
+ return
771
+ end
772
+
773
+ @info << "SWC configuration: Using config/swc.config.js (recommended). This config is merged with Shakapacker's defaults."
774
+ check_swc_config_settings(swc_config_path)
775
+ end
776
+
777
+ # The full hint is ~700 characters, and an Rspack app with both .swcrc and
778
+ # config/swc.config.js hits both call sites, so emit it once and refer back after that.
779
+ def add_rspack_swc_override_hint(lead)
780
+ if @rspack_swc_override_hint_emitted
781
+ add_fix_hint("#{lead} #{RSPACK_SWC_OVERRIDE_HINT_BACKREF}")
782
+ else
783
+ @rspack_swc_override_hint_emitted = true
784
+ add_fix_hint("#{lead} #{RSPACK_SWC_OVERRIDE_HINT}")
727
785
  end
728
786
  end
729
787
 
@@ -878,14 +936,89 @@ module Shakapacker
878
936
  "See https://rspack.rs/config/cache for options.")
879
937
  end
880
938
 
939
+ def check_rspack_react_refresh_plugin_constructor
940
+ return unless rspack_react_refresh_check_applicable?
941
+ return unless rspack_react_refresh_plugin_v2_or_newer?
942
+
943
+ rspack_react_refresh_config_paths.each do |path|
944
+ content = File.read(path)
945
+ next unless legacy_rspack_react_refresh_constructor?(content)
946
+
947
+ relative = config_path_for_warning(path)
948
+ add_action_required("Rspack React Refresh config #{relative} uses the " \
949
+ "#{RSPACK_REACT_REFRESH_PACKAGE} v1 default-export constructor pattern. " \
950
+ "With #{RSPACK_REACT_REFRESH_PACKAGE} v2, rspack may fail with " \
951
+ "'ReactRefreshPlugin is not a constructor'.")
952
+ add_fix_hint("Use a compat constructor: const ReactRefresh = require(\"#{RSPACK_REACT_REFRESH_PACKAGE}\"); " \
953
+ "const ReactRefreshRspackPlugin = ReactRefresh.ReactRefreshRspackPlugin || " \
954
+ "ReactRefresh.default || ReactRefresh; then call new ReactRefreshRspackPlugin().")
955
+ rescue SystemCallError => e
956
+ add_info_warning("Unable to validate Rspack React Refresh config #{config_path_for_warning(path)}: #{e.message}")
957
+ end
958
+ end
959
+
960
+ def rspack_react_refresh_check_applicable?
961
+ assets_bundler == "rspack" || unconfigured_hybrid_loader_graph?
962
+ end
963
+
964
+ def rspack_react_refresh_plugin_v2_or_newer?
965
+ version = installed_package_version(RSPACK_REACT_REFRESH_PACKAGE)
966
+ return version >= Gem::Version.new("2.0.0") if version
967
+
968
+ package_specifier_allows_version_or_newer?(
969
+ package_json_dependency_version(RSPACK_REACT_REFRESH_PACKAGE),
970
+ Gem::Version.new("2.0.0")
971
+ )
972
+ end
973
+
974
+ def rspack_react_refresh_config_paths
975
+ config_dir = rspack_react_refresh_config_dir
976
+ config_dir_path = Pathname.new(File.join(root_path.to_s, config_dir))
977
+ return [] unless config_dir_path.directory?
978
+
979
+ path = active_bundler_config_path_in(config_dir)
980
+ path ? [path] : []
981
+ end
982
+
983
+ def rspack_react_refresh_config_dir
984
+ config_dir = config.assets_bundler_config_path.to_s
985
+
986
+ if assets_bundler == "rspack" || same_directory_hybrid_config_present?(config_dir)
987
+ config_dir
988
+ else
989
+ "config/rspack"
990
+ end
991
+ end
992
+
993
+ def legacy_rspack_react_refresh_constructor?(content)
994
+ stripped = strip_rspack_config_comments_and_literals(content, preserve_literals: [RSPACK_REACT_REFRESH_PACKAGE])
995
+ constructor_names = []
996
+
997
+ constructor_names.concat(stripped.scan(
998
+ /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*require\(\s*["']#{Regexp.escape(RSPACK_REACT_REFRESH_PACKAGE)}["']\s*\)(?=\s*(?:[;,\)]|$))/
999
+ ).flatten)
1000
+ constructor_names.concat(stripped.scan(
1001
+ /\bimport\s+([A-Za-z_$][\w$]*)\s*(?:,\s*\{[^}]*\}\s*)?\s+from\s*["']#{Regexp.escape(RSPACK_REACT_REFRESH_PACKAGE)}["']/
1002
+ ).flatten)
1003
+ constructor_names.concat(stripped.scan(
1004
+ /\bimport\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s*["']#{Regexp.escape(RSPACK_REACT_REFRESH_PACKAGE)}["']/
1005
+ ).flatten)
1006
+
1007
+ constructor_names.uniq.any? do |constructor_name|
1008
+ stripped.match?(/\bnew\s+#{Regexp.escape(constructor_name)}\s*\(/)
1009
+ end
1010
+ end
1011
+
881
1012
  # Returns the single active config path the runner would load, or nil. Mirrors the
882
1013
  # resolution order in Shakapacker::Runner#find_rspack_config_with_fallback so the
883
1014
  # doctor inspects the same file the build will actually use (and so unused sibling
884
1015
  # configs in the same directory don't trigger spurious warnings).
885
1016
  # NOTE: keep this candidate list in sync with Runner#find_rspack_config_with_fallback.
886
1017
  def active_assets_bundler_config_path
887
- config_dir = config.assets_bundler_config_path.to_s
1018
+ active_bundler_config_path_in(config.assets_bundler_config_path.to_s)
1019
+ end
888
1020
 
1021
+ def active_bundler_config_path_in(config_dir)
889
1022
  candidates = %w[ts js].map { |ext| Pathname.new(File.join(root_path.to_s, config_dir, "rspack.config.#{ext}")) }
890
1023
  candidates += %w[ts js].map { |ext| Pathname.new(File.join(root_path.to_s, config_dir, "webpack.config.#{ext}")) }
891
1024
  if default_rspack_config_dir?(config_dir)
@@ -944,7 +1077,7 @@ module Shakapacker
944
1077
  stripped.gsub(%r{/(?:\\.|\[[^\]\n]*\]|[^/\n\\\[])+?/[gimsuy]*}, "")
945
1078
  end
946
1079
 
947
- def strip_rspack_config_comments_and_literals(content)
1080
+ def strip_rspack_config_comments_and_literals(content, preserve_literals: [])
948
1081
  stripped = +""
949
1082
  index = 0
950
1083
 
@@ -987,8 +1120,12 @@ module Shakapacker
987
1120
  end
988
1121
 
989
1122
  literal = content[index...literal_end]
990
- stripped << '""'
991
- stripped << literal.gsub(/[^\n]/, "")
1123
+ if preserved_js_string_literal?(literal, char, preserve_literals)
1124
+ stripped << literal
1125
+ else
1126
+ stripped << '""'
1127
+ stripped << literal.gsub(/[^\n]/, "")
1128
+ end
992
1129
  index = literal_end
993
1130
  elsif char == "`"
994
1131
  literal_end = index + 1
@@ -1029,6 +1166,12 @@ module Shakapacker
1029
1166
  stripped
1030
1167
  end
1031
1168
 
1169
+ def preserved_js_string_literal?(literal, quote, preserve_literals)
1170
+ return false unless literal.end_with?(quote)
1171
+
1172
+ preserve_literals.include?(literal[1...-1])
1173
+ end
1174
+
1032
1175
  def direct_export_cache_disabled?(stripped)
1033
1176
  # Match `cache: false` only near an exported config object at brace depth
1034
1177
  # 1. This avoids warning on local base config objects while still
@@ -1183,8 +1326,9 @@ module Shakapacker
1183
1326
  return versions.min
1184
1327
  end
1185
1328
 
1329
+ return package_version_from_range_specifier(cleaned) if cleaned.match?(/[<>=]/)
1186
1330
  return nil unless cleaned.match?(/\A[\^~]?\d/)
1187
- return nil if cleaned.match?(/(\s|\|\||[<>=:]|\A(?:git|file|link|workspace|npm):)/)
1331
+ return nil if cleaned.match?(/(\s|\|\||:|\A(?:git|file|link|workspace|npm):)/)
1188
1332
 
1189
1333
  match = cleaned.sub(/\A[\^~]/, "").match(/\A(\d+(?:\.\d+){0,2})(?:-[0-9A-Za-z.-]+)?\z/)
1190
1334
  match && Gem::Version.new(match[1])
@@ -1192,6 +1336,48 @@ module Shakapacker
1192
1336
  nil
1193
1337
  end
1194
1338
 
1339
+ def package_version_from_range_specifier(specifier)
1340
+ lower_bounds = specifier.scan(/(?:\A|\s)(?:>=|>)\s*(\d+(?:\.\d+){0,2})(?:-[0-9A-Za-z.-]+)?/)
1341
+ versions = lower_bounds.flatten.map { |version| Gem::Version.new(version) }
1342
+
1343
+ versions.max
1344
+ rescue ArgumentError
1345
+ nil
1346
+ end
1347
+
1348
+ def package_specifier_allows_version_or_newer?(specifier, minimum)
1349
+ return false unless specifier
1350
+
1351
+ cleaned = specifier.strip
1352
+ if cleaned.include?("||")
1353
+ return cleaned.split("||").any? { |part| package_specifier_allows_version_or_newer?(part, minimum) }
1354
+ end
1355
+ return false if cleaned.match?(/(:|\A(?:git|file|link|workspace|npm):)/)
1356
+
1357
+ if cleaned.match?(/[<>=]/)
1358
+ return package_range_specifier_allows_version_or_newer?(cleaned, minimum)
1359
+ end
1360
+
1361
+ version = package_version_from_specifier(cleaned)
1362
+ version && version >= minimum
1363
+ end
1364
+
1365
+ def package_range_specifier_allows_version_or_newer?(specifier, minimum)
1366
+ comparators = specifier.scan(/(?:\A|\s)(<=|<|>=|>|=)\s*(\d+(?:\.\d+){0,2})(?:-[0-9A-Za-z.-]+)?/)
1367
+ return false if comparators.empty?
1368
+
1369
+ equalities = comparators.select { |operator, _version| operator == "=" }
1370
+ return equalities.any? { |_operator, version| Gem::Version.new(version) >= minimum } if equalities.any?
1371
+
1372
+ upper_bounds = comparators.select { |operator, _version| VERSION_UPPER_BOUND_OPERATORS.include?(operator) }
1373
+ upper_bounds.all? do |operator, version|
1374
+ parsed = Gem::Version.new(version)
1375
+ operator == "<" ? parsed > minimum : parsed >= minimum
1376
+ end
1377
+ rescue ArgumentError
1378
+ false
1379
+ end
1380
+
1195
1381
  def declared_package_dependencies
1196
1382
  @declared_package_dependencies ||= begin
1197
1383
  package_json_paths.reverse_each.each_with_object({}) do |path, dependencies|
@@ -46,11 +46,65 @@ module Shakapacker
46
46
  .eslintrc.json
47
47
  ].freeze
48
48
 
49
- DEFAULT_SWC_CONFIG = <<~JS.freeze
49
+ SWC_CONFIG_WEBPACK_HEADER = <<~JS.freeze
50
50
  // config/swc.config.js
51
51
  // This file is merged with Shakapacker's default SWC configuration
52
52
  // See: https://swc.rs/docs/configuration/compilation
53
+ JS
54
+
55
+ # Rspack never reads config/swc.config.js: package/rules/rspack.ts sets its
56
+ # builtin:swc-loader options inline, so the file is generated with a header that says so.
57
+ #
58
+ # The example keeps `test: 'match'` and overrides the JS and TS rules separately on
59
+ # purpose. Matching on `use.loader` alone (a single override with no `test`) looks tidier
60
+ # but is wrong: webpack-merge cannot pair such an override with a specific rule, so it
61
+ # appends builtin:swc-loader onto EVERY rule's `use` chain, including the CSS and Sass
62
+ # rules. Verified at webpack-merge 5.10.0 and 6.0.1.
63
+ SWC_CONFIG_RSPACK_HEADER = <<~JS.freeze
64
+ // config/swc.config.js
65
+ // NOTE: This file is NOT read when assets_bundler is 'rspack'.
66
+ // Shakapacker's Rspack config sets its 'builtin:swc-loader' options inline, so nothing
67
+ // here reaches your build. To customize SWC for Rspack, apply webpack-merge's
68
+ // mergeWithRules to the OUTPUT of generateRspackConfig(). Passing an override into
69
+ // generateRspackConfig() cannot replace the built-in rule: it merges with plain merge,
70
+ // which concatenates module.rules and leaves the built-in rule in place alongside yours.
71
+ //
72
+ // Use options: 'merge', not 'replace'. 'merge' deep-merges into the built-in options so
73
+ // parser.jsx (JS), parser.syntax/tsx (TS), and transform.react.runtime survive.
74
+ // 'replace' swaps the whole options object and silently drops them, breaking JSX and
75
+ // TypeScript compilation.
76
+ //
77
+ // Keep test: 'match' in the merge spec. Matching on use.loader alone appends
78
+ // builtin:swc-loader to every rule's use chain, CSS and Sass included.
79
+ //
80
+ // const { mergeWithRules } = require('shakapacker');
81
+ // const { generateRspackConfig } = require('shakapacker/rspack');
82
+ //
83
+ // const swcOptions = { jsc: { keepClassNames: true } }; // your SWC options
84
+ //
85
+ // module.exports = mergeWithRules({
86
+ // module: { rules: { test: 'match', use: { loader: 'match', options: 'merge' } } },
87
+ // })(generateRspackConfig(), {
88
+ // module: {
89
+ // rules: [
90
+ // // Shakapacker registers separate builtin:swc-loader rules for JS and TS.
91
+ // // Override both: a JS-only override never reaches .ts/.tsx files.
92
+ // {
93
+ // test: /\\.(js|jsx|mjs)$/,
94
+ // use: [{ loader: 'builtin:swc-loader', options: swcOptions }],
95
+ // },
96
+ // {
97
+ // test: /\\.(ts|tsx)$/,
98
+ // use: [{ loader: 'builtin:swc-loader', options: swcOptions }],
99
+ // },
100
+ // ],
101
+ // },
102
+ // });
103
+ //
104
+ // See: https://github.com/shakacode/shakapacker/blob/main/docs/rspack.md
105
+ JS
53
106
 
107
+ SWC_CONFIG_BODY = <<~JS.freeze
54
108
  const { env } = require('shakapacker');
55
109
 
56
110
  module.exports = {
@@ -70,6 +124,11 @@ module Shakapacker
70
124
  };
71
125
  JS
72
126
 
127
+ # Kept for backward compatibility: same value as before, and still the webpack variant.
128
+ DEFAULT_SWC_CONFIG = "#{SWC_CONFIG_WEBPACK_HEADER}\n#{SWC_CONFIG_BODY}".freeze
129
+
130
+ RSPACK_SWC_CONFIG = "#{SWC_CONFIG_RSPACK_HEADER}\n#{SWC_CONFIG_BODY}".freeze
131
+
73
132
  def initialize(root_path, logger: nil)
74
133
  @root_path = Pathname.new(root_path)
75
134
  @logger = logger || Logger.new($stdout)
@@ -89,9 +148,7 @@ module Shakapacker
89
148
  logger.info " Note: SWC is approximately 20x faster than Babel for transpilation."
90
149
  logger.info " Please test your application thoroughly after migration."
91
150
  logger.info "\n📝 Configuration Info:"
92
- logger.info " - config/swc.config.js is merged with Shakapacker's default SWC configuration"
93
- logger.info " - You can customize config/swc.config.js to add additional options"
94
- logger.info " - Avoid using .swcrc as it overrides Shakapacker defaults completely"
151
+ log_swc_config_guidance
95
152
 
96
153
  # Show cleanup recommendations if babel packages found
97
154
  if results[:babel_packages_found].any?
@@ -275,6 +332,48 @@ module Shakapacker
275
332
  {}
276
333
  end
277
334
 
335
+ def log_swc_config_guidance
336
+ if rspack?
337
+ logger.info " - config/swc.config.js is NOT read when assets_bundler is 'rspack'"
338
+ logger.info " Shakapacker's Rspack config sets its 'builtin:swc-loader' options inline"
339
+ logger.info " - To customize SWC for Rspack, apply webpack-merge's 'mergeWithRules' to the"
340
+ logger.info " OUTPUT of generateRspackConfig(), matching on both 'test' and 'use.loader'"
341
+ logger.info " and merging 'use.options'. Matching on 'use.loader' alone would append"
342
+ logger.info " 'builtin:swc-loader' to every rule's 'use' chain, CSS and Sass included."
343
+ logger.info " Passing an override into generateRspackConfig() cannot replace"
344
+ logger.info " the built-in rule, because it merges with plain 'merge', which concatenates"
345
+ logger.info " 'module.rules' and leaves the built-in rule in place alongside yours"
346
+ logger.info " - Use options: 'merge', not 'replace', so the built-in parser and"
347
+ logger.info " transform.react defaults survive, and override the JS and TS rules separately"
348
+ logger.info " - The generated config/swc.config.js header contains a copy-pasteable example"
349
+ logger.info " - See: https://github.com/shakacode/shakapacker/blob/main/docs/rspack.md"
350
+ else
351
+ logger.info " - config/swc.config.js is merged with Shakapacker's default SWC configuration"
352
+ logger.info " - You can customize config/swc.config.js to add additional options"
353
+ logger.info " - Avoid using .swcrc as it overrides Shakapacker defaults completely"
354
+ end
355
+ end
356
+
357
+ def rspack?
358
+ assets_bundler == "rspack"
359
+ end
360
+
361
+ # Resolves through Shakapacker's own configuration rather than re-reading
362
+ # config/shakapacker.yml here, so this guidance can never disagree with the bundler the
363
+ # build actually uses. Instance handles SHAKAPACKER_CONFIG, Env.inquire (Rails.env plus
364
+ # the production fallback), and Configuration's own precedence. Falls back to webpack
365
+ # when the config is missing or unparseable, since migration must not crash on it.
366
+ def assets_bundler
367
+ return @assets_bundler if defined?(@assets_bundler)
368
+
369
+ @assets_bundler = begin
370
+ require "shakapacker"
371
+ Shakapacker::Instance.new(root_path: root_path).config.assets_bundler
372
+ rescue StandardError, LoadError
373
+ "webpack"
374
+ end
375
+ end
376
+
278
377
  def create_swc_config
279
378
  config_dir = root_path.join("config")
280
379
  swc_config_path = config_dir.join("swc.config.js")
@@ -287,7 +386,7 @@ module Shakapacker
287
386
  FileUtils.mkdir_p(config_dir) unless config_dir.exist?
288
387
 
289
388
  logger.info "📄 Creating config/swc.config.js..."
290
- File.write(swc_config_path, DEFAULT_SWC_CONFIG)
389
+ File.write(swc_config_path, rspack? ? RSPACK_SWC_CONFIG : DEFAULT_SWC_CONFIG)
291
390
  logger.info "✅ config/swc.config.js created"
292
391
  true
293
392
  rescue StandardError => e
@@ -33,7 +33,11 @@ module Shakapacker
33
33
  [true, "true", "yes", 1, "1", "t"].include?(value.instance_of?(String) ? value.downcase : value)
34
34
  end
35
35
 
36
- # Executes a string or an array of strings in a shell in the given directory in an unbundled environment
36
+ # Executes a string or an array of strings in a shell in the given directory.
37
+ # NOTE: this does NOT unbundle. The caller's Bundler environment (BUNDLE_GEMFILE,
38
+ # RUBYOPT, ...) is inherited, so a `bundle` command run here against a different
39
+ # directory's Gemfile still resolves the caller's Gemfile. Wrap the call in
40
+ # Bundler.with_unbundled_env when that matters.
37
41
  def self.sh_in_dir(dir, *shell_commands)
38
42
  shell_commands.flatten.each { |shell_command| sh %(cd '#{dir}' && #{shell_command.strip}) }
39
43
  end
@@ -1,4 +1,4 @@
1
1
  module Shakapacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "10.3.0".freeze
3
+ VERSION = "10.3.2".freeze
4
4
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shakapacker",
3
- "version": "10.3.0",
3
+ "version": "10.3.2",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "homepage": "https://github.com/shakacode/shakapacker",
6
6
  "bugs": {
@@ -58,8 +58,8 @@
58
58
  "@babel/core": "7.29.0",
59
59
  "@eslint/eslintrc": "^3.2.0",
60
60
  "@eslint/js": "^9.37.0",
61
- "@rspack/cli": "2.0.1",
62
- "@rspack/core": "2.0.1",
61
+ "@rspack/cli": "2.2.0",
62
+ "@rspack/core": "2.2.0",
63
63
  "@swc/core": "1.15.33",
64
64
  "@types/babel__core": "^7.20.5",
65
65
  "@types/js-yaml": "^4.0.9",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shakapacker
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.3.0
4
+ version: 10.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -225,7 +225,7 @@ homepage: https://github.com/shakacode/shakapacker
225
225
  licenses:
226
226
  - MIT
227
227
  metadata:
228
- source_code_uri: https://github.com/shakacode/shakapacker/tree/v10.3.0
228
+ source_code_uri: https://github.com/shakacode/shakapacker/tree/v10.3.2
229
229
  rdoc_options: []
230
230
  require_paths:
231
231
  - lib
@@ -240,7 +240,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
240
240
  - !ruby/object:Gem::Version
241
241
  version: '0'
242
242
  requirements: []
243
- rubygems_version: 3.6.9
243
+ rubygems_version: 4.0.18
244
244
  specification_version: 4
245
245
  summary: Use webpack to manage app-like JavaScript modules in Rails
246
246
  test_files: []