shakapacker 9.1.0 → 9.3.0.beta.0

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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +6 -9
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +6 -8
  4. data/.github/workflows/claude-code-review.yml +4 -5
  5. data/.github/workflows/claude.yml +1 -2
  6. data/.github/workflows/dummy.yml +4 -4
  7. data/.github/workflows/generator.yml +9 -9
  8. data/.github/workflows/node.yml +11 -2
  9. data/.github/workflows/ruby.yml +16 -16
  10. data/.github/workflows/test-bundlers.yml +9 -9
  11. data/.gitignore +7 -0
  12. data/CHANGELOG.md +50 -4
  13. data/CLAUDE.md +6 -1
  14. data/CONTRIBUTING.md +0 -1
  15. data/Gemfile.lock +1 -1
  16. data/README.md +35 -14
  17. data/TODO.md +10 -2
  18. data/TODO_v9.md +13 -3
  19. data/bin/export-bundler-config +11 -0
  20. data/conductor-setup.sh +1 -1
  21. data/conductor.json +1 -1
  22. data/docs/cdn_setup.md +13 -8
  23. data/docs/common-upgrades.md +2 -1
  24. data/docs/configuration.md +630 -0
  25. data/docs/css-modules-export-mode.md +120 -100
  26. data/docs/customizing_babel_config.md +16 -16
  27. data/docs/deployment.md +68 -6
  28. data/docs/developing_shakapacker.md +6 -0
  29. data/docs/optional-peer-dependencies.md +9 -4
  30. data/docs/peer-dependencies.md +17 -6
  31. data/docs/precompile_hook.md +342 -0
  32. data/docs/react.md +57 -47
  33. data/docs/releasing.md +195 -0
  34. data/docs/rspack.md +25 -21
  35. data/docs/rspack_migration_guide.md +363 -8
  36. data/docs/sprockets.md +1 -0
  37. data/docs/style_loader_vs_mini_css.md +12 -12
  38. data/docs/subresource_integrity.md +13 -7
  39. data/docs/transpiler-performance.md +40 -19
  40. data/docs/troubleshooting.md +122 -23
  41. data/docs/typescript-migration.md +48 -39
  42. data/docs/typescript.md +12 -8
  43. data/docs/using_esbuild_loader.md +10 -10
  44. data/docs/v6_upgrade.md +33 -20
  45. data/docs/v7_upgrade.md +8 -6
  46. data/docs/v8_upgrade.md +13 -12
  47. data/docs/v9_upgrade.md +2 -1
  48. data/eslint.config.fast.js +134 -0
  49. data/eslint.config.js +140 -0
  50. data/knip.ts +54 -0
  51. data/lib/install/bin/export-bundler-config +11 -0
  52. data/lib/install/bin/shakapacker +1 -1
  53. data/lib/install/bin/shakapacker-dev-server +1 -1
  54. data/lib/install/config/shakapacker.yml +16 -5
  55. data/lib/shakapacker/bundler_switcher.rb +7 -0
  56. data/lib/shakapacker/compiler.rb +80 -0
  57. data/lib/shakapacker/configuration.rb +56 -2
  58. data/lib/shakapacker/dev_server_runner.rb +140 -1
  59. data/lib/shakapacker/doctor.rb +302 -57
  60. data/lib/shakapacker/instance.rb +8 -3
  61. data/lib/shakapacker/rspack_runner.rb +1 -1
  62. data/lib/shakapacker/runner.rb +245 -9
  63. data/lib/shakapacker/version.rb +1 -1
  64. data/lib/shakapacker/webpack_runner.rb +1 -1
  65. data/lib/shakapacker.rb +10 -0
  66. data/lib/tasks/shakapacker/doctor.rake +42 -2
  67. data/lib/tasks/shakapacker/export_bundler_config.rake +72 -0
  68. data/package/babel/preset.ts +7 -4
  69. data/package/config.ts +42 -30
  70. data/package/configExporter/cli.ts +1274 -0
  71. data/package/configExporter/configDocs.ts +102 -0
  72. data/package/configExporter/configFile.ts +520 -0
  73. data/package/configExporter/fileWriter.ts +96 -0
  74. data/package/configExporter/index.ts +13 -0
  75. data/package/configExporter/types.ts +70 -0
  76. data/package/configExporter/yamlSerializer.ts +280 -0
  77. data/package/dev_server.ts +1 -1
  78. data/package/environments/__type-tests__/rspack-plugin-compatibility.ts +11 -5
  79. data/package/environments/base.ts +18 -13
  80. data/package/environments/development.ts +1 -1
  81. data/package/environments/production.ts +4 -1
  82. data/package/index.d.ts +50 -3
  83. data/package/index.d.ts.template +50 -0
  84. data/package/index.ts +7 -7
  85. data/package/loaders.d.ts +2 -2
  86. data/package/optimization/rspack.ts +1 -1
  87. data/package/plugins/rspack.ts +15 -4
  88. data/package/plugins/webpack.ts +7 -3
  89. data/package/rspack/index.ts +10 -2
  90. data/package/rules/raw.ts +3 -2
  91. data/package/rules/sass.ts +1 -1
  92. data/package/types/README.md +15 -13
  93. data/package/types/index.ts +5 -5
  94. data/package/types.ts +0 -1
  95. data/package/utils/defaultConfigPath.ts +4 -1
  96. data/package/utils/errorCodes.ts +129 -100
  97. data/package/utils/errorHelpers.ts +34 -29
  98. data/package/utils/getStyleRule.ts +5 -2
  99. data/package/utils/helpers.ts +21 -11
  100. data/package/utils/pathValidation.ts +43 -35
  101. data/package/utils/requireOrError.ts +1 -1
  102. data/package/utils/snakeToCamelCase.ts +1 -1
  103. data/package/utils/typeGuards.ts +132 -83
  104. data/package/utils/validateDependencies.ts +1 -1
  105. data/package/webpack-types.d.ts +3 -3
  106. data/package/webpackDevServerConfig.ts +22 -10
  107. data/package-lock.json +2 -2
  108. data/package.json +37 -28
  109. data/scripts/type-check-no-emit.js +1 -1
  110. data/test/configExporter/configFile.test.js +392 -0
  111. data/test/configExporter/integration.test.js +275 -0
  112. data/test/helpers.js +1 -1
  113. data/test/package/configExporter.test.js +154 -0
  114. data/test/package/helpers.test.js +2 -2
  115. data/test/package/rules/sass-version-parsing.test.js +71 -0
  116. data/test/package/rules/sass.test.js +2 -4
  117. data/test/package/rules/sass1.test.js +1 -3
  118. data/test/package/rules/sass16.test.js +23 -0
  119. data/tools/README.md +15 -5
  120. data/tsconfig.eslint.json +2 -9
  121. data/yarn.lock +1635 -1442
  122. metadata +29 -3
  123. data/.eslintignore +0 -5
@@ -20,16 +20,16 @@ As of Shakapacker v9, all peer dependencies are marked as optional via `peerDepe
20
20
  "dependencies": {
21
21
  "js-yaml": "^4.1.0",
22
22
  "path-complete-extname": "^1.0.0",
23
- "webpack-merge": "^5.8.0" // Direct dependency - always available
23
+ "webpack-merge": "^5.8.0" // Direct dependency - always available
24
24
  },
25
25
  "peerDependencies": {
26
26
  "webpack": "^5.76.0",
27
- "@rspack/core": "^1.0.0",
27
+ "@rspack/core": "^1.0.0"
28
28
  // ... all build tools
29
29
  },
30
30
  "peerDependenciesMeta": {
31
31
  "webpack": { "optional": true },
32
- "@rspack/core": { "optional": true },
32
+ "@rspack/core": { "optional": true }
33
33
  // ... all marked as optional
34
34
  }
35
35
  }
@@ -49,6 +49,7 @@ Type-only imports are erased during compilation and don't trigger module resolut
49
49
  ## Configuration Examples
50
50
 
51
51
  ### Webpack + Babel (Traditional)
52
+
52
53
  ```json
53
54
  {
54
55
  "dependencies": {
@@ -63,6 +64,7 @@ Type-only imports are erased during compilation and don't trigger module resolut
63
64
  ```
64
65
 
65
66
  ### Webpack + SWC (20x Faster)
67
+
66
68
  ```json
67
69
  {
68
70
  "dependencies": {
@@ -76,6 +78,7 @@ Type-only imports are erased during compilation and don't trigger module resolut
76
78
  ```
77
79
 
78
80
  ### Rspack + SWC (10x Faster Bundling)
81
+
79
82
  ```json
80
83
  {
81
84
  "dependencies": {
@@ -100,6 +103,7 @@ If upgrading from Shakapacker v8:
100
103
  ### New Installations
101
104
 
102
105
  The installer (`rails shakapacker:install`) only adds packages needed for your configuration:
106
+
103
107
  - Detects your preferred bundler (webpack/rspack)
104
108
  - Installs appropriate JavaScript transpiler (babel/swc/esbuild)
105
109
  - Adds only required dependencies
@@ -129,12 +133,13 @@ Verify Shakapacker loads without optional dependencies:
129
133
 
130
134
  ```javascript
131
135
  // This works even without webpack installed (when using rspack)
132
- const shakapacker = require('shakapacker');
136
+ const shakapacker = require("shakapacker")
133
137
  ```
134
138
 
135
139
  ### CI Integration
136
140
 
137
141
  The test suite includes:
142
+
138
143
  - `spec/shakapacker/optional_dependencies_spec.rb` - Package.json structure validation
139
144
  - `spec/shakapacker/doctor_optional_peer_spec.rb` - Doctor command validation
140
145
  - `test/peer-dependencies.sh` - Installation warning tests
@@ -1,4 +1,5 @@
1
1
  # Shakapacker's Peer Dependencies
2
+
2
3
  ## Last updated for our 9.0.0 version — see lib/install/package.json
3
4
 
4
5
  To simplify peer dependencies while supporting both webpack & rspack, we decided to document the dependencies here instead of creating two separate npm packages.
@@ -6,13 +7,16 @@ To simplify peer dependencies while supporting both webpack & rspack, we decided
6
7
  **Important Note**: Starting with v9, Babel dependencies are no longer included as peer dependencies. They will be installed automatically only if you're using Babel as your JavaScript transpiler.
7
8
 
8
9
  ## Essential for Rspack
9
- ```
10
+
11
+ ```text
10
12
  "@rspack/cli": "^1.0.0",
11
13
  "@rspack/core": "^1.0.0",
12
14
  "rspack-manifest-plugin": "^5.0.0",
13
15
  ```
16
+
14
17
  ## Essential for Webpack
15
- ```
18
+
19
+ ```text
16
20
  "mini-css-extract-plugin": "^2.0.0",
17
21
  "terser-webpack-plugin": "^5.3.1",
18
22
  "webpack": "^5.76.0",
@@ -24,7 +28,8 @@ To simplify peer dependencies while supporting both webpack & rspack, we decided
24
28
  ```
25
29
 
26
30
  ## Highly recommended
27
- ```
31
+
32
+ ```text
28
33
  "compression-webpack-plugin": "^9.0.0 || ^10.0.0|| ^11.0.0",
29
34
  "css-loader": "^6.0.0 || ^7.0.0",
30
35
  "sass-loader": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
@@ -34,27 +39,33 @@ To simplify peer dependencies while supporting both webpack & rspack, we decided
34
39
  ## Optional JavaScript Transpilers
35
40
 
36
41
  ### Babel (installed automatically when `javascript_transpiler: 'babel'`)
37
- ```
42
+
43
+ ```text
38
44
  "@babel/core": "^7.17.9",
39
45
  "@babel/plugin-transform-runtime": "^7.17.0",
40
46
  "@babel/preset-env": "^7.16.11",
41
47
  "@babel/runtime": "^7.17.9",
42
48
  "babel-loader": "^8.2.4 || ^9.0.0 || ^10.0.0",
43
49
  ```
50
+
44
51
  Note: These dependencies are only installed if you're using Babel as your JavaScript transpiler. Consider using SWC or esbuild for better performance.
45
52
 
46
53
  ### SWC (default - 20x faster than Babel)
47
- ```
54
+
55
+ ```text
48
56
  "@swc/core": "latest",
49
57
  "swc-loader": "latest"
50
58
  ```
59
+
51
60
  - **For webpack**: Installed automatically when using default configuration
52
61
  - **For rspack**: Built-in, no additional installation needed (rspack includes SWC natively)
53
62
  - Manual install: `npm install @swc/core swc-loader`
54
63
 
55
64
  ### esbuild
56
- ```
65
+
66
+ ```text
57
67
  "esbuild": "latest",
58
68
  "esbuild-loader": "latest"
59
69
  ```
70
+
60
71
  Install manually with: `npm install esbuild esbuild-loader`
@@ -0,0 +1,342 @@
1
+ # Precompile Hook
2
+
3
+ The `precompile_hook` configuration option allows you to run a custom command before asset compilation.
4
+
5
+ **📖 For other configuration options, see the [Configuration Guide](./configuration.md)**
6
+
7
+ This is useful for:
8
+
9
+ - Dynamically generating entry points (e.g., from database records)
10
+ - Running preparatory tasks before bundling
11
+ - Integrating with tools like React on Rails that need to generate packs
12
+
13
+ ## When to Use
14
+
15
+ The precompile hook is especially useful when you need to run commands like:
16
+
17
+ - `bin/rails react_on_rails:generate_packs` - Generate dynamic entry points
18
+ - `bin/rails react_on_rails:locale` - Generate locale files
19
+ - Any custom script that prepares files before asset compilation
20
+
21
+ **Important:** The hook runs in **both development and production**:
22
+
23
+ - **Development**: Runs before `bin/shakapacker --watch` or dev server starts
24
+ - **Production**: Runs before `rails assets:precompile`
25
+
26
+ ## Configuration
27
+
28
+ Add the `precompile_hook` option to your `config/shakapacker.yml`:
29
+
30
+ ```yaml
31
+ # For all environments
32
+ default: &default
33
+ precompile_hook: "bin/shakapacker-precompile-hook"
34
+
35
+ # Or environment-specific
36
+ development:
37
+ <<: *default
38
+ precompile_hook: "bin/dev-setup"
39
+
40
+ production:
41
+ <<: *default
42
+ precompile_hook: "bin/rails react_on_rails:generate_packs"
43
+ ```
44
+
45
+ ## Creating a Precompile Hook Script
46
+
47
+ ### Simple Shell Script
48
+
49
+ ```bash
50
+ #!/usr/bin/env bash
51
+ # bin/shakapacker-precompile-hook
52
+
53
+ echo "Preparing assets..."
54
+ bin/rails react_on_rails:generate_packs
55
+ bin/rails react_on_rails:locale
56
+ echo "Assets prepared successfully"
57
+ ```
58
+
59
+ ### Ruby Script with Database Access
60
+
61
+ ```ruby
62
+ #!/usr/bin/env ruby
63
+ # bin/shakapacker-precompile-hook
64
+
65
+ require_relative "../config/environment"
66
+
67
+ puts "Generating dynamic entry points..."
68
+
69
+ # Generate entry points from database
70
+ Theme.find_each do |theme|
71
+ entry_point = Rails.root.join("app/javascript/packs/theme_#{theme.id}.js")
72
+ File.write(entry_point, "import '../themes/#{theme.identifier}';")
73
+ puts " Created #{entry_point}"
74
+ end
75
+
76
+ puts "Entry points generated successfully"
77
+ exit 0
78
+ ```
79
+
80
+ Make the script executable:
81
+
82
+ ```bash
83
+ chmod +x bin/shakapacker-precompile-hook
84
+ ```
85
+
86
+ ## How It Works
87
+
88
+ ### Execution Flow
89
+
90
+ 1. **Triggered** when asset compilation starts
91
+ 2. **Hook runs** in your project root directory
92
+ 3. **Environment variables** are passed through (including `NODE_ENV`, `RAILS_ENV`, `SHAKAPACKER_ASSET_HOST`)
93
+ 4. **On success** (exit code 0): Compilation proceeds
94
+ 5. **On failure** (non-zero exit code): Compilation stops with error
95
+
96
+ **Migration Note:** If you're migrating from custom `assets:precompile` enhancements (e.g., in `lib/tasks/assets.rake`), ensure you don't run the same commands twice. React on Rails versions before 16.1.1 automatically prepend `react_on_rails:generate_packs` to `assets:precompile`. Versions 16.1.1+ detect `precompile_hook` and skip automatic task enhancement to avoid duplicate execution. For custom Rake task enhancements, remove manual invocations when adding `precompile_hook`.
97
+
98
+ To verify correct migration, run `rake assets:precompile` and check the logs. Commands like `react_on_rails:generate_packs` should appear **only once** in the output. If you see duplicate execution, either upgrade React on Rails to 16.1.1+ or remove your custom task enhancements.
99
+
100
+ ### Logging
101
+
102
+ The hook's stdout and stderr are logged:
103
+
104
+ ```
105
+ Running precompile hook: bin/shakapacker-precompile-hook
106
+ Preparing assets...
107
+ Entry points generated successfully
108
+ Precompile hook completed successfully
109
+ Compiling...
110
+ ```
111
+
112
+ ## React on Rails Integration
113
+
114
+ For React on Rails projects, the hook replaces manual steps in your workflow:
115
+
116
+ ### Before (Manual)
117
+
118
+ ```bash
119
+ # Development
120
+ bin/rails react_on_rails:generate_packs
121
+ bin/rails react_on_rails:locale
122
+ bin/shakapacker-dev-server
123
+
124
+ # Production
125
+ bin/rails react_on_rails:generate_packs
126
+ bin/rails react_on_rails:locale
127
+ RAILS_ENV=production bin/rails assets:precompile
128
+ ```
129
+
130
+ ### After (Automatic)
131
+
132
+ ```yaml
133
+ # config/shakapacker.yml
134
+ default: &default
135
+ precompile_hook: "bin/react-on-rails-hook"
136
+ ```
137
+
138
+ ```bash
139
+ #!/usr/bin/env bash
140
+ # bin/react-on-rails-hook
141
+ bin/rails react_on_rails:generate_packs
142
+ bin/rails react_on_rails:locale
143
+ ```
144
+
145
+ Now simply run:
146
+
147
+ ```bash
148
+ # Development
149
+ bin/shakapacker-dev-server
150
+
151
+ # Production
152
+ RAILS_ENV=production bin/rails assets:precompile
153
+ ```
154
+
155
+ ## Security
156
+
157
+ For security reasons, the precompile hook is validated to ensure:
158
+
159
+ ### 1. Project Root Restriction
160
+
161
+ The hook **must** reference a script within your project root:
162
+
163
+ ```yaml
164
+ # ✅ Valid - within project
165
+ precompile_hook: 'bin/shakapacker-precompile-hook'
166
+ precompile_hook: 'script/prepare-assets'
167
+ precompile_hook: 'bin/hook --arg1 --arg2'
168
+
169
+ # ❌ Invalid - outside project
170
+ precompile_hook: '/usr/bin/malicious-script'
171
+ precompile_hook: '../../../etc/passwd'
172
+ ```
173
+
174
+ ### 2. Symlink Resolution
175
+
176
+ Symlinks are resolved to their real paths before validation:
177
+
178
+ ```bash
179
+ # If bin/hook is a symlink to /usr/bin/evil
180
+ # The validation will detect and reject it
181
+ ```
182
+
183
+ ### 3. Path Traversal Protection
184
+
185
+ Path traversal attempts are blocked:
186
+
187
+ ```yaml
188
+ # ❌ These will be rejected
189
+ precompile_hook: 'bin/../../etc/passwd'
190
+ precompile_hook: '../outside-project/script'
191
+ ```
192
+
193
+ ### 4. Proper Path Boundary Checking
194
+
195
+ Partial path matches are prevented:
196
+
197
+ ```
198
+ # /project won't match /project-evil
199
+ # Uses File::SEPARATOR for proper validation
200
+ ```
201
+
202
+ ## Error Handling
203
+
204
+ ### Hook Failure
205
+
206
+ If the hook fails, you'll see a detailed error:
207
+
208
+ ```
209
+ PRECOMPILE HOOK FAILED:
210
+ EXIT STATUS: 1
211
+ COMMAND: bin/shakapacker-precompile-hook
212
+ OUTPUTS:
213
+ Error: Theme not found
214
+
215
+ To fix this:
216
+ 1. Check that the hook script exists and is executable
217
+ 2. Test the hook command manually: bin/shakapacker-precompile-hook
218
+ 3. Review the error output above for details
219
+ 4. You can disable the hook temporarily by commenting out 'precompile_hook' in shakapacker.yml
220
+ ```
221
+
222
+ ### Missing Executable
223
+
224
+ If the script doesn't exist, you'll see a warning:
225
+
226
+ ```
227
+ ⚠️ Warning: precompile_hook executable not found: /path/to/project/bin/hook
228
+ The hook command is configured but the script does not exist within the project root.
229
+ Please ensure the script exists or remove 'precompile_hook' from your shakapacker.yml configuration.
230
+ ```
231
+
232
+ ## Troubleshooting
233
+
234
+ ### Test the Hook Manually
235
+
236
+ Run the hook directly to see what happens:
237
+
238
+ ```bash
239
+ bin/shakapacker-precompile-hook
240
+ echo $? # Should output 0 for success
241
+ ```
242
+
243
+ ### Check Permissions
244
+
245
+ Ensure the script is executable:
246
+
247
+ ```bash
248
+ ls -la bin/shakapacker-precompile-hook
249
+ # Should show: -rwxr-xr-x (executable)
250
+
251
+ # If not executable:
252
+ chmod +x bin/shakapacker-precompile-hook
253
+ ```
254
+
255
+ ### Debug with Verbose Output
256
+
257
+ Add debug output to your hook:
258
+
259
+ ```bash
260
+ #!/usr/bin/env bash
261
+ set -x # Enable verbose mode
262
+ echo "Current directory: $(pwd)"
263
+ echo "Environment: $RAILS_ENV"
264
+ # Your commands here
265
+ ```
266
+
267
+ ### Temporarily Disable
268
+
269
+ To disable the hook for testing:
270
+
271
+ ```yaml
272
+ # config/shakapacker.yml
273
+ default:
274
+ # precompile_hook: 'bin/shakapacker-precompile-hook'
275
+ ```
276
+
277
+ ### Common Issues
278
+
279
+ **Issue:** Hook fails in production but works in development - Verify all dependencies are available (database, commands, gems)
280
+
281
+ **Issue:** Generated files not found - Check `source_path` and `source_entry_path` in `shakapacker.yml`
282
+
283
+ **Issue:** Permission denied - Run `chmod +x bin/shakapacker-precompile-hook`
284
+
285
+ ## Advanced Usage
286
+
287
+ ### Conditional Execution
288
+
289
+ ```bash
290
+ #!/usr/bin/env bash
291
+ # bin/shakapacker-precompile-hook
292
+
293
+ if [ "$RAILS_ENV" = "production" ]; then
294
+ echo "Running production-specific setup..."
295
+ bin/rails react_on_rails:generate_packs
296
+ else
297
+ echo "Running development setup..."
298
+ # Lighter-weight setup for development
299
+ fi
300
+ ```
301
+
302
+ ### Hook with Arguments
303
+
304
+ ```yaml
305
+ precompile_hook: "bin/prepare-assets --verbose --cache-bust"
306
+ ```
307
+
308
+ ```bash
309
+ #!/usr/bin/env bash
310
+ # bin/prepare-assets
311
+
312
+ VERBOSE=false
313
+ CACHE_BUST=false
314
+
315
+ while [[ $# -gt 0 ]]; do
316
+ case $1 in
317
+ --verbose) VERBOSE=true ;;
318
+ --cache-bust) CACHE_BUST=true ;;
319
+ esac
320
+ shift
321
+ done
322
+
323
+ if [ "$VERBOSE" = true ]; then
324
+ echo "Preparing assets..."
325
+ fi
326
+ ```
327
+
328
+ ### Handling Spaces in Paths
329
+
330
+ Use quotes for paths with spaces:
331
+
332
+ ```yaml
333
+ precompile_hook: "'bin/my hook script' --arg1"
334
+ ```
335
+
336
+ The hook system uses `Shellwords` to properly parse quoted arguments.
337
+
338
+ ## See Also
339
+
340
+ - [Deployment Guide](deployment.md) - Production deployment considerations
341
+ - [React on Rails Integration](https://github.com/shakacode/react_on_rails) - Main use case documentation
342
+ - [Configuration](../README.md#configuration-and-code) - General shakapacker configuration