Skip to content

Commit e49f2b1

Browse files
justin808claude
andcommitted
Upgrade Shakapacker from 8.2.0 to 9.0.0
This is a minimal upgrade to Shakapacker 9.0.0, focusing on core compatibility changes needed to get the gem working with the new version. Key changes: - Update shakapacker dependency from 8.2.0 to 9.0.0 in package.json and Gemfile - Add SWC dependencies (@swc/core, swc-loader) for Shakapacker 9.0 compatibility - Add precompile_hook configuration to shakapacker.yml - Create bin/shakapacker-precompile-hook script for ReScript builds and pack generation - Fix CSS Modules configuration to use default exports for backward compatibility - Update sass-resources-loader to work with all SCSS rules (both .scss and .module.scss) This upgrade provides a stable foundation for testing with Shakapacker 9.0.0 before proceeding with upgrades to 9.1.x and 9.2.x. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 7ceed7c commit e49f2b1

File tree

8 files changed

+251
-14
lines changed

8 files changed

+251
-14
lines changed

Gemfile.development_dependencies

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
gem "shakapacker", "8.2.0"
3+
gem "shakapacker", "9.0.0"
44
gem "bootsnap", require: false
55
gem "rails", "~> 7.1"
66

Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ GEM
342342
rubyzip (>= 1.2.2, < 3.0)
343343
websocket (~> 1.0)
344344
semantic_range (3.1.0)
345-
shakapacker (8.2.0)
345+
shakapacker (9.0.0)
346346
activesupport (>= 5.2)
347347
package_json
348348
rack-proxy (>= 0.6.1)
@@ -440,7 +440,7 @@ DEPENDENCIES
440440
scss_lint
441441
sdoc
442442
selenium-webdriver (= 4.9.0)
443-
shakapacker (= 8.2.0)
443+
shakapacker (= 9.0.0)
444444
spring (~> 4.0)
445445
sprockets (~> 4.0)
446446
sqlite3 (~> 1.6)

spec/dummy/Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ GEM
346346
rubyzip (>= 1.2.2, < 3.0)
347347
websocket (~> 1.0)
348348
semantic_range (3.1.0)
349-
shakapacker (8.2.0)
349+
shakapacker (9.0.0)
350350
activesupport (>= 5.2)
351351
package_json
352352
rack-proxy (>= 0.6.1)
@@ -441,7 +441,7 @@ DEPENDENCIES
441441
scss_lint
442442
sdoc
443443
selenium-webdriver (= 4.9.0)
444-
shakapacker (= 8.2.0)
444+
shakapacker (= 9.0.0)
445445
spring (~> 4.0)
446446
sprockets (~> 4.0)
447447
sqlite3 (~> 1.6)
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
# Shakapacker precompile hook
5+
# This script runs before Shakapacker compilation in both development and production.
6+
# See: https://github.com/shakacode/shakapacker/blob/main/docs/precompile_hook.md
7+
8+
require "fileutils"
9+
10+
# Find Rails root by walking upward looking for config/environment.rb
11+
def find_rails_root
12+
dir = Dir.pwd
13+
loop do
14+
return dir if File.exist?(File.join(dir, "config", "environment.rb"))
15+
16+
parent = File.dirname(dir)
17+
return nil if parent == dir # Reached filesystem root
18+
19+
dir = parent
20+
end
21+
end
22+
23+
# Build ReScript if needed
24+
def build_rescript_if_needed
25+
# Check for both old (bsconfig.json) and new (rescript.json) config files
26+
return unless File.exist?("bsconfig.json") || File.exist?("rescript.json")
27+
28+
puts "🔧 Building ReScript..."
29+
30+
# Cross-platform package manager detection
31+
yarn_available = system("yarn", "--version", out: File::NULL, err: File::NULL)
32+
npm_available = system("npm", "--version", out: File::NULL, err: File::NULL)
33+
34+
success = if yarn_available
35+
system("yarn", "build:rescript")
36+
elsif npm_available
37+
system("npm", "run", "build:rescript")
38+
else
39+
warn "⚠️ Warning: Neither yarn nor npm found. Skipping ReScript build."
40+
return
41+
end
42+
43+
if success
44+
puts "✅ ReScript build completed successfully"
45+
else
46+
warn "❌ ReScript build failed"
47+
exit 1
48+
end
49+
end
50+
51+
# Generate React on Rails packs if needed
52+
# rubocop:disable Metrics/CyclomaticComplexity
53+
def generate_packs_if_needed
54+
# Find Rails root directory
55+
rails_root = find_rails_root
56+
return unless rails_root
57+
58+
# Check if React on Rails initializer exists
59+
initializer_path = File.join(rails_root, "config", "initializers", "react_on_rails.rb")
60+
return unless File.exist?(initializer_path)
61+
62+
# Check if auto-pack generation is configured (match actual config assignments, not comments)
63+
config_file = File.read(initializer_path)
64+
has_auto_load = config_file =~ /^\s*config\.auto_load_bundle\s*=/
65+
has_components_subdir = config_file =~ /^\s*config\.components_subdirectory\s*=/
66+
return unless has_auto_load || has_components_subdir
67+
68+
puts "📦 Generating React on Rails packs..."
69+
70+
# Cross-platform bundle availability check
71+
bundle_available = system("bundle", "--version", out: File::NULL, err: File::NULL)
72+
return unless bundle_available
73+
74+
# Check if rake task exists (cross-platform)
75+
task_list = `bundle exec rails -T 2>&1`
76+
return unless task_list.include?("react_on_rails:generate_packs")
77+
78+
# Use array form for better cross-platform support
79+
success = system("bundle", "exec", "rails", "react_on_rails:generate_packs")
80+
81+
if success
82+
puts "✅ Pack generation completed successfully"
83+
else
84+
warn "❌ Pack generation failed"
85+
exit 1
86+
end
87+
end
88+
# rubocop:enable Metrics/CyclomaticComplexity
89+
90+
# Main execution
91+
begin
92+
build_rescript_if_needed
93+
generate_packs_if_needed
94+
95+
exit 0
96+
rescue StandardError => e
97+
warn "❌ Precompile hook failed: #{e.message}"
98+
warn e.backtrace.join("\n")
99+
exit 1
100+
end

spec/dummy/config/shakapacker.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ default: &default
55
source_entry_path: packs
66
public_root_path: public
77

8+
# Hook to run before compilation (e.g., for ReScript builds, pack generation)
9+
# See: https://github.com/shakacode/shakapacker/blob/main/docs/precompile_hook.md
10+
precompile_hook: bin/shakapacker-precompile-hook
11+
812
cache_path: tmp/cache/shakapacker
913
webpack_compile_output: false
1014
ensure_consistent_versioning: true

spec/dummy/config/webpack/commonWebpackConfig.js

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,38 @@ const sassLoaderConfig = {
2121
},
2222
};
2323

24-
const scssConfigIndex = baseClientWebpackConfig.module.rules.findIndex((config) =>
25-
'.scss'.match(config.test),
26-
);
27-
baseClientWebpackConfig.module.rules[scssConfigIndex]?.use.push(sassLoaderConfig);
24+
// Add sass-resources-loader to all SCSS rules (both .scss and .module.scss)
25+
baseClientWebpackConfig.module.rules.forEach((rule) => {
26+
if (rule.test && '.scss'.match(rule.test) && Array.isArray(rule.use)) {
27+
rule.use.push(sassLoaderConfig);
28+
}
29+
});
30+
31+
// Configure CSS Modules to use default exports (Shakapacker 9.0 compatibility)
32+
// Shakapacker 9.0 defaults to namedExport: true, but we use default imports
33+
// To restore backward compatibility with existing code using `import styles from`
34+
baseClientWebpackConfig.module.rules.forEach((rule) => {
35+
if (Array.isArray(rule.use)) {
36+
rule.use.forEach((loader) => {
37+
if (
38+
loader &&
39+
typeof loader === 'object' &&
40+
loader.loader &&
41+
typeof loader.loader === 'string' &&
42+
loader.loader.includes('css-loader') &&
43+
loader.options &&
44+
typeof loader.options === 'object' &&
45+
loader.options.modules &&
46+
typeof loader.options.modules === 'object'
47+
) {
48+
// eslint-disable-next-line no-param-reassign
49+
loader.options.modules.namedExport = false;
50+
// eslint-disable-next-line no-param-reassign
51+
loader.options.modules.exportLocalsConvention = 'camelCase';
52+
}
53+
});
54+
}
55+
});
2856

2957
// add jquery
3058
const exposeJQuery = {

spec/dummy/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"regenerator-runtime": "^0.13.4"
3030
},
3131
"devDependencies": {
32+
"@swc/core": "^1.7.0",
3233
"@babel/core": "7.17.9",
3334
"@babel/plugin-transform-runtime": "7.17.0",
3435
"@babel/preset-env": "7",
@@ -51,8 +52,9 @@
5152
"sass": "^1.43.4",
5253
"sass-loader": "^12.3.0",
5354
"sass-resources-loader": "^2.1.0",
54-
"shakapacker": "8.2.0",
55+
"shakapacker": "9.0.0",
5556
"style-loader": "^3.3.1",
57+
"swc-loader": "^0.2.6",
5658
"terser-webpack-plugin": "5.3.1",
5759
"url-loader": "^4.0.0",
5860
"webpack": "5.72.0",

spec/dummy/yarn.lock

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,87 @@
13621362
dependencies:
13631363
"@sinonjs/commons" "^3.0.0"
13641364

1365+
1366+
version "1.15.0"
1367+
resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.0.tgz#158a0890fb2546b4d57b99234c1033e4a38b62e2"
1368+
integrity sha512-TBKWkbnShnEjlIbO4/gfsrIgAqHBVqgPWLbWmPdZ80bF393yJcLgkrb7bZEnJs6FCbSSuGwZv2rx1jDR2zo6YA==
1369+
1370+
1371+
version "1.15.0"
1372+
resolved "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.0.tgz#d03a71e60244f19ac921bf23c2cafc4122d76d8e"
1373+
integrity sha512-f5JKL1v1H56CIZc1pVn4RGPOfnWqPwmuHdpf4wesvXunF1Bx85YgcspW5YxwqG5J9g3nPU610UFuExJXVUzOiQ==
1374+
1375+
1376+
version "1.15.0"
1377+
resolved "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.0.tgz#fe978712a8924c0555c6b248ad3b57912ba123fb"
1378+
integrity sha512-duK6nG+WyuunnfsfiTUQdzC9Fk8cyDLqT9zyXvY2i2YgDu5+BH5W6wM5O4mDNCU5MocyB/SuF5YDF7XySnowiQ==
1379+
1380+
1381+
version "1.15.0"
1382+
resolved "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.0.tgz#a5dacdd857dec4ac2931820def17bc0e42c88ede"
1383+
integrity sha512-ITe9iDtTRXM98B91rvyPP6qDVbhUBnmA/j4UxrHlMQ0RlwpqTjfZYZkD0uclOxSZ6qIrOj/X5CaoJlDUuQ0+Cw==
1384+
1385+
1386+
version "1.15.0"
1387+
resolved "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.0.tgz#243643a7d22c8e2f334046c1d76f342ad4369be9"
1388+
integrity sha512-Q5ldc2bzriuzYEoAuqJ9Vr3FyZhakk5hiwDbniZ8tlEXpbjBhbOleGf9/gkhLaouDnkNUEazFW9mtqwUTRdh7Q==
1389+
1390+
1391+
version "1.15.0"
1392+
resolved "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.0.tgz#26936f55c916f65d33a4cf957c7573722f9eca54"
1393+
integrity sha512-pY4is+jEpOxlYCSnI+7N8Oxbap9TmTz5YT84tUvRTlOlTBwFAUlWFCX0FRwWJlsfP0TxbqhIe8dNNzlsEmJbXQ==
1394+
1395+
1396+
version "1.15.0"
1397+
resolved "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.0.tgz#a7164c11ac86ed99a1d5d8bef86ec0fbe6235f6c"
1398+
integrity sha512-zYEt5eT8y8RUpoe7t5pjpoOdGu+/gSTExj8PV86efhj6ugB3bPlj3Y85ogdW3WMVXr4NvwqvzdaYGCZfXzSyVg==
1399+
1400+
1401+
version "1.15.0"
1402+
resolved "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.0.tgz#645fe54564eab4224127672f2f4fe44876223af0"
1403+
integrity sha512-zC1rmOgFH5v2BCbByOazEqs0aRNpTdLRchDExfcCfgKgeaD+IdpUOqp7i3VG1YzkcnbuZjMlXfM0ugpt+CddoA==
1404+
1405+
1406+
version "1.15.0"
1407+
resolved "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.0.tgz#fd70c8c8b542a52a88cda758fb82569d52ea949a"
1408+
integrity sha512-7t9U9KwMwQblkdJIH+zX1V4q1o3o41i0HNO+VlnAHT5o+5qHJ963PHKJ/pX3P2UlZnBCY465orJuflAN4rAP9A==
1409+
1410+
1411+
version "1.15.0"
1412+
resolved "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.0.tgz#1d4f06078c7dbf757c537dd08740472694257198"
1413+
integrity sha512-VE0Zod5vcs8iMLT64m5QS1DlTMXJFI/qSgtMDRx8rtZrnjt6/9NW8XUaiPJuRu8GluEO1hmHoyf1qlbY19gGSQ==
1414+
1415+
"@swc/core@^1.7.0":
1416+
version "1.15.0"
1417+
resolved "https://registry.npmjs.org/@swc/core/-/core-1.15.0.tgz#6ae4dbd5a164261ba799ccdf9eae3bbc61e112c2"
1418+
integrity sha512-8SnJV+JV0rYbfSiEiUvYOmf62E7QwsEG+aZueqSlKoxFt0pw333+bgZSQXGUV6etXU88nxur0afVMaINujBMSw==
1419+
dependencies:
1420+
"@swc/counter" "^0.1.3"
1421+
"@swc/types" "^0.1.25"
1422+
optionalDependencies:
1423+
"@swc/core-darwin-arm64" "1.15.0"
1424+
"@swc/core-darwin-x64" "1.15.0"
1425+
"@swc/core-linux-arm-gnueabihf" "1.15.0"
1426+
"@swc/core-linux-arm64-gnu" "1.15.0"
1427+
"@swc/core-linux-arm64-musl" "1.15.0"
1428+
"@swc/core-linux-x64-gnu" "1.15.0"
1429+
"@swc/core-linux-x64-musl" "1.15.0"
1430+
"@swc/core-win32-arm64-msvc" "1.15.0"
1431+
"@swc/core-win32-ia32-msvc" "1.15.0"
1432+
"@swc/core-win32-x64-msvc" "1.15.0"
1433+
1434+
"@swc/counter@^0.1.3":
1435+
version "0.1.3"
1436+
resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
1437+
integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
1438+
1439+
"@swc/types@^0.1.25":
1440+
version "0.1.25"
1441+
resolved "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz#b517b2a60feb37dd933e542d93093719e4cf1078"
1442+
integrity sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==
1443+
dependencies:
1444+
"@swc/counter" "^0.1.3"
1445+
13651446
"@types/babel__core@^7.1.14":
13661447
version "7.20.5"
13671448
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
@@ -3236,6 +3317,11 @@ find-up@^5.0.0:
32363317
locate-path "^6.0.0"
32373318
path-exists "^4.0.0"
32383319

3320+
flat@^5.0.2:
3321+
version "5.0.2"
3322+
resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
3323+
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
3324+
32393325
follow-redirects@^1.0.0:
32403326
version "1.14.5"
32413327
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381"
@@ -5648,13 +5734,14 @@ sha.js@^2.4.0, sha.js@^2.4.8:
56485734
inherits "^2.0.1"
56495735
safe-buffer "^5.0.1"
56505736

5651-
shakapacker@8.2.0:
5652-
version "8.2.0"
5653-
resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-8.2.0.tgz#c7bed87b8be2ae565cfe616f68552be545c77e14"
5654-
integrity sha512-Ct7BFqJVnKbxdqCzG+ja7Q6LPt/PlB7sSVBfG5jsAvmVCADM05cuoNwEgYNjFGKbDzHAxUqy5XgoI9Y030+JKQ==
5737+
shakapacker@9.0.0:
5738+
version "9.0.0"
5739+
resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-9.0.0.tgz#36fd2e81ffa3a01075222526b2b079bfd60a6efc"
5740+
integrity sha512-q+8VU3AQhPpCLlZmEmyooELmpa10FPXk631rrg46pLAYO40jnEeyK01BtI0SVNvz/nI+QFz1DwZE8NKVk/PRgw==
56555741
dependencies:
56565742
js-yaml "^4.1.0"
56575743
path-complete-extname "^1.0.0"
5744+
webpack-merge "^5.8.0"
56585745

56595746
shallow-clone@^3.0.0:
56605747
version "3.0.1"
@@ -5961,6 +6048,13 @@ supports-preserve-symlinks-flag@^1.0.0:
59616048
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
59626049
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
59636050

6051+
swc-loader@^0.2.6:
6052+
version "0.2.6"
6053+
resolved "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz#bf0cba8eeff34bb19620ead81d1277fefaec6bc8"
6054+
integrity sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==
6055+
dependencies:
6056+
"@swc/counter" "^0.1.3"
6057+
59646058
symbol-observable@^1.2.0:
59656059
version "1.2.0"
59666060
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
@@ -6340,6 +6434,15 @@ webpack-merge@5, webpack-merge@^5.7.3:
63406434
clone-deep "^4.0.1"
63416435
wildcard "^2.0.0"
63426436

6437+
webpack-merge@^5.8.0:
6438+
version "5.10.0"
6439+
resolved "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177"
6440+
integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==
6441+
dependencies:
6442+
clone-deep "^4.0.1"
6443+
flat "^5.0.2"
6444+
wildcard "^2.0.0"
6445+
63436446
webpack-sources@^3.2.3:
63446447
version "3.2.3"
63456448
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"

0 commit comments

Comments
 (0)