shakapacker 9.0.0.beta.2 → 9.0.0.beta.4

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.
@@ -0,0 +1,228 @@
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. SWC is Now the Default JavaScript Transpiler
69
+
70
+ **What changed:** SWC replaces Babel as the default JavaScript transpiler. Babel is no longer included in peer dependencies.
71
+
72
+ **Why:** SWC is 20x faster than Babel while maintaining compatibility with most JavaScript and TypeScript code.
73
+
74
+ **Impact on existing projects:**
75
+ - Your project will continue using Babel if you already have babel packages in package.json
76
+ - To switch to SWC for better performance, see migration options below
77
+
78
+ **Impact on new projects:**
79
+ - New installations will use SWC by default
80
+ - Babel dependencies won't be installed unless explicitly configured
81
+
82
+ ### Migration Options
83
+
84
+ #### Option 1 (Recommended): Switch to SWC
85
+ ```yml
86
+ # config/shakapacker.yml
87
+ javascript_transpiler: 'swc'
88
+ ```
89
+ Then install SWC:
90
+ ```bash
91
+ npm install @swc/core swc-loader
92
+ ```
93
+
94
+ #### Option 2: Keep using Babel
95
+ ```yml
96
+ # config/shakapacker.yml
97
+ javascript_transpiler: 'babel'
98
+ ```
99
+ No other changes needed - your existing babel packages will continue to work.
100
+
101
+ #### Option 3: Use esbuild
102
+ ```yml
103
+ # config/shakapacker.yml
104
+ javascript_transpiler: 'esbuild'
105
+ ```
106
+ Then install esbuild:
107
+ ```bash
108
+ npm install esbuild esbuild-loader
109
+ ```
110
+
111
+ ### 4. Rspack Support Added
112
+
113
+ **New feature:** Shakapacker v9 adds support for Rspack as an alternative bundler to webpack.
114
+
115
+ ```yml
116
+ # config/shakapacker.yml
117
+ assets_bundler: 'rspack' # or 'webpack' (default)
118
+ ```
119
+
120
+ ## Migration Steps
121
+
122
+ ### Step 1: Update Dependencies
123
+
124
+ ```bash
125
+ npm update shakapacker@^9.0.0
126
+ # or
127
+ yarn upgrade shakapacker@^9.0.0
128
+ ```
129
+
130
+ ### Step 2: Update CSS Module Imports
131
+
132
+ #### For each CSS module import:
133
+
134
+ ```js
135
+ // Find imports like this:
136
+ import styles from './styles.module.css';
137
+
138
+ // Replace with named imports:
139
+ import { className1, className2 } from './styles.module.css';
140
+ ```
141
+
142
+ #### Update TypeScript definitions:
143
+
144
+ ```typescript
145
+ // Update your CSS module type definitions
146
+ declare module '*.module.css' {
147
+ // With namedExport: true, css-loader generates individual named exports
148
+ // TypeScript can't know the exact names at compile time, so we declare
149
+ // a module with any number of string exports
150
+ const classes: { readonly [key: string]: string };
151
+ export = classes;
152
+ // Note: This allows 'import * as styles' but not 'import styles from'
153
+ // because css-loader with namedExport: true doesn't generate a default export
154
+ }
155
+ ```
156
+
157
+ ### Step 3: Handle Kebab-Case Class Names
158
+
159
+ v9 automatically converts kebab-case to camelCase:
160
+
161
+ ```css
162
+ /* styles.module.css */
163
+ .my-button { }
164
+ .primary-color { }
165
+ ```
166
+
167
+ ```js
168
+ // v9 imports
169
+ import { myButton, primaryColor } from './styles.module.css';
170
+ ```
171
+
172
+ ### Step 4: Update Configuration Files
173
+
174
+ If you have `webpack_loader` in your configuration:
175
+
176
+ ```yml
177
+ # config/shakapacker.yml
178
+ # OLD:
179
+ # webpack_loader: 'babel'
180
+
181
+ # NEW:
182
+ javascript_transpiler: 'babel'
183
+ ```
184
+
185
+ ### Step 5: Run Tests
186
+
187
+ ```bash
188
+ # Run your test suite
189
+ npm test
190
+
191
+ # Build your application
192
+ bin/shakapacker
193
+
194
+ # Test in development
195
+ bin/shakapacker-dev-server
196
+ ```
197
+
198
+ ## Troubleshooting
199
+
200
+ ### CSS Classes Not Applying
201
+
202
+ - Ensure you're using named imports: `import { className } from '...'`
203
+ - Check camelCase conversion for kebab-case names
204
+ - Clear cache: `rm -rf tmp/cache && bin/shakapacker`
205
+
206
+ ### TypeScript Errors
207
+
208
+ Update your global type definitions as shown in Step 2.
209
+
210
+ ### Build Warnings
211
+
212
+ 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
+
214
+ ## Need Help?
215
+
216
+ - See [CSS Modules Export Mode documentation](./css-modules-export-mode.md) for detailed configuration options
217
+ - Check the [CHANGELOG](../CHANGELOG.md) for all changes
218
+ - File issues at [GitHub Issues](https://github.com/shakacode/shakapacker/issues)
219
+
220
+ ## Gradual Migration Strategy
221
+
222
+ If you have a large codebase and need to migrate gradually:
223
+
224
+ 1. Override the CSS configuration to keep v8 behavior (see [documentation](./css-modules-export-mode.md))
225
+ 2. Migrate files incrementally
226
+ 3. Remove the override once migration is complete
227
+
228
+ This allows you to upgrade to v9 immediately while taking time to update your CSS module imports.
@@ -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,8 +40,10 @@ 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 JavaScript transpiler to use, available options are 'babel' (default), 'swc' or 'esbuild'
40
- javascript_transpiler: 'babel'
43
+ # Select JavaScript transpiler to use
44
+ # Available options: 'swc' (default, 20x faster), 'babel', or 'esbuild'
45
+ # Note: When using rspack, swc is used automatically regardless of this setting
46
+ javascript_transpiler: 'swc'
41
47
 
42
48
  # Select assets bundler to use
43
49
  # Available options: 'webpack' (default) or 'rspack'
@@ -26,5 +26,13 @@
26
26
  "@babel/preset-env": "^7.16.11",
27
27
  "@babel/runtime": "^7.17.9",
28
28
  "babel-loader": "^8.2.4 || ^9.0.0 || ^10.0.0"
29
+ },
30
+ "swc": {
31
+ "@swc/core": "^1.3.0",
32
+ "swc-loader": "^0.2.0"
33
+ },
34
+ "esbuild": {
35
+ "esbuild": "^0.24.0",
36
+ "esbuild-loader": "^4.0.0"
29
37
  }
30
38
  }
@@ -2,25 +2,56 @@ require "shakapacker/utils/misc"
2
2
  require "shakapacker/utils/manager"
3
3
  require "shakapacker/utils/version_syntax_converter"
4
4
  require "package_json"
5
+ require "yaml"
6
+ require "json"
5
7
 
6
8
  # Install Shakapacker
7
9
 
8
10
  force_option = ENV["FORCE"] ? { force: true } : {}
9
11
 
10
- copy_file "#{__dir__}/config/shakapacker.yml", "config/shakapacker.yml", force_option
12
+ # Initialize variables for use throughout the template
13
+ # Using instance variable to avoid method definition issues in Rails templates
14
+ @package_json ||= PackageJson.new
15
+ install_dir = File.expand_path(File.dirname(__FILE__))
16
+
17
+ # Installation strategy:
18
+ # - USE_BABEL_PACKAGES installs both babel AND swc for compatibility
19
+ # - Otherwise install only the specified transpiler
20
+ if ENV["USE_BABEL_PACKAGES"] == "true" || ENV["USE_BABEL_PACKAGES"] == "1"
21
+ @transpiler_to_install = "babel"
22
+ say "📦 Installing Babel packages (USE_BABEL_PACKAGES is set)", :yellow
23
+ say "✨ Also installing SWC packages for default config compatibility", :green
24
+ elsif ENV["JAVASCRIPT_TRANSPILER"]
25
+ @transpiler_to_install = ENV["JAVASCRIPT_TRANSPILER"]
26
+ say "📦 Installing #{@transpiler_to_install} packages", :blue
27
+ else
28
+ # Default to swc (matches the default in shakapacker.yml)
29
+ @transpiler_to_install = "swc"
30
+ say "✨ Installing SWC packages (20x faster than Babel)", :green
31
+ end
32
+
33
+ # Copy config file
34
+ copy_file "#{install_dir}/config/shakapacker.yml", "config/shakapacker.yml", force_option
35
+
36
+ # Update config if USE_BABEL_PACKAGES is set to ensure babel is used at runtime
37
+ if @transpiler_to_install == "babel" && !ENV["JAVASCRIPT_TRANSPILER"]
38
+ # When USE_BABEL_PACKAGES is set, update the config to use babel
39
+ gsub_file "config/shakapacker.yml", "javascript_transpiler: 'swc'", "javascript_transpiler: 'babel'"
40
+ say " 📝 Updated config/shakapacker.yml to use Babel transpiler", :green
41
+ end
11
42
 
12
43
  say "Copying webpack core config"
13
- directory "#{__dir__}/config/webpack", "config/webpack", force_option
44
+ directory "#{install_dir}/config/webpack", "config/webpack", force_option
14
45
 
15
46
  if Dir.exist?(Shakapacker.config.source_path)
16
47
  say "The packs app source directory already exists"
17
48
  else
18
49
  say "Creating packs app source directory"
19
50
  empty_directory "app/javascript/packs"
20
- copy_file "#{__dir__}/application.js", "app/javascript/packs/application.js"
51
+ copy_file "#{install_dir}/application.js", "app/javascript/packs/application.js"
21
52
  end
22
53
 
23
- apply "#{__dir__}/binstubs.rb"
54
+ apply "#{install_dir}/binstubs.rb"
24
55
 
25
56
  git_ignore_path = Rails.root.join(".gitignore")
26
57
  if File.exist?(git_ignore_path)
@@ -43,17 +74,8 @@ else
43
74
  say %( Add <%= javascript_pack_tag "application" %> within the <head> tag in your custom layout.)
44
75
  end
45
76
 
46
- def package_json
47
- @package_json ||= PackageJson.new
48
- end
49
-
50
77
  # setup the package manager with default values
51
- package_json.merge! do |pj|
52
- babel = pj.fetch("babel", {})
53
-
54
- babel["presets"] ||= []
55
- babel["presets"].push("./node_modules/shakapacker/package/babel/preset.js")
56
-
78
+ @package_json.merge! do |pj|
57
79
  package_manager = pj.fetch("packageManager") do
58
80
  "#{Shakapacker::Utils::Manager.guess_binary}@#{Shakapacker::Utils::Manager.guess_version}"
59
81
  end
@@ -62,7 +84,6 @@ package_json.merge! do |pj|
62
84
  "name" => "app",
63
85
  "private" => true,
64
86
  "version" => "0.1.0",
65
- "babel" => babel,
66
87
  "browserslist" => [
67
88
  "defaults"
68
89
  ],
@@ -74,7 +95,7 @@ Shakapacker::Utils::Manager.error_unless_package_manager_is_obvious!
74
95
 
75
96
  # Ensure there is `system!("bin/yarn")` command in `./bin/setup` file
76
97
  if (setup_path = Rails.root.join("bin/setup")).exist?
77
- native_install_command = package_json.manager.native_install_command.join(" ")
98
+ native_install_command = @package_json.manager.native_install_command.join(" ")
78
99
 
79
100
  say "Run #{native_install_command} during bin/setup"
80
101
 
@@ -103,42 +124,56 @@ if (setup_path = Rails.root.join("bin/setup")).exist?
103
124
  end
104
125
  end
105
126
 
106
- def add_dependencies(dependencies, type)
107
- package_json.manager.add!(dependencies, type: type)
108
- rescue PackageJson::Error
109
- say "Shakapacker installation failed 😭 See above for details.", :red
110
- exit 1
111
- end
112
-
113
- def fetch_peer_dependencies
114
- PackageJson.read("#{__dir__}").fetch(ENV["SHAKAPACKER_BUNDLER"] || "webpack")
115
- end
116
-
117
- def fetch_common_dependencies
118
- ENV["SKIP_COMMON_LOADERS"] ? {} : PackageJson.read("#{__dir__}").fetch("common")
119
- end
120
-
121
- def fetch_babel_dependencies
122
- ENV["USE_BABEL_PACKAGES"] ? PackageJson.read("#{__dir__}").fetch("babel") : {}
123
- end
124
-
125
127
  Dir.chdir(Rails.root) do
126
128
  npm_version = Shakapacker::Utils::VersionSyntaxConverter.new.rubygem_to_npm(Shakapacker::VERSION)
127
129
  say "Installing shakapacker@#{npm_version}"
128
- add_dependencies(["shakapacker@#{npm_version}"], :production)
129
-
130
- package_json.merge! do |pj|
131
- {
132
- "dependencies" => pj["dependencies"].merge({
133
- # TODO: workaround for test suite - long-run need to actually account for diff pkg manager behaviour
134
- "shakapacker" => pj["dependencies"]["shakapacker"].delete_prefix("^")
135
- })
136
- }
130
+ begin
131
+ @package_json.manager.add!(["shakapacker@#{npm_version}"], type: :production)
132
+ rescue PackageJson::Error
133
+ say "Shakapacker installation failed 😭 See above for details.", :red
134
+ exit 1
137
135
  end
138
136
 
139
- peers = fetch_peer_dependencies
140
- peers = peers.merge(fetch_common_dependencies)
141
- peers = peers.merge(fetch_babel_dependencies)
137
+ @package_json.merge! do |pj|
138
+ if pj["dependencies"] && pj["dependencies"]["shakapacker"]
139
+ {
140
+ "dependencies" => pj["dependencies"].merge({
141
+ # TODO: workaround for test suite - long-run need to actually account for diff pkg manager behaviour
142
+ "shakapacker" => pj["dependencies"]["shakapacker"].delete_prefix("^")
143
+ })
144
+ }
145
+ else
146
+ pj
147
+ end
148
+ end
149
+
150
+ # Inline fetch_peer_dependencies and fetch_common_dependencies
151
+ peers = PackageJson.read(install_dir).fetch(ENV["SHAKAPACKER_BUNDLER"] || "webpack")
152
+ common_deps = ENV["SKIP_COMMON_LOADERS"] ? {} : PackageJson.read(install_dir).fetch("common")
153
+ peers = peers.merge(common_deps)
154
+
155
+ # Add transpiler-specific dependencies based on detected/configured transpiler
156
+ # Inline the logic here since methods can't be called before they're defined in Rails templates
157
+
158
+ # Install transpiler-specific dependencies
159
+ # When USE_BABEL_PACKAGES is set, install both babel AND swc
160
+ # This ensures backward compatibility while supporting the default config
161
+ if @transpiler_to_install == "babel"
162
+ # Install babel packages
163
+ babel_deps = PackageJson.read(install_dir).fetch("babel")
164
+ peers = peers.merge(babel_deps)
165
+
166
+ # Also install SWC since that's what the default config uses
167
+ # This ensures the runtime works regardless of config
168
+ swc_deps = PackageJson.read(install_dir).fetch("swc")
169
+ peers = peers.merge(swc_deps)
170
+ elsif @transpiler_to_install == "swc"
171
+ swc_deps = PackageJson.read(install_dir).fetch("swc")
172
+ peers = peers.merge(swc_deps)
173
+ elsif @transpiler_to_install == "esbuild"
174
+ esbuild_deps = PackageJson.read(install_dir).fetch("esbuild")
175
+ peers = peers.merge(esbuild_deps)
176
+ end
142
177
 
143
178
  dev_dependency_packages = ["webpack-dev-server"]
144
179
 
@@ -146,8 +181,15 @@ Dir.chdir(Rails.root) do
146
181
  dev_dependencies_to_add = []
147
182
 
148
183
  peers.each do |(package, version)|
149
- major_version = version.split("||").last.match(/(\d+)/)[1]
150
- entry = "#{package}@#{major_version}"
184
+ # Handle versions like "^1.3.0" or ">= 4 || 5"
185
+ if version.start_with?("^", "~") || version.match?(/^\d+\.\d+/)
186
+ # Already has proper version format, use as-is
187
+ entry = "#{package}@#{version}"
188
+ else
189
+ # Extract major version from complex version strings like ">= 4 || 5"
190
+ major_version = version.split("||").last.match(/(\d+)/)[1]
191
+ entry = "#{package}@#{major_version}"
192
+ end
151
193
 
152
194
  if dev_dependency_packages.include? package
153
195
  dev_dependencies_to_add << entry
@@ -157,8 +199,36 @@ Dir.chdir(Rails.root) do
157
199
  end
158
200
 
159
201
  say "Adding shakapacker peerDependencies"
160
- add_dependencies(dependencies_to_add, :production)
202
+ begin
203
+ @package_json.manager.add!(dependencies_to_add, type: :production)
204
+ rescue PackageJson::Error
205
+ say "Shakapacker installation failed 😭 See above for details.", :red
206
+ exit 1
207
+ end
161
208
 
162
209
  say "Installing webpack-dev-server for live reloading as a development dependency"
163
- add_dependencies(dev_dependencies_to_add, :dev)
210
+ begin
211
+ @package_json.manager.add!(dev_dependencies_to_add, type: :dev)
212
+ rescue PackageJson::Error
213
+ say "Shakapacker installation failed 😭 See above for details.", :red
214
+ exit 1
215
+ end
216
+
217
+ # Configure babel preset in package.json if babel is being used
218
+ if @transpiler_to_install == "babel"
219
+ @package_json.merge! do |pj|
220
+ babel = pj.fetch("babel", {})
221
+ babel["presets"] ||= []
222
+ unless babel["presets"].include?("./node_modules/shakapacker/package/babel/preset.js")
223
+ babel["presets"].push("./node_modules/shakapacker/package/babel/preset.js")
224
+ end
225
+ { "babel" => babel }
226
+ end
227
+ end
228
+ end
229
+
230
+ # Helper methods defined at the end (Rails template convention)
231
+
232
+ def package_json
233
+ @package_json
164
234
  end
@@ -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
@@ -149,6 +156,38 @@ class Shakapacker::Configuration
149
156
  end
150
157
 
151
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
+
152
191
  def data
153
192
  @data ||= load
154
193
  end
@@ -1,4 +1,4 @@
1
1
  module Shakapacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "9.0.0.beta.2".freeze
3
+ VERSION = "9.0.0.beta.4".freeze
4
4
  end
data/package/config.js CHANGED
@@ -59,8 +59,8 @@ if (process.env.SHAKAPACKER_ASSETS_BUNDLER) {
59
59
  }
60
60
 
61
61
  // Define clear defaults
62
- const DEFAULT_JAVASCRIPT_TRANSPILER =
63
- config.assets_bundler === "rspack" ? "swc" : "babel"
62
+ // SWC is now the default transpiler for both webpack and rspack
63
+ const DEFAULT_JAVASCRIPT_TRANSPILER = "swc"
64
64
 
65
65
  // Backward compatibility: Add webpack_loader property that maps to javascript_transpiler
66
66
  // Show deprecation warning if webpack_loader is used
data/package/index.d.ts CHANGED
@@ -9,6 +9,7 @@ declare module "shakapacker" {
9
9
  css_extract_ignore_order_warnings: boolean
10
10
  public_root_path: string
11
11
  public_output_path: string
12
+ private_output_path?: string
12
13
  cache_path: string
13
14
  webpack_compile_output: boolean
14
15
  shakapacker_precompile: boolean
@@ -23,6 +24,14 @@ declare module "shakapacker" {
23
24
  publicPath: string
24
25
  publicPathWithoutCDN: string
25
26
  manifestPath: string
27
+ manifest_path?: string
28
+ assets_bundler?: string
29
+ dev_server?: DevServerConfig
30
+ integrity?: {
31
+ enabled: boolean
32
+ cross_origin: string
33
+ hash_functions?: string[]
34
+ }
26
35
  }
27
36
 
28
37
  export interface Env {
@@ -60,6 +69,8 @@ declare module "shakapacker" {
60
69
  ipc?: boolean | string
61
70
  magic_html?: boolean
62
71
  live_reload?: boolean
72
+ inline_css?: boolean
73
+ env_prefix?: string
63
74
  open?:
64
75
  | boolean
65
76
  | string
@@ -136,4 +147,4 @@ declare module "shakapacker/package/babel/preset.js" {
136
147
  ) => TransformOptions & RequiredTransformOptions
137
148
 
138
149
  export = defaultConfigFunc
139
- }
150
+ }
@@ -12,6 +12,8 @@ debug("Adding JavaScript rule with builtin:swc-loader")
12
12
  rules.push({
13
13
  test: /\.(js|jsx|mjs)$/,
14
14
  exclude: /node_modules/,
15
+ // The 'type' field is required for Rspack to properly handle JavaScript modules
16
+ // when using builtin loaders. It ensures correct module parsing and transformation.
15
17
  type: "javascript/auto",
16
18
  use: [
17
19
  {
@@ -38,6 +40,8 @@ debug("Adding TypeScript rule with builtin:swc-loader")
38
40
  rules.push({
39
41
  test: /\.(ts|tsx)$/,
40
42
  exclude: /node_modules/,
43
+ // The 'type' field is required for Rspack to properly handle TypeScript modules
44
+ // when using builtin loaders. It ensures correct module parsing and transformation.
41
45
  type: "javascript/auto",
42
46
  use: [
43
47
  {
@@ -3,6 +3,7 @@ const { canProcess, moduleExists } = require("./helpers")
3
3
  const { requireOrError } = require("./requireOrError")
4
4
  const config = require("../config")
5
5
  const inliningCss = require("./inliningCss")
6
+ const { validateCssModulesConfig } = require("./validateCssModulesConfig")
6
7
 
7
8
  const getStyleRule = (test, preprocessors = []) => {
8
9
  if (moduleExists("css-loader")) {
@@ -19,17 +20,25 @@ const getStyleRule = (test, preprocessors = []) => {
19
20
  ? requireOrError("@rspack/core").CssExtractRspackPlugin.loader
20
21
  : requireOrError("mini-css-extract-plugin").loader
21
22
 
23
+ const cssLoaderOptions = {
24
+ sourceMap: true,
25
+ importLoaders: 2,
26
+ modules: {
27
+ auto: true,
28
+ // v9 defaults: named exports with camelCase conversion
29
+ namedExport: true,
30
+ exportLocalsConvention: "camelCase"
31
+ }
32
+ }
33
+
34
+ // Validate CSS modules configuration
35
+ validateCssModulesConfig(cssLoaderOptions)
36
+
22
37
  const use = [
23
38
  inliningCss ? "style-loader" : extractionPlugin,
24
39
  {
25
40
  loader: require.resolve("css-loader"),
26
- options: {
27
- sourceMap: true,
28
- importLoaders: 2,
29
- modules: {
30
- auto: true
31
- }
32
- }
41
+ options: cssLoaderOptions
33
42
  },
34
43
  tryPostcss(),
35
44
  ...preprocessors