shakapacker 9.0.0.beta.4 → 9.0.0.beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintignore +1 -0
  3. data/.github/workflows/claude-code-review.yml +1 -1
  4. data/.github/workflows/dummy.yml +4 -0
  5. data/.github/workflows/generator.yml +7 -0
  6. data/.github/workflows/node.yml +22 -0
  7. data/.github/workflows/ruby.yml +11 -0
  8. data/.github/workflows/test-bundlers.yml +27 -9
  9. data/.gitignore +20 -0
  10. data/.yalcignore +26 -0
  11. data/CHANGELOG.md +58 -40
  12. data/CONTRIBUTING.md +64 -0
  13. data/Gemfile.lock +1 -1
  14. data/README.md +80 -1
  15. data/docs/optional-peer-dependencies.md +198 -0
  16. data/docs/typescript.md +99 -0
  17. data/docs/v9_upgrade.md +79 -2
  18. data/lib/install/template.rb +8 -1
  19. data/lib/shakapacker/configuration.rb +58 -1
  20. data/lib/shakapacker/doctor.rb +751 -0
  21. data/lib/shakapacker/swc_migrator.rb +292 -0
  22. data/lib/shakapacker/version.rb +1 -1
  23. data/lib/shakapacker.rb +1 -0
  24. data/lib/tasks/shakapacker/doctor.rake +8 -0
  25. data/lib/tasks/shakapacker/migrate_to_swc.rake +13 -0
  26. data/lib/tasks/shakapacker.rake +1 -0
  27. data/package/config.ts +162 -0
  28. data/package/{dev_server.js → dev_server.ts} +8 -5
  29. data/package/env.ts +67 -0
  30. data/package/environments/base.js +94 -117
  31. data/package/environments/base.ts +138 -0
  32. data/package/index.d.ts +3 -150
  33. data/package/{index.js → index.ts} +18 -8
  34. data/package/loaders.d.ts +28 -0
  35. data/package/types.ts +108 -0
  36. data/package/utils/configPath.ts +6 -0
  37. data/package/utils/{debug.js → debug.ts} +7 -7
  38. data/package/utils/defaultConfigPath.ts +4 -0
  39. data/package/utils/errorHelpers.ts +77 -0
  40. data/package/utils/{getStyleRule.js → getStyleRule.ts} +17 -20
  41. data/package/utils/helpers.ts +85 -0
  42. data/package/utils/{inliningCss.js → inliningCss.ts} +3 -3
  43. data/package/utils/{requireOrError.js → requireOrError.ts} +2 -2
  44. data/package/utils/snakeToCamelCase.ts +5 -0
  45. data/package/utils/typeGuards.ts +228 -0
  46. data/package/utils/{validateDependencies.js → validateDependencies.ts} +4 -4
  47. data/package/webpack-types.d.ts +33 -0
  48. data/package/webpackDevServerConfig.ts +117 -0
  49. data/package.json +112 -4
  50. data/test/peer-dependencies.sh +85 -0
  51. data/test/typescript/build.test.js +117 -0
  52. data/tsconfig.json +39 -0
  53. data/yarn.lock +1 -1
  54. metadata +34 -17
  55. data/package/config.js +0 -80
  56. data/package/env.js +0 -48
  57. data/package/utils/configPath.js +0 -4
  58. data/package/utils/defaultConfigPath.js +0 -2
  59. data/package/utils/helpers.js +0 -127
  60. data/package/utils/snakeToCamelCase.js +0 -5
  61. data/package/utils/validateCssModulesConfig.js +0 -91
  62. data/package/webpackDevServerConfig.js +0 -73
@@ -0,0 +1,198 @@
1
+ # Optional Peer Dependencies in Shakapacker
2
+
3
+ ## Overview
4
+
5
+ As of Shakapacker v9, all peer dependencies are marked as optional via `peerDependenciesMeta`. This design provides maximum flexibility while maintaining clear version constraints.
6
+
7
+ ## Key Benefits
8
+
9
+ 1. **No Installation Warnings** - Package managers (npm, yarn, pnpm) won't warn about missing peer dependencies
10
+ 2. **Install Only What You Need** - Users only install packages for their chosen configuration
11
+ 3. **Clear Version Constraints** - When packages are installed, version compatibility is still enforced
12
+ 4. **Smaller Node Modules** - Reduced disk usage by not installing unnecessary packages
13
+
14
+ ## Implementation Details
15
+
16
+ ### Package.json Structure
17
+
18
+ ```json
19
+ {
20
+ "dependencies": {
21
+ "js-yaml": "^4.1.0",
22
+ "path-complete-extname": "^1.0.0",
23
+ "webpack-merge": "^5.8.0" // Direct dependency - always available
24
+ },
25
+ "peerDependencies": {
26
+ "webpack": "^5.76.0",
27
+ "@rspack/core": "^1.0.0",
28
+ // ... all build tools
29
+ },
30
+ "peerDependenciesMeta": {
31
+ "webpack": { "optional": true },
32
+ "@rspack/core": { "optional": true },
33
+ // ... all marked as optional
34
+ }
35
+ }
36
+ ```
37
+
38
+ ### TypeScript Type-Only Imports
39
+
40
+ To prevent runtime errors when optional packages aren't installed, all webpack imports use type-only syntax:
41
+
42
+ ```typescript
43
+ // @ts-ignore: webpack is an optional peer dependency (using type-only import)
44
+ import type { Configuration } from "webpack"
45
+ ```
46
+
47
+ Type-only imports are erased during compilation and don't trigger module resolution at runtime.
48
+
49
+ ## Configuration Examples
50
+
51
+ ### Webpack + Babel (Traditional)
52
+ ```json
53
+ {
54
+ "dependencies": {
55
+ "shakapacker": "^9.0.0",
56
+ "webpack": "^5.76.0",
57
+ "webpack-cli": "^5.0.0",
58
+ "babel-loader": "^8.2.4",
59
+ "@babel/core": "^7.17.9",
60
+ "@babel/preset-env": "^7.16.11"
61
+ }
62
+ }
63
+ ```
64
+
65
+ ### Webpack + SWC (20x Faster)
66
+ ```json
67
+ {
68
+ "dependencies": {
69
+ "shakapacker": "^9.0.0",
70
+ "webpack": "^5.76.0",
71
+ "webpack-cli": "^5.0.0",
72
+ "@swc/core": "^1.3.0",
73
+ "swc-loader": "^0.2.0"
74
+ }
75
+ }
76
+ ```
77
+
78
+ ### Rspack + SWC (10x Faster Bundling)
79
+ ```json
80
+ {
81
+ "dependencies": {
82
+ "shakapacker": "^9.0.0",
83
+ "@rspack/core": "^1.0.0",
84
+ "@rspack/cli": "^1.0.0",
85
+ "rspack-manifest-plugin": "^5.0.0"
86
+ }
87
+ }
88
+ ```
89
+
90
+ ## Migration Guide
91
+
92
+ ### From v8 to v9
93
+
94
+ If upgrading from Shakapacker v8:
95
+
96
+ 1. **No action required** - Your existing dependencies will continue to work
97
+ 2. **No more warnings** - Peer dependency warnings will disappear after upgrading
98
+ 3. **Option to optimize** - You can now remove unused dependencies (e.g., remove Babel if using SWC)
99
+
100
+ ### New Installations
101
+
102
+ The installer (`rails shakapacker:install`) only adds packages needed for your configuration:
103
+ - Detects your preferred bundler (webpack/rspack)
104
+ - Installs appropriate JavaScript transpiler (babel/swc/esbuild)
105
+ - Adds only required dependencies
106
+
107
+ ## Version Constraints
108
+
109
+ Version ranges are carefully chosen for compatibility:
110
+
111
+ - **Broader ranges for peer deps** - Allows flexibility (e.g., `^5.76.0` for webpack)
112
+ - **Specific versions in devDeps** - Ensures testing against known versions
113
+ - **Forward compatibility** - Ranges include future minor versions (e.g., `^5.0.0 || ^6.0.0`)
114
+
115
+ ## Testing
116
+
117
+ ### Installation Tests
118
+
119
+ Test that no warnings appear during installation:
120
+
121
+ ```bash
122
+ # Test script available at test/peer-dependencies.sh
123
+ ./test/peer-dependencies.sh
124
+ ```
125
+
126
+ ### Runtime Tests
127
+
128
+ Verify Shakapacker loads without optional dependencies:
129
+
130
+ ```javascript
131
+ // This works even without webpack installed (when using rspack)
132
+ const shakapacker = require('shakapacker');
133
+ ```
134
+
135
+ ### CI Integration
136
+
137
+ The test suite includes:
138
+ - `spec/shakapacker/optional_dependencies_spec.rb` - Package.json structure validation
139
+ - `spec/shakapacker/doctor_optional_peer_spec.rb` - Doctor command validation
140
+ - `test/peer-dependencies.sh` - Installation warning tests
141
+
142
+ ## Troubleshooting
143
+
144
+ ### Still seeing peer dependency warnings?
145
+
146
+ 1. Ensure you're using Shakapacker v9.0.0 or later
147
+ 2. Clear your package manager cache:
148
+ - npm: `npm cache clean --force`
149
+ - yarn: `yarn cache clean`
150
+ - pnpm: `pnpm store prune`
151
+ 3. Reinstall dependencies
152
+
153
+ ### Module not found errors?
154
+
155
+ 1. Check you've installed required dependencies for your configuration
156
+ 2. Refer to the configuration examples above
157
+ 3. Run `rails shakapacker:doctor` for diagnostics
158
+
159
+ ### TypeScript errors?
160
+
161
+ The `@ts-ignore` comments are intentional and necessary for optional dependencies.
162
+ They prevent TypeScript errors when optional packages aren't installed.
163
+
164
+ ## Contributing
165
+
166
+ When adding new dependencies:
167
+
168
+ 1. Add to `peerDependencies` with appropriate version range
169
+ 2. Mark as optional in `peerDependenciesMeta`
170
+ 3. Use type-only imports in TypeScript: `import type { ... }`
171
+ 4. Test with all package managers (npm, yarn, pnpm)
172
+ 5. Update this documentation if needed
173
+
174
+ ## Design Rationale
175
+
176
+ This approach balances several concerns:
177
+
178
+ 1. **User Experience** - No confusing warnings during installation
179
+ 2. **Flexibility** - Support multiple configurations without forcing unnecessary installs
180
+ 3. **Compatibility** - Maintain version constraints for safety
181
+ 4. **Performance** - Reduce installation time and disk usage
182
+ 5. **Type Safety** - TypeScript support without runtime dependencies
183
+
184
+ ## Future Improvements
185
+
186
+ Potential enhancements for future versions:
187
+
188
+ 1. **Conditional exports** - Use package.json exports field for better tree-shaking
189
+ 2. **Dynamic imports** - Load bundler-specific code only when needed
190
+ 3. **Doctor updates** - Enhance doctor command to better understand optional dependencies
191
+ 4. **Automated testing** - Add CI jobs testing each configuration combination
192
+
193
+ ## References
194
+
195
+ - [npm: peerDependenciesMeta](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#peerdependenciesmeta)
196
+ - [TypeScript: Type-Only Imports](https://www.typescriptlang.org/docs/handbook/modules.html#type-only-imports-and-exports)
197
+ - [Shakapacker Issue #565](https://github.com/shakacode/shakapacker/issues/565)
198
+ - [Pull Request #615](https://github.com/shakacode/shakapacker/pull/615)
@@ -0,0 +1,99 @@
1
+ # TypeScript Support
2
+
3
+ Shakapacker v9 includes TypeScript support, providing type safety and better IDE experience for your webpack configurations.
4
+
5
+ ## Quick Start
6
+
7
+ ### Using TypeScript Config
8
+
9
+ ```typescript
10
+ // webpack.config.ts
11
+ import { generateWebpackConfig } from 'shakapacker'
12
+ import type { Configuration } from 'webpack'
13
+
14
+ const config: Configuration = generateWebpackConfig({
15
+ // Your config with full type safety
16
+ })
17
+
18
+ export default config
19
+ ```
20
+
21
+ ### Using JSDoc (JavaScript)
22
+
23
+ ```javascript
24
+ // webpack.config.js
25
+ const { generateWebpackConfig } = require('shakapacker')
26
+
27
+ /** @type {import('webpack').Configuration} */
28
+ const config = {
29
+ // Still get autocomplete in JS files!
30
+ }
31
+
32
+ module.exports = generateWebpackConfig(config)
33
+ ```
34
+
35
+ ## Benefits
36
+
37
+ - **Compile-time error detection** - Catch config errors before runtime
38
+ - **IDE autocomplete** - Full IntelliSense for all options
39
+ - **Type safety** - Prevents 85-100% of common configuration errors
40
+ - **No breaking changes** - Fully backward compatible
41
+
42
+ ## Migration
43
+
44
+ 1. **No migration required** - Existing JavaScript configs continue to work
45
+ 2. **Optional TypeScript** - Use it only if you want the benefits
46
+ 3. **Gradual adoption** - Start with JSDoc comments, move to TypeScript later
47
+
48
+ ## IDE Setup
49
+
50
+ ### VS Code
51
+ - Install TypeScript extension (built-in)
52
+ - Set `"typescript.tsdk": "node_modules/typescript/lib"` in settings
53
+
54
+ ### WebStorm/IntelliJ
55
+ - Enable TypeScript service in Settings → Languages & Frameworks → TypeScript
56
+
57
+ ## Common Patterns
58
+
59
+ ### Environment-Specific Config
60
+
61
+ ```typescript
62
+ import { generateWebpackConfig, env } from 'shakapacker'
63
+
64
+ const config = generateWebpackConfig({
65
+ optimization: {
66
+ minimize: env.isProduction
67
+ }
68
+ })
69
+ ```
70
+
71
+ ### Rspack Config
72
+
73
+ ```typescript
74
+ import { generateRspackConfig } from 'shakapacker/rspack'
75
+ import type { RspackOptions } from '@rspack/core'
76
+
77
+ const config: RspackOptions = {
78
+ // Rspack-specific config
79
+ }
80
+
81
+ export default generateRspackConfig(config)
82
+ ```
83
+
84
+ ## Troubleshooting
85
+
86
+ **Cannot find module 'shakapacker'**
87
+ ```typescript
88
+ /// <reference types="shakapacker" />
89
+ ```
90
+
91
+ **Type errors with custom loaders**
92
+ ```typescript
93
+ use: [require.resolve('custom-loader') as any]
94
+ ```
95
+
96
+ ## Further Reading
97
+
98
+ - [Webpack TypeScript Documentation](https://webpack.js.org/configuration/configuration-languages/#typescript)
99
+ - [TypeScript Handbook](https://www.typescriptlang.org/docs/)
data/docs/v9_upgrade.md CHANGED
@@ -1,6 +1,19 @@
1
1
  # Shakapacker v9 Upgrade Guide
2
2
 
3
- This guide outlines breaking changes and migration steps for upgrading from Shakapacker v8 to v9.
3
+ This guide outlines new features, breaking changes, and migration steps for upgrading from Shakapacker v8 to v9.
4
+
5
+ ## New Features
6
+
7
+ ### TypeScript Support
8
+
9
+ Shakapacker v9 includes TypeScript definitions for better IDE support and type safety.
10
+
11
+ - **No breaking changes** - JavaScript configs continue to work
12
+ - **Optional** - Use TypeScript only if you want it
13
+ - **Type safety** - Catch configuration errors at compile-time
14
+ - **IDE support** - Full autocomplete for all options
15
+
16
+ See the [TypeScript Documentation](./typescript.md) for usage examples.
4
17
 
5
18
  ## Breaking Changes
6
19
 
@@ -117,6 +130,35 @@ npm install esbuild esbuild-loader
117
130
  assets_bundler: 'rspack' # or 'webpack' (default)
118
131
  ```
119
132
 
133
+ ### 5. All Peer Dependencies Now Optional
134
+
135
+ **What changed:** All peer dependencies are now marked as optional via `peerDependenciesMeta`.
136
+
137
+ **Benefits:**
138
+ - **No installation warnings** - You won't see peer dependency warnings for packages you don't use
139
+ - **Install only what you need** - Using webpack? Don't install rspack. Using SWC? Don't install Babel.
140
+ - **Clear version constraints** - When you do install a package, version compatibility is still enforced
141
+
142
+ **What this means for you:**
143
+ - **Existing projects:** No changes needed. Your existing dependencies will continue to work.
144
+ - **New projects:** The installer only adds the packages you actually need based on your configuration.
145
+ - **Package manager behavior:** npm, yarn, and pnpm will no longer warn about missing peer dependencies.
146
+
147
+ **Example:** If you're using SWC with webpack, you only need:
148
+ ```json
149
+ {
150
+ "dependencies": {
151
+ "shakapacker": "^9.0.0",
152
+ "@swc/core": "^1.3.0",
153
+ "swc-loader": "^0.2.0",
154
+ "webpack": "^5.76.0",
155
+ "webpack-cli": "^5.0.0",
156
+ "webpack-dev-server": "^5.0.0"
157
+ }
158
+ }
159
+ ```
160
+ You won't get warnings about missing Babel, Rspack, or esbuild packages.
161
+
120
162
  ## Migration Steps
121
163
 
122
164
  ### Step 1: Update Dependencies
@@ -211,6 +253,41 @@ Update your global type definitions as shown in Step 2.
211
253
 
212
254
  If you see warnings about CSS module exports, ensure you've updated all imports to use named exports or have properly configured the override.
213
255
 
256
+ ### Unexpected Peer Dependency Warnings After Upgrade
257
+
258
+ 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.
259
+
260
+ **For npm:**
261
+ ```bash
262
+ rm -rf node_modules package-lock.json
263
+ npm install
264
+ ```
265
+
266
+ **For Yarn:**
267
+ ```bash
268
+ rm -rf node_modules yarn.lock
269
+ yarn install
270
+ ```
271
+
272
+ **For pnpm:**
273
+ ```bash
274
+ rm -rf node_modules pnpm-lock.yaml
275
+ pnpm install
276
+ ```
277
+
278
+ **For Bun:**
279
+ ```bash
280
+ rm -rf node_modules bun.lockb
281
+ bun install
282
+ ```
283
+
284
+ **When is this necessary?**
285
+ - If you see peer dependency warnings for packages you don't use (e.g., warnings about Babel when using SWC)
286
+ - If your package manager cached the old dependency resolution from v8
287
+ - After switching transpilers or bundlers (e.g., from Babel to SWC, or webpack to rspack)
288
+
289
+ **Note:** This is typically only needed once after the v8 → v9 upgrade. Subsequent installs will use the correct dependency resolution.
290
+
214
291
  ## Need Help?
215
292
 
216
293
  - See [CSS Modules Export Mode documentation](./css-modules-export-mode.md) for detailed configuration options
@@ -225,4 +302,4 @@ If you have a large codebase and need to migrate gradually:
225
302
  2. Migrate files incrementally
226
303
  3. Remove the override once migration is complete
227
304
 
228
- This allows you to upgrade to v9 immediately while taking time to update your CSS module imports.
305
+ This allows you to upgrade to v9 immediately while taking time to update your CSS module imports.
@@ -167,6 +167,11 @@ Dir.chdir(Rails.root) do
167
167
  # This ensures the runtime works regardless of config
168
168
  swc_deps = PackageJson.read(install_dir).fetch("swc")
169
169
  peers = peers.merge(swc_deps)
170
+
171
+ say "ℹ️ Installing both Babel and SWC packages for compatibility:", :blue
172
+ say " - Babel packages are installed as requested via USE_BABEL_PACKAGES", :blue
173
+ say " - SWC packages are also installed to ensure the default config works", :blue
174
+ say " - Your actual transpiler will be determined by your shakapacker.yml configuration", :blue
170
175
  elsif @transpiler_to_install == "swc"
171
176
  swc_deps = PackageJson.read(install_dir).fetch("swc")
172
177
  peers = peers.merge(swc_deps)
@@ -187,7 +192,9 @@ Dir.chdir(Rails.root) do
187
192
  entry = "#{package}@#{version}"
188
193
  else
189
194
  # Extract major version from complex version strings like ">= 4 || 5"
190
- major_version = version.split("||").last.match(/(\d+)/)[1]
195
+ # Fallback to "latest" if no version number found
196
+ version_match = version.split("||").last.match(/(\d+)/)
197
+ major_version = version_match ? version_match[1] : "latest"
191
198
  entry = "#{package}@#{major_version}"
192
199
  end
193
200
 
@@ -1,4 +1,5 @@
1
1
  require "yaml"
2
+ require "json"
2
3
  require "active_support/core_ext/hash/keys"
3
4
  require "active_support/core_ext/hash/indifferent_access"
4
5
 
@@ -123,7 +124,12 @@ class Shakapacker::Configuration
123
124
  end
124
125
 
125
126
  # Use explicit config if set, otherwise default based on bundler
126
- fetch(:javascript_transpiler) || fetch(:webpack_loader) || default_javascript_transpiler
127
+ transpiler = fetch(:javascript_transpiler) || fetch(:webpack_loader) || default_javascript_transpiler
128
+
129
+ # Validate transpiler configuration
130
+ validate_transpiler_configuration(transpiler) unless self.class.installing
131
+
132
+ transpiler
127
133
  end
128
134
 
129
135
  # Deprecated: Use javascript_transpiler instead
@@ -138,6 +144,57 @@ class Shakapacker::Configuration
138
144
  rspack? ? "swc" : "babel"
139
145
  end
140
146
 
147
+ def validate_transpiler_configuration(transpiler)
148
+ return unless ENV["NODE_ENV"] != "test" # Skip validation in test environment
149
+
150
+ # Check if package.json exists
151
+ package_json_path = root_path.join("package.json")
152
+ return unless package_json_path.exist?
153
+
154
+ begin
155
+ package_json = JSON.parse(File.read(package_json_path))
156
+ all_deps = (package_json["dependencies"] || {}).merge(package_json["devDependencies"] || {})
157
+
158
+ # Check for transpiler mismatch
159
+ has_babel = all_deps.keys.any? { |pkg| pkg.start_with?("@babel/", "babel-") }
160
+ has_swc = all_deps.keys.any? { |pkg| pkg.include?("swc") }
161
+ has_esbuild = all_deps.keys.any? { |pkg| pkg.include?("esbuild") }
162
+
163
+ case transpiler
164
+ when "babel"
165
+ if !has_babel && has_swc
166
+ warn_transpiler_mismatch("Babel", "SWC packages found but Babel is configured")
167
+ end
168
+ when "swc"
169
+ if !has_swc && has_babel
170
+ warn_transpiler_mismatch("SWC", "Babel packages found but SWC is configured")
171
+ end
172
+ when "esbuild"
173
+ if !has_esbuild && (has_babel || has_swc)
174
+ other = has_babel ? "Babel" : "SWC"
175
+ warn_transpiler_mismatch("esbuild", "#{other} packages found but esbuild is configured")
176
+ end
177
+ end
178
+ rescue JSON::ParserError
179
+ # Ignore if package.json is malformed
180
+ end
181
+ end
182
+
183
+ def warn_transpiler_mismatch(configured, message)
184
+ $stderr.puts <<~WARNING
185
+ ⚠️ Transpiler Configuration Mismatch Detected:
186
+ #{message}
187
+ Configured transpiler: #{configured}
188
+ #{' '}
189
+ This might cause unexpected behavior or build failures.
190
+ #{' '}
191
+ To fix this:
192
+ 1. Run 'rails shakapacker:migrate_to_swc' to migrate to SWC (recommended for 20x faster builds)
193
+ 2. Or install the correct packages for #{configured}
194
+ 3. Or update your shakapacker.yml to match your installed packages
195
+ WARNING
196
+ end
197
+
141
198
  public
142
199
 
143
200
  def fetch(key)