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 +4 -4
- data/.husky/pre-commit +2 -0
- data/CHANGELOG.md +23 -83
- data/Gemfile.lock +1 -1
- data/README.md +3 -2
- data/TODO_v9.md +5 -2
- data/conductor-setup.sh +12 -0
- data/docs/css-modules-export-mode.md +102 -8
- data/docs/v9_upgrade.md +57 -3
- data/lib/shakapacker/doctor.rb +94 -0
- data/lib/shakapacker/swc_migrator.rb +60 -2
- data/lib/shakapacker/version.rb +1 -1
- data/package/utils/getStyleRule.ts +7 -2
- data/package.json +1 -1
- data/tools/README.md +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bcee4a9f167db64caa92dd26cc09d18b58a7bcd9e42df48d83a67ee588e4661
|
4
|
+
data.tar.gz: 70bee9a11ad197b10731b8f0870c52093fa64092ad470525679d32b44b64fcc2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c3be887fa8da2e9ef41aaf1753556da768002c7fcb0a765d348dac99c49d092caf2fe652008b86059a98c4b62d78326ff5f14cf4e39ed30696aebcd83560bc0
|
7
|
+
data.tar.gz: 2f4e2c8a069381191daed7fa8dbe6a38c93731c31399234d78621448d9a48a9d0759d9f84e29a94e8e87a88e4174e7a52d951470c56779fca673ebdc907fdda9
|
data/.husky/pre-commit
ADDED
data/CHANGELOG.md
CHANGED
@@ -9,70 +9,9 @@
|
|
9
9
|
## [Unreleased]
|
10
10
|
Changes since the last non-beta release.
|
11
11
|
|
12
|
-
|
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
|
-
|
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
|
-
-
|
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
|
-
- **
|
113
|
-
-
|
114
|
-
-
|
115
|
-
|
116
|
-
-
|
117
|
-
-
|
118
|
-
|
119
|
-
|
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
|
-
###
|
123
|
-
-
|
124
|
-
-
|
125
|
-
-
|
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
|
-
-
|
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.
|
551
|
-
[v9.0.0-beta.
|
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
data/README.md
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
-
# Shakapacker (
|
1
|
+
# Shakapacker (v9)
|
2
2
|
---
|
3
3
|
|
4
|
-
_🚀 Shakapacker 9
|
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: '
|
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
|
-
|
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
|
307
|
+
// v9 default - camelCase conversion
|
257
308
|
import { myButton, primaryColor } from './styles.module.css';
|
309
|
+
<button className={myButton} />
|
310
|
+
```
|
258
311
|
|
259
|
-
|
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) | `
|
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: '
|
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
|
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.
|
data/lib/shakapacker/doctor.rb
CHANGED
@@ -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?
|
data/lib/shakapacker/version.rb
CHANGED
@@ -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
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: '
|
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.
|
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.
|
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
|