shakapacker 9.0.0.beta.0 → 9.0.0.beta.3

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/claude-code-review.yml +54 -0
  3. data/.github/workflows/claude.yml +50 -0
  4. data/.github/workflows/dummy.yml +3 -3
  5. data/.github/workflows/test-bundlers.yml +152 -0
  6. data/.rubocop.yml +1 -0
  7. data/CHANGELOG.md +15 -3
  8. data/CLAUDE.md +29 -0
  9. data/Gemfile.lock +1 -1
  10. data/README.md +42 -1
  11. data/Rakefile +39 -4
  12. data/TODO.md +51 -0
  13. data/TODO_v9.md +84 -0
  14. data/conductor-setup.sh +58 -0
  15. data/conductor.json +7 -0
  16. data/docs/cdn_setup.md +379 -0
  17. data/docs/css-modules-export-mode.md +216 -86
  18. data/docs/deployment.md +10 -1
  19. data/docs/rspack.md +7 -7
  20. data/docs/rspack_migration_guide.md +202 -0
  21. data/docs/using_esbuild_loader.md +3 -3
  22. data/docs/using_swc_loader.md +5 -3
  23. data/docs/v6_upgrade.md +10 -0
  24. data/docs/v9_upgrade.md +185 -0
  25. data/lib/install/bin/shakapacker +3 -17
  26. data/lib/install/config/shakapacker.yml +9 -4
  27. data/lib/shakapacker/configuration.rb +75 -3
  28. data/lib/shakapacker/dev_server_runner.rb +19 -9
  29. data/lib/shakapacker/manifest.rb +4 -3
  30. data/lib/shakapacker/rspack_runner.rb +4 -42
  31. data/lib/shakapacker/runner.rb +105 -11
  32. data/lib/shakapacker/utils/manager.rb +2 -0
  33. data/lib/shakapacker/version.rb +1 -1
  34. data/lib/shakapacker/version_checker.rb +1 -1
  35. data/lib/shakapacker/webpack_runner.rb +4 -42
  36. data/lib/tasks/shakapacker/install.rake +6 -2
  37. data/package/config.js +24 -0
  38. data/package/environments/base.js +12 -2
  39. data/package/environments/development.js +52 -12
  40. data/package/environments/production.js +8 -3
  41. data/package/environments/test.js +5 -3
  42. data/package/index.d.ts +69 -30
  43. data/package/index.js +1 -1
  44. data/package/optimization/rspack.js +9 -5
  45. data/package/plugins/rspack.js +12 -28
  46. data/package/rspack/index.js +57 -0
  47. data/package/rules/babel.js +2 -2
  48. data/package/rules/esbuild.js +2 -2
  49. data/package/rules/raw.js +5 -5
  50. data/package/rules/rspack.js +77 -7
  51. data/package/rules/swc.js +2 -2
  52. data/package/utils/debug.js +49 -0
  53. data/package/utils/getStyleRule.js +19 -10
  54. data/package/utils/requireOrError.js +1 -1
  55. data/package/utils/validateCssModulesConfig.js +91 -0
  56. data/package/utils/validateDependencies.js +61 -0
  57. data/package/webpackDevServerConfig.js +2 -0
  58. data/package-lock.json +11966 -0
  59. data/package.json +9 -2
  60. data/test/package/rules/esbuild.test.js +1 -1
  61. data/test/package/rules/swc.test.js +1 -1
  62. data/tools/README.md +124 -0
  63. data/tools/css-modules-v9-codemod.js +179 -0
  64. data/yarn.lock +199 -81
  65. metadata +20 -3
  66. data/lib/install/bin/shakapacker-rspack +0 -13
@@ -0,0 +1,202 @@
1
+ # Rspack Migration Guide for Shakapacker
2
+
3
+ ## Overview
4
+ This guide documents the differences between webpack and Rspack configurations in Shakapacker, and provides migration guidance for users switching to Rspack.
5
+
6
+ ## Key Differences from Webpack
7
+
8
+ ### 1. Built-in Loaders
9
+ Rspack provides built-in loaders for better performance:
10
+
11
+ **JavaScript/TypeScript:**
12
+ - Use `builtin:swc-loader` instead of `babel-loader` or `ts-loader`
13
+ - 20x faster than Babel on single thread, 70x on multiple cores
14
+ - Configuration example:
15
+ ```javascript
16
+ {
17
+ test: /\.(js|jsx|ts|tsx)$/,
18
+ loader: 'builtin:swc-loader',
19
+ options: {
20
+ jsc: {
21
+ parser: {
22
+ syntax: 'typescript', // or 'ecmascript'
23
+ tsx: true, // for TSX files
24
+ jsx: true // for JSX files
25
+ },
26
+ transform: {
27
+ react: {
28
+ runtime: 'automatic'
29
+ }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ ### 2. Plugin Replacements
37
+
38
+ #### Built-in Rspack Alternatives
39
+ | Webpack Plugin | Rspack Alternative | Status |
40
+ |---------------|-------------------|---------|
41
+ | `copy-webpack-plugin` | `rspack.CopyRspackPlugin` | ✅ Built-in |
42
+ | `mini-css-extract-plugin` | `rspack.CssExtractRspackPlugin` | ✅ Built-in |
43
+ | `terser-webpack-plugin` | `rspack.SwcJsMinimizerRspackPlugin` | ✅ Built-in |
44
+ | `css-minimizer-webpack-plugin` | `rspack.LightningCssMinimizerRspackPlugin` | ✅ Built-in |
45
+
46
+ #### Community Alternatives
47
+ | Webpack Plugin | Rspack Alternative | Package |
48
+ |---------------|-------------------|----------|
49
+ | `fork-ts-checker-webpack-plugin` | `ts-checker-rspack-plugin` | `npm i -D ts-checker-rspack-plugin` |
50
+ | `@pmmmwh/react-refresh-webpack-plugin` | `@rspack/plugin-react-refresh` | `npm i -D @rspack/plugin-react-refresh` |
51
+ | `eslint-webpack-plugin` | `eslint-rspack-plugin` | `npm i -D eslint-rspack-plugin` |
52
+
53
+ #### Incompatible Plugins
54
+ The following webpack plugins are NOT compatible with Rspack:
55
+ - `webpack.optimize.LimitChunkCountPlugin` - Use `optimization.splitChunks` configuration instead
56
+ - `webpack-manifest-plugin` - Use `rspack-manifest-plugin` instead
57
+ - Git revision plugins - Use alternative approaches
58
+
59
+ ### 3. Asset Module Types
60
+ Replace file loaders with asset modules:
61
+ - `file-loader` → `type: 'asset/resource'`
62
+ - `url-loader` → `type: 'asset/inline'`
63
+ - `raw-loader` → `type: 'asset/source'`
64
+
65
+ ### 4. Configuration Differences
66
+
67
+ #### TypeScript Configuration
68
+ **Required:** Add `isolatedModules: true` to your `tsconfig.json`:
69
+ ```json
70
+ {
71
+ "compilerOptions": {
72
+ "isolatedModules": true
73
+ }
74
+ }
75
+ ```
76
+
77
+ #### React Fast Refresh
78
+ ```javascript
79
+ // Development configuration
80
+ const ReactRefreshPlugin = require('@rspack/plugin-react-refresh');
81
+
82
+ module.exports = {
83
+ plugins: [
84
+ new ReactRefreshPlugin(),
85
+ new rspack.HotModuleReplacementPlugin()
86
+ ]
87
+ };
88
+ ```
89
+
90
+ ### 5. Optimization Differences
91
+
92
+ #### Code Splitting
93
+ Rspack's `splitChunks` configuration is similar to webpack but with some differences:
94
+ ```javascript
95
+ optimization: {
96
+ splitChunks: {
97
+ chunks: 'all',
98
+ cacheGroups: {
99
+ vendor: {
100
+ test: /[\\/]node_modules[\\/]/,
101
+ priority: -10,
102
+ reuseExistingChunk: true
103
+ }
104
+ }
105
+ }
106
+ }
107
+ ```
108
+
109
+ #### Minimization
110
+ ```javascript
111
+ optimization: {
112
+ minimize: true,
113
+ minimizer: [
114
+ new rspack.SwcJsMinimizerRspackPlugin(),
115
+ new rspack.LightningCssMinimizerRspackPlugin()
116
+ ]
117
+ }
118
+ ```
119
+
120
+ ### 6. Development Server
121
+ Rspack uses its own dev server with some configuration differences:
122
+ ```javascript
123
+ devServer: {
124
+ // Rspack-specific: Force writing assets to disk
125
+ devMiddleware: {
126
+ writeToDisk: true
127
+ }
128
+ }
129
+ ```
130
+
131
+ ## Migration Checklist
132
+
133
+ ### Step 1: Update Dependencies
134
+ ```bash
135
+ # Remove webpack dependencies
136
+ npm uninstall webpack webpack-cli webpack-dev-server
137
+
138
+ # Install Rspack
139
+ npm install --save-dev @rspack/core @rspack/cli
140
+ ```
141
+
142
+ ### Step 2: Update Configuration Files
143
+ 1. Create `config/rspack/rspack.config.js` based on your webpack config
144
+ 2. Update `config/shakapacker.yml`:
145
+ ```yaml
146
+ assets_bundler: 'rspack'
147
+ ```
148
+
149
+ ### Step 3: Replace Loaders
150
+ - Replace `babel-loader` with `builtin:swc-loader`
151
+ - Remove `file-loader`, `url-loader`, `raw-loader` - use asset modules
152
+ - Update CSS loaders to use Rspack's built-in support
153
+
154
+ ### Step 4: Update Plugins
155
+ - Replace plugins with Rspack alternatives (see table above)
156
+ - Remove incompatible plugins
157
+ - Add Rspack-specific plugins as needed
158
+
159
+ ### Step 5: TypeScript Setup
160
+ 1. Add `isolatedModules: true` to `tsconfig.json`
161
+ 2. Optional: Add `ts-checker-rspack-plugin` for type checking
162
+
163
+ ### Step 6: Test Your Build
164
+ ```bash
165
+ # Development build
166
+ bin/shakapacker
167
+
168
+ # Production build
169
+ bin/shakapacker --mode production
170
+ ```
171
+
172
+ ## Common Issues and Solutions
173
+
174
+ ### Issue: LimitChunkCountPlugin Error
175
+ **Error:** `Cannot read properties of undefined (reading 'tap')`
176
+ **Solution:** Remove `webpack.optimize.LimitChunkCountPlugin` and use `splitChunks` configuration instead.
177
+
178
+ ### Issue: Missing Loaders
179
+ **Error:** Module parse errors
180
+ **Solution:** Check console logs for skipped loaders and install missing dependencies.
181
+
182
+ ### Issue: CSS Extraction
183
+ **Error:** CSS not being extracted properly
184
+ **Solution:** Use `rspack.CssExtractRspackPlugin` instead of `mini-css-extract-plugin`.
185
+
186
+ ### Issue: TypeScript Errors
187
+ **Error:** TypeScript compilation errors
188
+ **Solution:** Ensure `isolatedModules: true` is set in `tsconfig.json`.
189
+
190
+ ## Performance Tips
191
+
192
+ 1. **Use Built-in Loaders:** Always prefer Rspack's built-in loaders for better performance
193
+ 2. **Minimize Plugins:** Use only necessary plugins as each adds overhead
194
+ 3. **Enable Caching:** Rspack has built-in persistent caching
195
+ 4. **Use SWC:** The built-in SWC loader is significantly faster than Babel
196
+
197
+ ## Resources
198
+
199
+ - [Rspack Documentation](https://rspack.rs)
200
+ - [Rspack Examples](https://github.com/rspack-contrib/rspack-examples)
201
+ - [Awesome Rspack](https://github.com/rspack-contrib/awesome-rspack)
202
+ - [Migration Guide](https://rspack.rs/guide/migration/webpack)
@@ -27,7 +27,7 @@ To use esbuild as your transpiler today. You need to do two things:
27
27
  npm install esbuild esbuild-loader
28
28
  ```
29
29
 
30
- 2. Add or change `webpack_loader` value in your default `shakapacker.yml` config to `esbuild`
30
+ 2. Add or change `javascript_transpiler` value in your default `shakapacker.yml` config to `esbuild`
31
31
  The default configuration of babel is done by using `package.json` to use the file within the `shakapacker` package.
32
32
 
33
33
  ```yml
@@ -46,8 +46,8 @@ default: &default
46
46
  # Reload manifest.json on all requests so we reload latest compiled packs
47
47
  cache_manifest: false
48
48
 
49
- # Select loader to use, available options are 'babel' (default), 'swc' or 'esbuild'
50
- webpack_loader: 'esbuild'
49
+ # Select JavaScript transpiler to use, available options are 'babel' (default), 'swc' or 'esbuild'
50
+ javascript_transpiler: 'esbuild'
51
51
  ```
52
52
 
53
53
  ### (Optional) Replace minification with esbuild
@@ -12,6 +12,8 @@ It supports all ECMAScript features and it's designed to be a drop-in replacemen
12
12
 
13
13
  For comparison between SWC and Babel, see the docs at https://swc.rs/docs/migrating-from-babel.
14
14
 
15
+ > **Note:** SWC is also natively built into RSpack bundler, providing even faster compilation speeds. When using RSpack (`assets_bundler: 'rspack'`), SWC is used automatically regardless of the `javascript_transpiler` setting.
16
+
15
17
  ## Switching your Shakapacker project to SWC
16
18
 
17
19
  In order to use SWC as your compiler today. You need to do two things:
@@ -22,7 +24,7 @@ In order to use SWC as your compiler today. You need to do two things:
22
24
  npm install @swc/core swc-loader
23
25
  ```
24
26
 
25
- 2. Add or change `webpack_loader` value in your default `shakapacker.yml` config to `swc`
27
+ 2. Add or change `javascript_transpiler` value in your default `shakapacker.yml` config to `swc`
26
28
  The default configuration of babel is done by using `package.json` to use the file within the `shakapacker` package.
27
29
 
28
30
  ```yml
@@ -41,8 +43,8 @@ default: &default
41
43
  # Reload manifest.json on all requests so we reload latest compiled packs
42
44
  cache_manifest: false
43
45
 
44
- # Select loader to use, available options are 'babel' (default) or 'swc'
45
- webpack_loader: 'swc'
46
+ # Select JavaScript transpiler to use, available options are 'babel' (default) or 'swc'
47
+ javascript_transpiler: 'swc'
46
48
  ```
47
49
 
48
50
  ## Usage
data/docs/v6_upgrade.md CHANGED
@@ -101,6 +101,16 @@ _If you're on webpacker v5, follow [how to upgrade to webpacker v6.0.0.rc.6 from
101
101
 
102
102
  1. Update `webpack-dev-server` to the current version, greater than 4.2, updating `package.json`.
103
103
 
104
+ **Important:** If you encounter the error `[webpack-cli] Invalid options object. Dev Server has been initialized using an options object that does not match the API schema` with an unknown property `_assetEmittingPreviousFiles`, this indicates your webpack-dev-server configuration contains deprecated options.
105
+
106
+ To resolve this issue:
107
+ - Ensure you're using webpack-cli >= 4.7.0 with webpack-dev-server 5.x (webpack-cli 4.7+ is compatible with webpack-dev-server v5)
108
+ - Check your current versions: `npm list webpack-cli webpack-dev-server`
109
+ - Remove any legacy options like `_assetEmittingPreviousFiles` from your dev-server configuration
110
+ - Review the [webpack-dev-server migration guide](https://github.com/webpack/webpack-dev-server/blob/master/migration-v5.md) for proper v4 to v5 migration steps
111
+
112
+ See [issue #526](https://github.com/shakacode/shakapacker/issues/526) for more details.
113
+
104
114
  1. Update API usage of the view helpers by changing `javascript_packs_with_chunks_tag` and `stylesheet_packs_with_chunks_tag` to `javascript_pack_tag` and `stylesheet_pack_tag`. Ensure that your layouts and views will only have **at most one call** to `javascript_pack_tag` and **at most one call** to `stylesheet_pack_tag`. You can now pass multiple bundles to these view helper methods. If you fail to changes this, you may experience performance issues, and other bugs related to multiple copies of React, like [issue 2932](https://github.com/rails/webpacker/issues/2932). If you expose jquery globally with `expose-loader` by using `import $ from "expose-loader?exposes=$,jQuery!jquery"` in your `app/javascript/application.js`, pass the option `defer: false` to your `javascript_pack_tag`.
105
115
 
106
116
  1. If you are using any integrations like `css`, `postcss`, `React` or `TypeScript`. Please see https://github.com/shakacode/shakapacker#integrations section on how they work in v6.
@@ -0,0 +1,185 @@
1
+ # Shakapacker v9 Upgrade Guide
2
+
3
+ This guide outlines breaking changes and migration steps for upgrading from Shakapacker v8 to v9.
4
+
5
+ ## Breaking Changes
6
+
7
+ ### 1. CSS Modules Configuration Changed to Named Exports
8
+
9
+ **What changed:** CSS Modules are now configured with `namedExport: true` and `exportLocalsConvention: 'camelCase'` by default, aligning with Next.js and modern tooling standards.
10
+
11
+ **JavaScript Projects:**
12
+ ```js
13
+ // Before (v8)
14
+ import styles from './Component.module.css';
15
+ <button className={styles.button} />
16
+
17
+ // After (v9)
18
+ import { button } from './Component.module.css';
19
+ <button className={button} />
20
+ ```
21
+
22
+ **TypeScript Projects:**
23
+ ```typescript
24
+ // Before (v8)
25
+ import styles from './Component.module.css';
26
+ <button className={styles.button} />
27
+
28
+ // After (v9) - namespace import due to TypeScript limitations
29
+ import * as styles from './Component.module.css';
30
+ <button className={styles.button} />
31
+ ```
32
+
33
+ **Migration Options:**
34
+
35
+ 1. **Update your code** (Recommended):
36
+ - JavaScript: Change to named imports (`import { className }`)
37
+ - TypeScript: Change to namespace imports (`import * as styles`)
38
+ - Kebab-case class names are automatically converted to camelCase
39
+
40
+ 2. **Keep v8 behavior** temporarily:
41
+ - Override the css-loader configuration as shown in [CSS Modules Export Mode documentation](./css-modules-export-mode.md)
42
+ - This gives you time to migrate gradually
43
+
44
+ **Benefits of the change:**
45
+ - Eliminates webpack/TypeScript warnings
46
+ - Better tree-shaking of unused CSS classes
47
+ - More explicit about which classes are used
48
+ - Aligns with modern JavaScript standards
49
+
50
+ ### 2. Configuration Option Renamed: `webpack_loader` → `javascript_transpiler`
51
+
52
+ **What changed:** The configuration option has been renamed to better reflect its purpose.
53
+
54
+ **Before (v8):**
55
+ ```yml
56
+ # config/shakapacker.yml
57
+ webpack_loader: 'babel'
58
+ ```
59
+
60
+ **After (v9):**
61
+ ```yml
62
+ # config/shakapacker.yml
63
+ javascript_transpiler: 'babel'
64
+ ```
65
+
66
+ **Note:** The old `webpack_loader` option is deprecated but still supported with a warning.
67
+
68
+ ### 3. Rspack Support Added
69
+
70
+ **New feature:** Shakapacker v9 adds support for Rspack as an alternative bundler to webpack.
71
+
72
+ ```yml
73
+ # config/shakapacker.yml
74
+ assets_bundler: 'rspack' # or 'webpack' (default)
75
+ ```
76
+
77
+ ## Migration Steps
78
+
79
+ ### Step 1: Update Dependencies
80
+
81
+ ```bash
82
+ npm update shakapacker@^9.0.0
83
+ # or
84
+ yarn upgrade shakapacker@^9.0.0
85
+ ```
86
+
87
+ ### Step 2: Update CSS Module Imports
88
+
89
+ #### For each CSS module import:
90
+
91
+ ```js
92
+ // Find imports like this:
93
+ import styles from './styles.module.css';
94
+
95
+ // Replace with named imports:
96
+ import { className1, className2 } from './styles.module.css';
97
+ ```
98
+
99
+ #### Update TypeScript definitions:
100
+
101
+ ```typescript
102
+ // Update your CSS module type definitions
103
+ declare module '*.module.css' {
104
+ // With namedExport: true, css-loader generates individual named exports
105
+ // TypeScript can't know the exact names at compile time, so we declare
106
+ // a module with any number of string exports
107
+ const classes: { readonly [key: string]: string };
108
+ export = classes;
109
+ // Note: This allows 'import * as styles' but not 'import styles from'
110
+ // because css-loader with namedExport: true doesn't generate a default export
111
+ }
112
+ ```
113
+
114
+ ### Step 3: Handle Kebab-Case Class Names
115
+
116
+ v9 automatically converts kebab-case to camelCase:
117
+
118
+ ```css
119
+ /* styles.module.css */
120
+ .my-button { }
121
+ .primary-color { }
122
+ ```
123
+
124
+ ```js
125
+ // v9 imports
126
+ import { myButton, primaryColor } from './styles.module.css';
127
+ ```
128
+
129
+ ### Step 4: Update Configuration Files
130
+
131
+ If you have `webpack_loader` in your configuration:
132
+
133
+ ```yml
134
+ # config/shakapacker.yml
135
+ # OLD:
136
+ # webpack_loader: 'babel'
137
+
138
+ # NEW:
139
+ javascript_transpiler: 'babel'
140
+ ```
141
+
142
+ ### Step 5: Run Tests
143
+
144
+ ```bash
145
+ # Run your test suite
146
+ npm test
147
+
148
+ # Build your application
149
+ bin/shakapacker
150
+
151
+ # Test in development
152
+ bin/shakapacker-dev-server
153
+ ```
154
+
155
+ ## Troubleshooting
156
+
157
+ ### CSS Classes Not Applying
158
+
159
+ - Ensure you're using named imports: `import { className } from '...'`
160
+ - Check camelCase conversion for kebab-case names
161
+ - Clear cache: `rm -rf tmp/cache && bin/shakapacker`
162
+
163
+ ### TypeScript Errors
164
+
165
+ Update your global type definitions as shown in Step 2.
166
+
167
+ ### Build Warnings
168
+
169
+ If you see warnings about CSS module exports, ensure you've updated all imports to use named exports or have properly configured the override.
170
+
171
+ ## Need Help?
172
+
173
+ - See [CSS Modules Export Mode documentation](./css-modules-export-mode.md) for detailed configuration options
174
+ - Check the [CHANGELOG](../CHANGELOG.md) for all changes
175
+ - File issues at [GitHub Issues](https://github.com/shakacode/shakapacker/issues)
176
+
177
+ ## Gradual Migration Strategy
178
+
179
+ If you have a large codebase and need to migrate gradually:
180
+
181
+ 1. Override the CSS configuration to keep v8 behavior (see [documentation](./css-modules-export-mode.md))
182
+ 2. Migrate files incrementally
183
+ 3. Remove the override once migration is complete
184
+
185
+ This allows you to upgrade to v9 immediately while taking time to update your CSS module imports.
@@ -2,24 +2,10 @@
2
2
 
3
3
  ENV["RAILS_ENV"] ||= "development"
4
4
  ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
5
+ ENV["APP_ROOT"] ||= File.expand_path("..", __dir__)
5
6
 
6
7
  require "bundler/setup"
7
- require "pathname"
8
8
  require "shakapacker"
9
+ require "shakapacker/runner"
9
10
 
10
- APP_ROOT = File.expand_path("..", __dir__)
11
- Dir.chdir(APP_ROOT) do
12
- config = Shakapacker::Configuration.new(
13
- root_path: Pathname.new(APP_ROOT),
14
- config_path: Pathname.new(File.join(APP_ROOT, "config/shakapacker.yml")),
15
- env: ENV["RAILS_ENV"] || ENV["NODE_ENV"] || "development"
16
- )
17
-
18
- if config.rspack?
19
- require "shakapacker/rspack_runner"
20
- Shakapacker::RspackRunner.run(ARGV)
21
- else
22
- require "shakapacker/webpack_runner"
23
- Shakapacker::WebpackRunner.run(ARGV)
24
- end
25
- end
11
+ Shakapacker::Runner.run(ARGV)
@@ -29,6 +29,10 @@ default: &default
29
29
  # Location for manifest.json, defaults to {public_output_path}/manifest.json if unset
30
30
  # manifest_path: public/packs/manifest.json
31
31
 
32
+ # Location for private server-side bundles (e.g., for SSR)
33
+ # These bundles are not served publicly, unlike public_output_path
34
+ # private_output_path: ssr-generated
35
+
32
36
  # Additional paths webpack should look up modules
33
37
  # ['app/assets', 'engine/foo/app/assets']
34
38
  additional_paths: []
@@ -36,11 +40,12 @@ default: &default
36
40
  # Reload manifest.json on all requests so we reload latest compiled packs
37
41
  cache_manifest: false
38
42
 
39
- # Select loader to use, available options are 'babel' (default), 'swc' or 'esbuild'
40
- webpack_loader: 'babel'
43
+ # Select JavaScript transpiler to use, available options are 'babel' (default), 'swc' or 'esbuild'
44
+ javascript_transpiler: 'babel'
41
45
 
42
- # Select bundler to use, available options are 'webpack' (default) or 'rspack'
43
- bundler: 'webpack'
46
+ # Select assets bundler to use
47
+ # Available options: 'webpack' (default) or 'rspack'
48
+ assets_bundler: 'webpack'
44
49
 
45
50
  # Raises an error if there is a mismatch in the shakapacker gem and npm package being used
46
51
  ensure_consistent_versioning: true
@@ -68,6 +68,13 @@ class Shakapacker::Configuration
68
68
  root_path.join(fetch(:public_root_path))
69
69
  end
70
70
 
71
+ def private_output_path
72
+ private_path = fetch(:private_output_path)
73
+ return nil unless private_path
74
+ validate_output_paths!
75
+ root_path.join(private_path)
76
+ end
77
+
71
78
  def public_output_path
72
79
  public_path.join(fetch(:public_output_path))
73
80
  end
@@ -88,18 +95,51 @@ class Shakapacker::Configuration
88
95
  fetch(:compiler_strategy)
89
96
  end
90
97
 
98
+ def assets_bundler
99
+ # Show deprecation warning if using old 'bundler' key
100
+ if data.has_key?(:bundler) && !data.has_key?(:assets_bundler)
101
+ $stderr.puts "⚠️ DEPRECATION WARNING: The 'bundler' configuration option is deprecated. Please use 'assets_bundler' instead to avoid confusion with Ruby's Bundler gem manager."
102
+ end
103
+ ENV["SHAKAPACKER_ASSETS_BUNDLER"] || fetch(:assets_bundler) || fetch(:bundler) || "webpack"
104
+ end
105
+
106
+ # Deprecated: Use assets_bundler instead
91
107
  def bundler
92
- fetch(:bundler) || "webpack"
108
+ assets_bundler
93
109
  end
94
110
 
95
111
  def rspack?
96
- bundler == "rspack"
112
+ assets_bundler == "rspack"
97
113
  end
98
114
 
99
115
  def webpack?
100
- bundler == "webpack"
116
+ assets_bundler == "webpack"
101
117
  end
102
118
 
119
+ def javascript_transpiler
120
+ # Show deprecation warning if using old 'webpack_loader' key
121
+ if data.has_key?(:webpack_loader) && !data.has_key?(:javascript_transpiler)
122
+ $stderr.puts "⚠️ DEPRECATION WARNING: The 'webpack_loader' configuration option is deprecated. Please use 'javascript_transpiler' instead as it better reflects its purpose of configuring JavaScript transpilation regardless of the bundler used."
123
+ end
124
+
125
+ # Use explicit config if set, otherwise default based on bundler
126
+ fetch(:javascript_transpiler) || fetch(:webpack_loader) || default_javascript_transpiler
127
+ end
128
+
129
+ # Deprecated: Use javascript_transpiler instead
130
+ def webpack_loader
131
+ javascript_transpiler
132
+ end
133
+
134
+ private
135
+
136
+ def default_javascript_transpiler
137
+ # RSpack has built-in SWC support, use it by default
138
+ rspack? ? "swc" : "babel"
139
+ end
140
+
141
+ public
142
+
103
143
  def fetch(key)
104
144
  data.fetch(key, defaults[key])
105
145
  end
@@ -116,6 +156,38 @@ class Shakapacker::Configuration
116
156
  end
117
157
 
118
158
  private
159
+ def validate_output_paths!
160
+ # Skip validation if already validated to avoid redundant checks
161
+ return if @validated_output_paths
162
+ @validated_output_paths = true
163
+
164
+ # Only validate when both paths are configured
165
+ return unless fetch(:private_output_path) && fetch(:public_output_path)
166
+
167
+ private_path_str, public_path_str = resolve_paths_for_comparison
168
+
169
+ if private_path_str == public_path_str
170
+ raise "Shakapacker configuration error: private_output_path and public_output_path must be different. " \
171
+ "Both paths resolve to '#{private_path_str}'. " \
172
+ "The private_output_path is for server-side bundles (e.g., SSR) that should not be served publicly."
173
+ end
174
+ end
175
+
176
+ def resolve_paths_for_comparison
177
+ private_full_path = root_path.join(fetch(:private_output_path))
178
+ public_full_path = root_path.join(fetch(:public_root_path), fetch(:public_output_path))
179
+
180
+ # Create directories if they don't exist (for testing)
181
+ private_full_path.mkpath unless private_full_path.exist?
182
+ public_full_path.mkpath unless public_full_path.exist?
183
+
184
+ # Use realpath to resolve symbolic links and relative paths
185
+ [private_full_path.realpath.to_s, public_full_path.realpath.to_s]
186
+ rescue Errno::ENOENT
187
+ # If paths don't exist yet, fall back to cleanpath for comparison
188
+ [private_full_path.cleanpath.to_s, public_full_path.cleanpath.to_s]
189
+ end
190
+
119
191
  def data
120
192
  @data ||= load
121
193
  end
@@ -7,6 +7,10 @@ require_relative "runner"
7
7
 
8
8
  module Shakapacker
9
9
  class DevServerRunner < Shakapacker::Runner
10
+ def self.run(argv)
11
+ new(argv).run
12
+ end
13
+
10
14
  def run
11
15
  load_config
12
16
  detect_unsupported_switches!
@@ -75,17 +79,16 @@ module Shakapacker
75
79
  env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --inspect-brk --trace-warnings"
76
80
  end
77
81
 
78
- # Add bundler-specific flags and config
79
- bundler = get_bundler_type
80
- if bundler == "webpack"
81
- cmd += ["--config", @webpack_config]
82
+ # Add config file
83
+ cmd += ["--config", @webpack_config]
84
+
85
+ # Add assets bundler-specific flags
86
+ if webpack?
82
87
  cmd += ["--progress", "--color"] if @pretty
83
88
  # Default behavior of webpack-dev-server is @hot = true
84
89
  cmd += ["--hot", "only"] if @hot == "only"
85
90
  cmd += ["--no-hot"] if !@hot
86
- elsif bundler == "rspack"
87
- # Only add config for rspack if it's not a rspack-specific command
88
- cmd += ["--config", @webpack_config]
91
+ elsif rspack?
89
92
  # Rspack supports --hot but not --no-hot or --progress/--color
90
93
  cmd += ["--hot"] if @hot && @hot != false
91
94
  end
@@ -98,9 +101,16 @@ module Shakapacker
98
101
  end
99
102
 
100
103
  def build_cmd
101
- bundler = get_bundler_type
102
- command = bundler == "rspack" ? "rspack" : "webpack"
104
+ command = @config.rspack? ? "rspack" : "webpack"
103
105
  package_json.manager.native_exec_command(command, ["serve"])
104
106
  end
107
+
108
+ def webpack?
109
+ @config.webpack?
110
+ end
111
+
112
+ def rspack?
113
+ @config.rspack?
114
+ end
105
115
  end
106
116
  end