shakapacker 9.0.0.beta.8 → 9.0.0.beta.9

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: 6b968c57e16cafe6ddb6fb317b442db6b96682ee075498f3b8bc60f43f87d7bd
4
- data.tar.gz: a3bf4f39a4c6b869e3301723423387577a78a0818403c1bb31efd42f9bc0ac7c
3
+ metadata.gz: 5bcee4a9f167db64caa92dd26cc09d18b58a7bcd9e42df48d83a67ee588e4661
4
+ data.tar.gz: 70bee9a11ad197b10731b8f0870c52093fa64092ad470525679d32b44b64fcc2
5
5
  SHA512:
6
- metadata.gz: ebfa33ceea921c0c66f9a9affb4eb1c736c981696d87523e4a55f82311e6779a28b3b9ca0b8b8a270fb00dbd04302be57928091f4b7c7b580ee66d2585c98f4f
7
- data.tar.gz: 61a683b023eec46e7beb3a294db371b28ac1d8668744d7212ab938eb5a0a1fe53dba7763f5f9e90374ed329cb2f6ae07a232f3b0970e3bb4d504f4b79ea9eaeb
6
+ metadata.gz: 7c3be887fa8da2e9ef41aaf1753556da768002c7fcb0a765d348dac99c49d092caf2fe652008b86059a98c4b62d78326ff5f14cf4e39ed30696aebcd83560bc0
7
+ data.tar.gz: 2f4e2c8a069381191daed7fa8dbe6a38c93731c31399234d78621448d9a48a9d0759d9f84e29a94e8e87a88e4174e7a52d951470c56779fca673ebdc907fdda9
data/.husky/pre-commit ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env sh
2
+ npx lint-staged
data/CHANGELOG.md CHANGED
@@ -9,70 +9,9 @@
9
9
  ## [Unreleased]
10
10
  Changes since the last non-beta release.
11
11
 
12
- ### Added
13
- - **Phase 5 TypeScript Migration - Framework-Specific Modules** by [justin808](https://github.com/justin808)
14
- - Converted framework-specific modules to TypeScript
15
- - Migrated package/rspack/index.js to TypeScript
16
- - Migrated package/swc/index.js to TypeScript
17
- - Migrated package/esbuild/index.js to TypeScript
18
- - Migrated package/babel/preset.js to TypeScript
19
- - Added @types/babel__core for enhanced type safety
20
- - All 130 tests passing
21
- - **Phase 6 TypeScript Migration - Final Cleanup** (by [justin808](https://github.com/justin808))
22
- - Added TypeScript ESLint support with @typescript-eslint/parser and @typescript-eslint/eslint-plugin
23
- - Configured TypeScript-specific linting rules for improved code quality
24
- - Verified strict mode is enabled in TypeScript configuration
25
- - Enhanced developer experience with TypeScript linting across the entire codebase
26
-
27
- ## [v9.0.0-beta.7] - October 1, 2025
28
-
29
- ### Added
30
- - **Phase 2 TypeScript Migration - Core Modules** ([PR 608](https://github.com/shakacode/shakapacker/pull/608) by [justin808](https://github.com/justin808))
31
- - Converted core modules to TypeScript: config.ts, env.ts, and utilities
32
- - Enhanced type safety across the codebase
33
- - Better IDE support and autocomplete
34
- - **Phase 3 TypeScript Migration - Environment Files** ([PR 614](https://github.com/shakacode/shakapacker/pull/614) by [justin808](https://github.com/justin808))
35
- - Converted all environment configuration files to TypeScript (development, production, test)
36
- - Added centralized type exports for consumer use (import from "shakapacker/types")
37
- - Created shared TypeScript interfaces for environment configurations
38
- - Introduced structured error codes for programmatic error handling
39
- - Exported shared types: WebpackConfig, RspackConfig, EnvironmentConfig
40
- - **Optional Peer Dependencies** ([PR 615](https://github.com/shakacode/shakapacker/pull/615) by [justin808](https://github.com/justin808))
41
- - Restored peer dependencies as optional to improve package version tracking
42
- - Added peerDependenciesMeta marking all peers as optional
43
- - Moved webpack-merge to direct dependencies (required at runtime)
44
- - Prevents installation warnings while maintaining upgrade visibility
45
- - **Migration Tooling Improvements** ([PR 613](https://github.com/shakacode/shakapacker/pull/613) by [justin808](https://github.com/justin808))
46
- - Added SWC migration helper: rake shakapacker:migrate:to_swc
47
- - Enhanced error messages for missing dependencies
48
- - Improved doctor command output
49
-
50
- ### Security
51
- - **Path Validation Utilities** ([PR 614](https://github.com/shakacode/shakapacker/pull/614) by [justin808](https://github.com/justin808))
52
- - Added validation to prevent directory traversal attacks
53
- - Implemented environment variable sanitization to prevent injection
54
- - Enforced strict port validation (reject strings with non-digits)
55
- - Added SHAKAPACKER_NPM_PACKAGE path validation (only .tgz/.tar.gz allowed)
56
- - Path traversal security checks now run regardless of validation mode
12
+ ## [v9.0.0-beta.8] - October 3, 2025
57
13
 
58
- ### Changed
59
- - **Build Process Improvements** ([PR 614](https://github.com/shakacode/shakapacker/pull/614) by [justin808](https://github.com/justin808))
60
- - Environment JS files now generated during npm publish (not committed to git)
61
- - Prevents TypeScript source and compiled JS from getting out of sync
62
- - Auto-format compiled JavaScript during build process
63
- - Enhanced .npmignore to exclude TypeScript sources, include compiled JS
64
-
65
- ### Performance
66
- - **Validation Caching** ([PR 614](https://github.com/shakacode/shakapacker/pull/614) by [justin808](https://github.com/justin808))
67
- - Implemented TTL-based validation caching (5s watch, 1min dev, infinite prod)
68
- - Made cache TTL configurable via SHAKAPACKER_CACHE_TTL environment variable
69
- - Lazy-loaded and cached watch mode detection
70
-
71
- ### Fixed
72
- - Fixed clearValidationCache() to actually clear the cache ([PR 614](https://github.com/shakacode/shakapacker/pull/614) by [justin808](https://github.com/justin808))
73
- - Fixed private_output_path configuration edge cases ([PR 604](https://github.com/shakacode/shakapacker/pull/604) by [justin808](https://github.com/justin808))
74
-
75
- ## [v9.0.0-beta.4] - September 15, 2025
14
+ See the [v9 Upgrade Guide](https://github.com/shakacode/shakapacker/blob/main/docs/v9_upgrade.md) for detailed migration instructions.
76
15
 
77
16
  ### ⚠️ Breaking Changes
78
17
 
@@ -80,7 +19,7 @@ Changes since the last non-beta release.
80
19
  - Babel dependencies are no longer included as peer dependencies
81
20
  - Improves compilation speed by 20x
82
21
  - **Migration for existing projects:**
83
- - **Option 1 (Recommended):** Switch to SWC:
22
+ - **Option 1 (Recommended):** Switch to SWC - Run `rake shakapacker:migrate:to_swc` or manually:
84
23
  ```yaml
85
24
  # config/shakapacker.yml
86
25
  javascript_transpiler: 'swc'
@@ -93,11 +32,9 @@ Changes since the last non-beta release.
93
32
  ```
94
33
 
95
34
  2. **CSS Modules now use named exports by default**
96
- - Configured with `namedExport: true` and `exportLocalsConvention: 'camelCase'`
97
35
  - **JavaScript:** Use named imports: `import { className } from './styles.module.css'`
98
36
  - **TypeScript:** Use namespace imports: `import * as styles from './styles.module.css'`
99
- - Default imports (`import styles from '...'`) no longer work
100
- - See [CSS Modules Export Mode documentation](./docs/css-modules-export-mode.md) for migration details
37
+ - To keep the old behavior with default imports, see [CSS Modules Export Mode documentation](./docs/css-modules-export-mode.md) for configuration instructions
101
38
 
102
39
  3. **Configuration option renamed from `webpack_loader` to `javascript_transpiler`**
103
40
  - Better reflects its purpose of configuring JavaScript transpilation
@@ -109,23 +46,26 @@ Changes since the last non-beta release.
109
46
  - Faster Rust-based bundling with webpack-compatible APIs
110
47
  - Built-in SWC loader and CSS extraction
111
48
  - Automatic bundler detection in `bin/shakapacker`
112
- - **Private output path** for server-side rendering bundles ([PR 592](https://github.com/shakacode/shakapacker/pull/592) by [justin808](https://github.com/justin808))
113
- - Configure `private_output_path` for private server bundles
114
- - **Enhanced TypeScript definitions** ([PR 602](https://github.com/shakacode/shakapacker/pull/602) by [justin808](https://github.com/justin808))
115
- - Better IDE support and type safety
116
- - **`rake shakapacker:doctor` diagnostic command** ([PR 609](https://github.com/shakacode/shakapacker/pull/609) by [justin808](https://github.com/justin808))
117
- - Check for configuration issues and missing dependencies
118
- - Identify missing loaders that cause build errors
119
- - Particularly useful when migrating to v9 where peer dependencies are removed
120
- - Detects transpiler-specific issues based on v9 changes
49
+ - **TypeScript type definitions** for improved IDE support and autocomplete
50
+ - Types available via `import type { WebpackConfig, RspackConfig, EnvironmentConfig } from "shakapacker/types"`
51
+ - See [TypeScript Documentation](./docs/typescript.md) for migration and usage instructions
52
+ - **Optional peer dependencies** - All peer dependencies now marked as optional, preventing installation warnings while maintaining version compatibility tracking
53
+ - **Private output path** for server-side rendering bundles ([PR 592](https://github.com/shakacode/shakapacker/pull/592))
54
+ - Configure `private_output_path` for private server bundles separate from public assets
55
+ - **`rake shakapacker:doctor` diagnostic command** to check for configuration issues and missing dependencies
56
+ - **`rake shakapacker:migrate:to_swc`** migration helper to assist with switching from Babel to SWC
121
57
 
122
- ### Changed
123
- - Configuration option renamed from `bundler` to `assets_bundler` (deprecated but supported)
124
- - **Babel dependencies are now optional** instead of peer dependencies ([PR 603](https://github.com/shakacode/shakapacker/pull/603) by [justin808](https://github.com/justin808))
125
- - Installed automatically only when `javascript_transpiler` is set to 'babel'
58
+ ### Security
59
+ - **Path Validation Utilities** ([PR 614](https://github.com/shakacode/shakapacker/pull/614) by [justin808](https://github.com/justin808))
60
+ - Added validation to prevent directory traversal attacks
61
+ - Implemented environment variable sanitization to prevent injection
62
+ - Enforced strict port validation (reject strings with non-digits)
63
+ - Added SHAKAPACKER_NPM_PACKAGE path validation (only .tgz/.tar.gz allowed)
64
+ - Path traversal security checks now run regardless of validation mode
126
65
 
127
66
  ### Fixed
128
- - Update webpack-dev-server to secure versions (^4.15.2 || ^5.2.2) ([PR 585](https://github.com/shakacode/shakapacker/pull/585) by [justin808](https://github.com/justin808))
67
+ - Fixed private_output_path configuration edge cases ([PR 604](https://github.com/shakacode/shakapacker/pull/604))
68
+ - Updated webpack-dev-server to secure versions (^4.15.2 || ^5.2.2) ([PR 585](https://github.com/shakacode/shakapacker/pull/585))
129
69
 
130
70
  ## [v8.4.0] - September 8, 2024
131
71
 
@@ -547,8 +487,8 @@ Note: [Rubygem is 6.3.0.pre.rc.1](https://rubygems.org/gems/shakapacker/versions
547
487
  ## v5.4.3 and prior changes from rails/webpacker
548
488
  See [CHANGELOG.md in rails/webpacker (up to v5.4.3)](https://github.com/rails/webpacker/blob/master/CHANGELOG.md)
549
489
 
550
- [Unreleased]: https://github.com/shakacode/shakapacker/compare/v9.0.0-beta.4...main
551
- [v9.0.0-beta.4]: https://github.com/shakacode/shakapacker/compare/v8.4.0...v9.0.0-beta.4
490
+ [Unreleased]: https://github.com/shakacode/shakapacker/compare/v9.0.0-beta.8...main
491
+ [v9.0.0-beta.8]: https://github.com/shakacode/shakapacker/compare/v8.4.0...v9.0.0-beta.8
552
492
  [v8.4.0]: https://github.com/shakacode/shakapacker/compare/v8.3.0...v8.4.0
553
493
  [v8.3.0]: https://github.com/shakacode/shakapacker/compare/v8.2.0...v8.3.0
554
494
  [v8.2.0]: https://github.com/shakacode/shakapacker/compare/v8.1.0...v8.2.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shakapacker (9.0.0.beta.8)
4
+ shakapacker (9.0.0.beta.9)
5
5
  activesupport (>= 5.2)
6
6
  package_json
7
7
  rack-proxy (>= 0.6.1)
data/README.md CHANGED
@@ -1,13 +1,14 @@
1
- # Shakapacker (v8)
1
+ # Shakapacker (v9)
2
2
  ---
3
3
 
4
- _🚀 Shakapacker 9.0.0.beta.2 supports [Rspack](https://rspack.rs/)! 10x faster than webpack!_
4
+ _🚀 Shakapacker 9 supports [Rspack](https://rspack.rs/)! 10x faster than webpack!_
5
5
 
6
6
  ---
7
7
 
8
8
  _Official, actively maintained successor to [rails/webpacker](https://github.com/rails/webpacker). ShakaCode stands behind the long-term maintenance and development of this project for the Rails community._
9
9
 
10
10
  * ⚠️ See the [6-stable](https://github.com/shakacode/shakapacker/tree/6-stable) branch for Shakapacker v6.x code and documentation. :warning:
11
+ * **See [V9 Upgrade](./docs/v9_upgrade.md) for upgrading from the v8 release.**
11
12
  * See [V8 Upgrade](./docs/v8_upgrade.md) for upgrading from the v7 release.
12
13
  * See [V7 Upgrade](./docs/v7_upgrade.md) for upgrading from the v6 release.
13
14
  * See [V6 Upgrade](./docs/v6_upgrade.md) for upgrading from v5 or prior v6 releases.
data/TODO_v9.md CHANGED
@@ -20,12 +20,15 @@ Align with Next.js and modern tooling by using named exports:
20
20
  options: {
21
21
  modules: {
22
22
  namedExport: true,
23
- exportLocalsConvention: 'camelCase'
23
+ exportLocalsConvention: 'camelCaseOnly' // Must be 'camelCaseOnly' or 'dashesOnly' with namedExport: true
24
24
  }
25
25
  }
26
26
  }
27
27
  ```
28
28
 
29
+ **Note:** Using `exportLocalsConvention: 'camelCase'` with `namedExport: true` will cause a build error.
30
+ css-loader only allows `'camelCaseOnly'` or `'dashesOnly'` when named exports are enabled.
31
+
29
32
  2. **Update TypeScript types:**
30
33
  - Ensure proper typing for CSS modules with named exports
31
34
  - May need to update or generate `.d.ts` files for CSS modules
@@ -81,4 +84,4 @@ Align with Next.js and modern tooling by using named exports:
81
84
  ### Test Infrastructure
82
85
  - Successfully implemented dual bundler support (webpack/rspack)
83
86
  - test-bundler script working well with status command
84
- - Consider adding more comprehensive tests for both bundlers
87
+ - Consider adding more comprehensive tests for both bundlers
data/conductor-setup.sh CHANGED
@@ -35,6 +35,18 @@ $BUNDLE_CMD install
35
35
  echo "📦 Installing JavaScript dependencies..."
36
36
  yarn install
37
37
 
38
+ # Set up Husky git hooks
39
+ echo "🪝 Setting up Husky git hooks..."
40
+ npx husky
41
+ if [ ! -f .husky/pre-commit ]; then
42
+ echo "Creating pre-commit hook..."
43
+ cat > .husky/pre-commit << 'EOF'
44
+ #!/usr/bin/env sh
45
+ npx lint-staged
46
+ EOF
47
+ chmod +x .husky/pre-commit
48
+ fi
49
+
38
50
  # Copy environment files if they exist in root
39
51
  if [ -n "${CONDUCTOR_ROOT_PATH:-}" ]; then
40
52
  if [ -f "$CONDUCTOR_ROOT_PATH/.env" ]; then
@@ -32,6 +32,55 @@ import * as styles from './Foo.module.css';
32
32
  - Aligns with modern JavaScript module standards
33
33
  - Automatically converts kebab-case to camelCase (`my-button` → `myButton`)
34
34
 
35
+ ### Important: exportLocalsConvention with namedExport
36
+
37
+ When `namedExport: true` is enabled (v9 default), css-loader requires `exportLocalsConvention` to be either `'camelCaseOnly'` or `'dashesOnly'`.
38
+
39
+ **The following will cause a build error:**
40
+ ```js
41
+ modules: {
42
+ namedExport: true,
43
+ exportLocalsConvention: 'camelCase' // ❌ ERROR: incompatible with namedExport: true
44
+ }
45
+ ```
46
+
47
+ **Error message:**
48
+ ```
49
+ "exportLocalsConvention" with "camelCase" value is incompatible with "namedExport: true" option
50
+ ```
51
+
52
+ **Correct v9 configuration:**
53
+ ```js
54
+ modules: {
55
+ namedExport: true,
56
+ exportLocalsConvention: 'camelCaseOnly' // ✅ Correct - only camelCase exported
57
+ }
58
+ ```
59
+
60
+ **exportLocalsConvention options with namedExport:**
61
+
62
+ When `namedExport: true`, you can use:
63
+ - `'camelCaseOnly'` (v9 default): Exports ONLY the camelCase version (e.g., only `myButton`)
64
+ - `'dashesOnly'`: Exports ONLY the original kebab-case version (e.g., only `my-button`)
65
+
66
+ **Not compatible with namedExport: true:**
67
+ - `'camelCase'`: Exports both versions (both `my-button` and `myButton`) - only works with `namedExport: false` (v8 behavior)
68
+
69
+ **Configuration Quick Reference:**
70
+
71
+ | namedExport | exportLocalsConvention | `.my-button` exports | Use Case | Compatible? |
72
+ |-------------|------------------------|---------------------|----------|-------------|
73
+ | `true` | `'camelCaseOnly'` | `myButton` | JavaScript conventions | ✅ Valid |
74
+ | `true` | `'dashesOnly'` | `'my-button'` | Preserve CSS naming | ✅ Valid |
75
+ | `false` | `'camelCase'` | Both `myButton` AND `'my-button'` | v8 compatibility | ✅ Valid |
76
+ | `false` | `'asIs'` | `'my-button'` | No transformation | ✅ Valid |
77
+ | `true` | `'camelCase'` | - | - | ❌ Build Error |
78
+
79
+ **When to use each option:**
80
+ - Use `'camelCaseOnly'` if you prefer standard JavaScript naming conventions
81
+ - Use `'dashesOnly'` if you want to preserve your CSS class names exactly as written
82
+ - Use `'camelCase'` (with `namedExport: false`) only if you need both versions available
83
+
35
84
  ## Version 8.x and Earlier Behavior
36
85
 
37
86
  In Shakapacker v8 and earlier, the default behavior was to use a **default export object**:
@@ -244,7 +293,9 @@ import { bright, container, button } from './Component.module.css';
244
293
 
245
294
  #### 3. Handle Kebab-Case Class Names
246
295
 
247
- With v9's `exportLocalsConvention: 'camelCase'`, kebab-case class names are automatically converted:
296
+ **Option A: Use camelCase (v9 default)**
297
+
298
+ With `exportLocalsConvention: 'camelCaseOnly'`, kebab-case class names are automatically converted:
248
299
 
249
300
  ```css
250
301
  /* styles.module.css */
@@ -253,13 +304,35 @@ With v9's `exportLocalsConvention: 'camelCase'`, kebab-case class names are auto
253
304
  ```
254
305
 
255
306
  ```js
256
- // v9 imports (camelCase conversion)
307
+ // v9 default - camelCase conversion
257
308
  import { myButton, primaryColor } from './styles.module.css';
309
+ <button className={myButton} />
310
+ ```
258
311
 
259
- // Use the camelCase versions in your components
312
+ **Option B: Keep kebab-case with 'dashesOnly'**
313
+
314
+ If you prefer to preserve the original kebab-case names, configure your webpack to use `'dashesOnly'`:
315
+
316
+ ```js
317
+ // config/webpack/commonWebpackConfig.js
318
+ modules: {
319
+ namedExport: true,
320
+ exportLocalsConvention: 'dashesOnly'
321
+ }
322
+ ```
323
+
324
+ ```js
325
+ // With dashesOnly - preserve kebab-case
326
+ import * as styles from './styles.module.css';
327
+ <button className={styles['my-button']} />
328
+
329
+ // Or with aliasing:
330
+ import { 'my-button': myButton } from './styles.module.css';
260
331
  <button className={myButton} />
261
332
  ```
262
333
 
334
+ **Note:** With both `'camelCaseOnly'` and `'dashesOnly'`, only one version of each class name is exported. The original kebab-case name is NOT available with `'camelCaseOnly'`, and the camelCase version is NOT available with `'dashesOnly'`.
335
+
263
336
  #### 4. Using a Codemod for Large Codebases
264
337
 
265
338
  For large codebases, you can create a codemod to automate the migration:
@@ -298,12 +371,12 @@ npx jscodeshift -t css-modules-v9-migration.js src/
298
371
 
299
372
  ## Version Comparison
300
373
 
301
- | Feature | v8 (and earlier) | v9 |
302
- |---------|-----------------|----|
374
+ | Feature | v8 (and earlier) | v9 |
375
+ |---------|-----------------|----|
303
376
  | Default behavior | Default export object | Named exports |
304
377
  | Import syntax | `import styles from '...'` | `import { className } from '...'` |
305
378
  | Class reference | `styles.className` | `className` |
306
- | Export convention | `asIs` (no transformation) | `camelCase` |
379
+ | Export convention | `asIs` (no transformation) | `camelCaseOnly` |
307
380
  | TypeScript warnings | May show warnings | No warnings |
308
381
  | Tree-shaking | Limited | Optimized |
309
382
 
@@ -368,13 +441,34 @@ Then search for `css-loader` options in the generated JSON file.
368
441
 
369
442
  ## Troubleshooting
370
443
 
444
+ ### Build Error: exportLocalsConvention Incompatible with namedExport
445
+
446
+ If you see this error during build:
447
+ ```
448
+ "exportLocalsConvention" with "camelCase" value is incompatible with "namedExport: true" option
449
+ ```
450
+
451
+ **Cause:** Your webpack configuration has `namedExport: true` with `exportLocalsConvention: 'camelCase'`.
452
+
453
+ **Solution:** Change `exportLocalsConvention` to `'camelCaseOnly'` or `'dashesOnly'`:
454
+
455
+ ```js
456
+ // config/webpack/commonWebpackConfig.js or similar
457
+ modules: {
458
+ namedExport: true,
459
+ exportLocalsConvention: 'camelCaseOnly' // or 'dashesOnly'
460
+ }
461
+ ```
462
+
463
+ Alternatively, if you need the `'camelCase'` option (both original and camelCase exports), you must revert to v8 behavior by setting `namedExport: false` as shown in the "Reverting to Default Exports" section above.
464
+
371
465
  ### CSS Classes Not Applying
372
466
 
373
467
  If your CSS classes aren't applying after the upgrade:
374
468
 
375
469
  1. **Check import syntax**: Ensure you're using the correct import style for your configuration
376
470
  2. **Verify class names**: Use `console.log` to see available classes
377
- 3. **Check camelCase conversion**: Kebab-case names are converted to camelCase in v9
471
+ 3. **Check camelCase conversion**: Kebab-case names are converted to camelCase in v9 with `'camelCaseOnly'`
378
472
  4. **Rebuild webpack**: Clear cache and rebuild: `rm -rf tmp/cache && bin/shakapacker`
379
473
 
380
474
  ### TypeScript Support
@@ -415,4 +509,4 @@ The configuration changes should not impact build performance significantly. If
415
509
  - **v8 default**: Default export object with no conversion
416
510
  - **Migration path**: Update imports or override configuration
417
511
  - **Benefits of v9**: No warnings, better tree-shaking, explicit dependencies
418
- - **Keeping v8 behavior**: Override css-loader configuration as shown above
512
+ - **Keeping v8 behavior**: Override css-loader configuration as shown above
data/docs/v9_upgrade.md CHANGED
@@ -19,7 +19,18 @@ See the [TypeScript Documentation](./typescript.md) for usage examples.
19
19
 
20
20
  ### 1. CSS Modules Configuration Changed to Named Exports
21
21
 
22
- **What changed:** CSS Modules are now configured with `namedExport: true` and `exportLocalsConvention: 'camelCase'` by default, aligning with Next.js and modern tooling standards.
22
+ **What changed:** CSS Modules are now configured with `namedExport: true` and `exportLocalsConvention: 'camelCaseOnly'` by default, aligning with Next.js and modern tooling standards.
23
+
24
+ > **Important:** When `namedExport: true` is enabled, css-loader requires `exportLocalsConvention` to be either `'camelCaseOnly'` or `'dashesOnly'`. Using `'camelCase'` will cause a build error: `"exportLocalsConvention" with "camelCase" value is incompatible with "namedExport: true" option`.
25
+
26
+ **Quick Reference: Configuration Options**
27
+
28
+ | Configuration | namedExport | exportLocalsConvention | CSS: `.my-button` | Export Available | Works With |
29
+ |---------------|-------------|------------------------|-------------------|------------------|------------|
30
+ | **v9 Default** | `true` | `'camelCaseOnly'` | `.my-button` | `myButton` only | ✅ Named exports |
31
+ | **Alternative** | `true` | `'dashesOnly'` | `.my-button` | `'my-button'` only | ✅ Named exports |
32
+ | **v8 Style** | `false` | `'camelCase'` | `.my-button` | Both `myButton` AND `'my-button'` | ✅ Default export |
33
+ | **❌ Invalid** | `true` | `'camelCase'` | - | - | ❌ Build Error |
23
34
 
24
35
  **JavaScript Projects:**
25
36
  ```js
@@ -198,7 +209,7 @@ declare module '*.module.css' {
198
209
 
199
210
  ### Step 3: Handle Kebab-Case Class Names
200
211
 
201
- v9 automatically converts kebab-case to camelCase:
212
+ v9 automatically converts kebab-case to camelCase with `exportLocalsConvention: 'camelCaseOnly'`:
202
213
 
203
214
  ```css
204
215
  /* styles.module.css */
@@ -207,10 +218,34 @@ v9 automatically converts kebab-case to camelCase:
207
218
  ```
208
219
 
209
220
  ```js
210
- // v9 imports
221
+ // v9 default - camelCase conversion
211
222
  import { myButton, primaryColor } from './styles.module.css';
212
223
  ```
213
224
 
225
+ **Alternative: Keep kebab-case names with 'dashesOnly'**
226
+
227
+ If you prefer to keep kebab-case names in JavaScript, you can override the configuration to use `'dashesOnly'`:
228
+
229
+ ```js
230
+ // config/webpack/commonWebpackConfig.js
231
+ modules: {
232
+ namedExport: true,
233
+ exportLocalsConvention: 'dashesOnly' // Keep original kebab-case names
234
+ }
235
+ ```
236
+
237
+ Then use the original kebab-case names in your imports:
238
+
239
+ ```js
240
+ // With dashesOnly configuration
241
+ import { 'my-button': myButton, 'primary-color': primaryColor } from './styles.module.css';
242
+ // or access as properties
243
+ import * as styles from './styles.module.css';
244
+ const buttonClass = styles['my-button'];
245
+ ```
246
+
247
+ **Note:** With `'camelCaseOnly'` (default) or `'dashesOnly'`, only one version is exported. If you need both the original and camelCase versions, you would need to use `'camelCase'` instead, but this requires `namedExport: false` (v8 behavior). See the [CSS Modules Export Mode documentation](./css-modules-export-mode.md) for details on reverting to v8 behavior.
248
+
214
249
  ### Step 4: Update Configuration Files
215
250
 
216
251
  If you have `webpack_loader` in your configuration:
@@ -253,6 +288,25 @@ Update your global type definitions as shown in Step 2.
253
288
 
254
289
  If you see warnings about CSS module exports, ensure you've updated all imports to use named exports or have properly configured the override.
255
290
 
291
+ ### Build Error: exportLocalsConvention Incompatible with namedExport
292
+
293
+ If you see this error:
294
+ ```
295
+ "exportLocalsConvention" with "camelCase" value is incompatible with "namedExport: true" option
296
+ ```
297
+
298
+ This means your webpack configuration has `namedExport: true` with `exportLocalsConvention: 'camelCase'`. The fix is to change to `'camelCaseOnly'` or `'dashesOnly'`:
299
+
300
+ ```js
301
+ // config/webpack/commonWebpackConfig.js or wherever you configure css-loader
302
+ modules: {
303
+ namedExport: true,
304
+ exportLocalsConvention: 'camelCaseOnly' // or 'dashesOnly'
305
+ }
306
+ ```
307
+
308
+ If you want to use `'camelCase'` (which exports both original and camelCase versions), you must set `namedExport: false` and revert to v8 behavior. See the [CSS Modules Export Mode documentation](./css-modules-export-mode.md) for details.
309
+
256
310
  ### Unexpected Peer Dependency Warnings After Upgrade
257
311
 
258
312
  If you experience unexpected peer dependency warnings after upgrading to v9, you may need to clear your package manager's cache and reinstall dependencies. This ensures the new optional peer dependency configuration takes effect properly.
@@ -43,6 +43,7 @@ module Shakapacker
43
43
  # Dependency checks
44
44
  check_javascript_transpiler_dependencies if config_exists?
45
45
  check_css_dependencies
46
+ check_css_modules_configuration
46
47
  check_bundler_dependencies if config_exists?
47
48
  check_file_type_dependencies if config_exists?
48
49
  check_sri_dependencies if config_exists?
@@ -432,6 +433,28 @@ module Shakapacker
432
433
  if transpiler == "esbuild" && package_installed?("babel-loader")
433
434
  @warnings << "Both esbuild and Babel dependencies are installed. Consider removing Babel dependencies to reduce node_modules size"
434
435
  end
436
+
437
+ # Check for SWC configuration conflicts
438
+ if transpiler == "swc"
439
+ check_swc_config_conflicts
440
+ end
441
+ end
442
+
443
+ def check_swc_config_conflicts
444
+ swcrc_path = root_path.join(".swcrc")
445
+ return unless swcrc_path.exist?
446
+
447
+ begin
448
+ swcrc = JSON.parse(File.read(swcrc_path))
449
+ # Check for conflicting jsc.target and env settings
450
+ if swcrc.dig("jsc", "target") && swcrc["env"]
451
+ @issues << "SWC configuration conflict: .swcrc contains both 'jsc.target' and 'env' settings, which are mutually exclusive. Remove 'jsc.target' from .swcrc"
452
+ elsif swcrc.dig("jsc", "target")
453
+ @warnings << "SWC configuration: .swcrc contains 'jsc.target' which may conflict with the loader's 'env' setting. Consider removing 'jsc.target' from .swcrc to avoid build errors"
454
+ end
455
+ rescue JSON::ParserError
456
+ @warnings << "SWC configuration: .swcrc exists but contains invalid JSON"
457
+ end
435
458
  end
436
459
 
437
460
  def check_css_dependencies
@@ -440,6 +463,77 @@ module Shakapacker
440
463
  check_optional_dependency("mini-css-extract-plugin", @warnings, "CSS extraction")
441
464
  end
442
465
 
466
+ def check_css_modules_configuration
467
+ # Check for CSS module files in the project
468
+ return unless config_exists?
469
+
470
+ source_path = config.source_path
471
+ return unless source_path.exist?
472
+
473
+ # Performance optimization: Just check if ANY CSS module file exists
474
+ # Using .first with early return is much faster than globbing all files
475
+ css_module_exists = Dir.glob(File.join(source_path, "**/*.module.{css,scss,sass}")).first
476
+ return unless css_module_exists
477
+
478
+ # Check webpack configuration for CSS modules settings
479
+ webpack_config_paths = [
480
+ root_path.join("config/webpack/webpack.config.js"),
481
+ root_path.join("config/webpack/webpack.config.ts"),
482
+ root_path.join("config/webpack/commonWebpackConfig.js"),
483
+ root_path.join("config/webpack/commonWebpackConfig.ts")
484
+ ]
485
+
486
+ webpack_config_paths.each do |config_path|
487
+ next unless config_path.exist?
488
+
489
+ config_content = File.read(config_path)
490
+
491
+ # Check for the invalid configuration: namedExport: true with exportLocalsConvention: 'camelCase'
492
+ if config_content.match(/namedExport\s*:\s*true/) && config_content.match(/exportLocalsConvention\s*:\s*['"]camelCase['"]/)
493
+ @issues << "CSS Modules: Invalid configuration detected in #{config_path.relative_path_from(root_path)}"
494
+ @issues << " Using exportLocalsConvention: 'camelCase' with namedExport: true will cause build errors"
495
+ @issues << " Change to 'camelCaseOnly' or 'dashesOnly'. See docs/v9_upgrade.md for details"
496
+ end
497
+
498
+ # Warn if CSS modules are used but no configuration is found
499
+ if !config_content.match(/namedExport/) && !config_content.match(/exportLocalsConvention/)
500
+ @info << "CSS module files found but no explicit CSS modules configuration detected"
501
+ @info << " v9 defaults: namedExport: true, exportLocalsConvention: 'camelCaseOnly'"
502
+ end
503
+ end
504
+
505
+ # Check for common v8 to v9 migration issues
506
+ check_css_modules_import_patterns
507
+ rescue => e
508
+ # Don't fail doctor if CSS modules check has issues
509
+ @warnings << "Unable to validate CSS modules configuration: #{e.message}"
510
+ end
511
+
512
+ def check_css_modules_import_patterns
513
+ # Look for JavaScript/TypeScript files that might have v8-style imports
514
+ source_path = config.source_path
515
+
516
+ # Use lazy evaluation with Enumerator to avoid loading all file paths into memory
517
+ # Stop after checking 50 files or finding a match
518
+ v8_pattern = /import\s+\w+\s+from\s+['"][^'"]*\.module\.(css|scss|sass)['"]/
519
+
520
+ Dir.glob(File.join(source_path, "**/*.{js,jsx,ts,tsx}")).lazy.take(50).each do |file|
521
+ # Read file and check for v8 pattern
522
+ content = File.read(file)
523
+
524
+ # Check for v8 default import pattern with .module.css
525
+ if v8_pattern.match?(content)
526
+ @warnings << "Potential v8-style CSS module imports detected (using default import)"
527
+ @warnings << " v9 uses named exports. Update to: import { className } from './styles.module.css'"
528
+ @warnings << " Or use: import * as styles from './styles.module.css' (TypeScript)"
529
+ @warnings << " See docs/v9_upgrade.md for migration guide"
530
+ break # Stop after finding first occurrence
531
+ end
532
+ end
533
+ rescue => e
534
+ # Don't fail doctor if import pattern check has issues
535
+ end
536
+
443
537
  def check_bundler_dependencies
444
538
  bundler = config.assets_bundler
445
539
  case bundler
@@ -30,6 +30,15 @@ module Shakapacker
30
30
  "swc-loader" => "^0.2.6"
31
31
  }.freeze
32
32
 
33
+ ESLINT_CONFIG_FILES = %w[
34
+ .eslintrc
35
+ .eslintrc.js
36
+ .eslintrc.cjs
37
+ .eslintrc.yaml
38
+ .eslintrc.yml
39
+ .eslintrc.json
40
+ ].freeze
41
+
33
42
  DEFAULT_SWCRC_CONFIG = {
34
43
  "jsc" => {
35
44
  "parser" => {
@@ -41,8 +50,7 @@ module Shakapacker
41
50
  "react" => {
42
51
  "runtime" => "automatic"
43
52
  }
44
- },
45
- "target" => "es2015"
53
+ }
46
54
  },
47
55
  "module" => {
48
56
  "type" => "es6"
@@ -67,6 +75,10 @@ module Shakapacker
67
75
  logger.info "🎉 Migration to SWC complete!"
68
76
  logger.info " Note: SWC is approximately 20x faster than Babel for transpilation."
69
77
  logger.info " Please test your application thoroughly after migration."
78
+ logger.info "\n📝 Configuration Info:"
79
+ logger.info " - .swcrc provides base configuration for all environments"
80
+ logger.info " - The SWC loader adds automatic environment targeting (via 'env' setting)"
81
+ logger.info " - You can customize .swcrc, but avoid setting 'jsc.target' as it conflicts with 'env'"
70
82
 
71
83
  # Show cleanup recommendations if babel packages found
72
84
  if results[:babel_packages_found].any?
@@ -99,6 +111,16 @@ module Shakapacker
99
111
  return { removed_packages: [], config_files_deleted: [] }
100
112
  end
101
113
 
114
+ # Check if ESLint uses Babel parser
115
+ if eslint_uses_babel?
116
+ logger.info "\n⚠️ WARNING: ESLint configuration detected that may use Babel"
117
+ logger.info " If you use @babel/eslint-parser or babel-eslint, you may need to:"
118
+ logger.info " 1. Keep @babel/core and related Babel packages for ESLint"
119
+ logger.info " 2. Or switch to @typescript-eslint/parser for TypeScript files"
120
+ logger.info " 3. Or use espree (ESLint's default parser) for JavaScript files"
121
+ logger.info "\n Proceeding with Babel package removal. Check your ESLint config after."
122
+ end
123
+
102
124
  removed_packages = remove_babel_from_package_json(package_json_path)
103
125
  deleted_files = delete_babel_config_files
104
126
 
@@ -132,6 +154,42 @@ module Shakapacker
132
154
 
133
155
  private
134
156
 
157
+ def eslint_uses_babel?
158
+ # Check for ESLint config files
159
+ # Note: This is a heuristic check that may have false positives (e.g., in comments),
160
+ # but false positives only result in an extra warning, which is safer than silently
161
+ # breaking ESLint configurations.
162
+ ESLINT_CONFIG_FILES.each do |config_file|
163
+ config_path = root_path.join(config_file)
164
+ next unless config_path.exist?
165
+
166
+ content = File.read(config_path)
167
+ # Check for Babel parser references
168
+ return true if content.match?(/@babel\/eslint-parser|babel-eslint/)
169
+ end
170
+
171
+ # Check package.json for eslintConfig
172
+ package_json_path = root_path.join("package.json")
173
+ if package_json_path.exist?
174
+ begin
175
+ package_json = JSON.parse(File.read(package_json_path))
176
+ if package_json["eslintConfig"]
177
+ return true if package_json["eslintConfig"].to_json.match?(/@babel\/eslint-parser|babel-eslint/)
178
+ end
179
+
180
+ # Check if Babel ESLint packages are installed
181
+ dependencies = package_json["dependencies"] || {}
182
+ dev_dependencies = package_json["devDependencies"] || {}
183
+ all_deps = dependencies.merge(dev_dependencies)
184
+ return true if all_deps.key?("@babel/eslint-parser") || all_deps.key?("babel-eslint")
185
+ rescue JSON::ParserError => e
186
+ logger.debug "Could not parse package.json for ESLint detection: #{e.message}"
187
+ end
188
+ end
189
+
190
+ false
191
+ end
192
+
135
193
  def update_shakapacker_config
136
194
  config_path = root_path.join("config/shakapacker.yml")
137
195
  return false unless config_path.exist?
@@ -1,4 +1,4 @@
1
1
  module Shakapacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "9.0.0.beta.8".freeze
3
+ VERSION = "9.0.0.beta.9".freeze
4
4
  end
@@ -33,7 +33,12 @@ const getStyleRule = (test: RegExp, preprocessors: any[] = []): StyleRule | null
33
33
  sourceMap: true,
34
34
  importLoaders: 2,
35
35
  modules: {
36
- auto: true
36
+ auto: true,
37
+ // v9 defaults: Use named exports with camelCase conversion
38
+ // Note: css-loader requires 'camelCaseOnly' or 'dashesOnly' when namedExport is true
39
+ // Using 'camelCase' with namedExport: true causes a build error
40
+ namedExport: true,
41
+ exportLocalsConvention: 'camelCaseOnly'
37
42
  }
38
43
  }
39
44
  },
@@ -56,4 +61,4 @@ const getStyleRule = (test: RegExp, preprocessors: any[] = []): StyleRule | null
56
61
  return null
57
62
  }
58
63
 
59
- export = { getStyleRule }
64
+ export = { getStyleRule }
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shakapacker",
3
- "version": "9.0.0-beta.8",
3
+ "version": "9.0.0-beta.9",
4
4
  "description": "Use webpack to manage app-like JavaScript modules in Rails",
5
5
  "homepage": "https://github.com/shakacode/shakapacker",
6
6
  "bugs": {
data/tools/README.md CHANGED
@@ -104,7 +104,7 @@ const Button: React.FC = () => {
104
104
 
105
105
  ### Notes
106
106
 
107
- 1. **Kebab-case conversion**: CSS classes with kebab-case (e.g., `my-button`) are automatically converted to camelCase (`myButton`) for JavaScript files, matching css-loader's `exportLocalsConvention: 'camelCase'` setting.
107
+ 1. **Kebab-case conversion**: CSS classes with kebab-case (e.g., `my-button`) are automatically converted to camelCase (`myButton`) for JavaScript files, matching css-loader's `exportLocalsConvention: 'camelCaseOnly'` setting.
108
108
 
109
109
  2. **Unused imports**: The codemod only imports CSS classes that are actually used in JavaScript files. If you pass the entire styles object to a component, it will convert to namespace import for safety.
110
110
 
@@ -121,4 +121,4 @@ const Button: React.FC = () => {
121
121
  **Solution**: Ensure your TypeScript definitions are updated as shown in the [v9 Upgrade Guide](../docs/v9_upgrade.md).
122
122
 
123
123
  **Issue**: Runtime errors about missing CSS classes
124
- **Solution**: Check if you have kebab-case class names that need camelCase conversion.
124
+ **Solution**: Check if you have kebab-case class names that need camelCase conversion.
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: 9.0.0.beta.8
4
+ version: 9.0.0.beta.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -147,6 +147,7 @@ files:
147
147
  - ".github/workflows/ruby.yml"
148
148
  - ".github/workflows/test-bundlers.yml"
149
149
  - ".gitignore"
150
+ - ".husky/pre-commit"
150
151
  - ".node-version"
151
152
  - ".npmignore"
152
153
  - ".rspec"
@@ -346,7 +347,7 @@ homepage: https://github.com/shakacode/shakapacker
346
347
  licenses:
347
348
  - MIT
348
349
  metadata:
349
- source_code_uri: https://github.com/shakacode/shakapacker/tree/v9.0.0.beta.8
350
+ source_code_uri: https://github.com/shakacode/shakapacker/tree/v9.0.0.beta.9
350
351
  rdoc_options: []
351
352
  require_paths:
352
353
  - lib