shakapacker 9.0.0.beta.2 → 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.
@@ -1,26 +1,98 @@
1
1
  # CSS Modules Export Mode
2
2
 
3
- Most React guides and tutorials expect to import CSS Modules using a **default export object**:
3
+ ## Version 9.x (Current Default Behavior)
4
+
5
+ Starting with Shakapacker v9, CSS Modules are configured with **named exports** (`namedExport: true`) by default to align with Next.js and modern tooling standards.
6
+
7
+ ### JavaScript Usage
8
+
9
+ In pure JavaScript projects, you can use true named imports:
10
+
11
+ ```js
12
+ // v9 - named exports in JavaScript
13
+ import { bright, container } from './Foo.module.css';
14
+ <button className={bright} />
15
+ ```
16
+
17
+ ### TypeScript Usage
18
+
19
+ TypeScript cannot statically analyze CSS files to determine the exact export names at compile time. When css-loader generates individual named exports dynamically from your CSS classes, TypeScript doesn't know what those exports will be. Therefore, you must use namespace imports:
20
+
21
+ ```typescript
22
+ // v9 - namespace import required for TypeScript
23
+ import * as styles from './Foo.module.css';
24
+ <button className={styles.bright} />
25
+ ```
26
+
27
+ **Why namespace imports?** While webpack's css-loader generates true named exports at runtime (with `namedExport: true`), TypeScript's type system cannot determine these dynamic exports during compilation. The namespace import pattern allows TypeScript to treat the import as an object with string keys, bypassing the need for static export validation while still benefiting from the runtime optimizations of named exports.
28
+
29
+ ### Benefits of v9 Configuration
30
+ - Eliminates certain webpack warnings
31
+ - Provides better tree-shaking potential
32
+ - Aligns with modern JavaScript module standards
33
+ - Automatically converts kebab-case to camelCase (`my-button` → `myButton`)
34
+
35
+ ## Version 8.x and Earlier Behavior
36
+
37
+ In Shakapacker v8 and earlier, the default behavior was to use a **default export object**:
4
38
 
5
39
  ```js
40
+ // v8 and earlier default
6
41
  import styles from './Foo.module.css';
7
42
  <button className={styles.bright} />
8
43
  ```
9
44
 
10
- However, depending on configuration, `css-loader` may instead emit **named exports**:
45
+ ---
46
+
47
+ ## Migrating from v8 to v9
48
+
49
+ When upgrading to Shakapacker v9, you'll need to update your CSS Module imports from default exports to named exports.
50
+
51
+ ### Migration Options
11
52
 
53
+ #### Option 1: Update Your Code (Recommended)
54
+
55
+ **For JavaScript projects:**
12
56
  ```js
13
- import { bright } from './Foo.module.css';
14
- <button className={bright} />
57
+ // Before (v8)
58
+ import styles from './Component.module.css';
59
+ <div className={styles.container}>
60
+ <button className={styles.button}>Click me</button>
61
+ </div>
62
+
63
+ // After (v9) - JavaScript
64
+ import { container, button } from './Component.module.css';
65
+ <div className={container}>
66
+ <button className={button}>Click me</button>
67
+ </div>
68
+ ```
69
+
70
+ **For TypeScript projects:**
71
+ ```typescript
72
+ // Before (v8)
73
+ import styles from './Component.module.css';
74
+ <div className={styles.container}>
75
+ <button className={styles.button}>Click me</button>
76
+ </div>
77
+
78
+ // After (v9) - TypeScript
79
+ import * as styles from './Component.module.css';
80
+ <div className={styles.container}>
81
+ <button className={styles.button}>Click me</button>
82
+ </div>
15
83
  ```
16
84
 
17
- By default, Shakapacker currently leaves `css-loader`'s `modules.namedExport` option unset, which leads to **named exports** being used in many cases. This can surprise developers expecting the `import styles ...` pattern.
85
+ Note: TypeScript projects only need to change from default import to namespace import (`* as styles`), the property access remains the same.
86
+
87
+ #### Option 2: Keep v8 Behavior
88
+
89
+ If you prefer to keep the v8 default export behavior during migration, you can override the configuration (see below).
18
90
 
19
91
  ---
20
92
 
21
- ## How to Configure Shakapacker for Default Exports
93
+ ## Reverting to Default Exports (v8 Behavior)
22
94
 
23
- To force the more familiar `import styles ...` behavior (i.e. `namedExport: false`), update your webpack configuration as follows.
95
+ To use the v8-style default exports instead of v9's named exports:
24
96
 
25
97
  ### Option 1: Update `config/webpack/commonWebpackConfig.js` (Recommended)
26
98
 
@@ -32,7 +104,7 @@ const { generateWebpackConfig, merge } = require('shakapacker');
32
104
 
33
105
  const baseClientWebpackConfig = generateWebpackConfig();
34
106
 
35
- // Override CSS Modules configuration to use default exports instead of named exports
107
+ // Override CSS Modules configuration to use v8-style default exports
36
108
  const overrideCssModulesConfig = (config) => {
37
109
  // Find the CSS rule in the module rules
38
110
  const cssRule = config.module.rules.find(rule =>
@@ -45,7 +117,7 @@ const overrideCssModulesConfig = (config) => {
45
117
  );
46
118
 
47
119
  if (cssLoaderUse && cssLoaderUse.options && cssLoaderUse.options.modules) {
48
- // Set namedExport to false for default export behavior
120
+ // Override v9 default to use v8-style default exports
49
121
  cssLoaderUse.options.modules.namedExport = false;
50
122
  cssLoaderUse.options.modules.exportLocalsConvention = 'asIs';
51
123
  }
@@ -77,14 +149,14 @@ If you prefer using a separate environment file:
77
149
  const { environment } = require('@shakacode/shakapacker');
78
150
  const getStyleRule = require('@shakacode/shakapacker/package/utils/getStyleRule');
79
151
 
80
- // CSS Modules rule for *.module.css with default export enabled
152
+ // CSS Modules rule for *.module.css with v8-style default export
81
153
  const cssModulesRule = getStyleRule(/\.module\.css$/i, [], {
82
154
  sourceMap: true,
83
155
  importLoaders: 2,
84
156
  modules: {
85
157
  auto: true,
86
- namedExport: false, // <-- key: enable default export object
87
- exportLocalsConvention: 'asIs' // keep your class names as-is
158
+ namedExport: false, // <-- override v9 default
159
+ exportLocalsConvention: 'asIs' // keep class names as-is instead of camelCase
88
160
  }
89
161
  });
90
162
 
@@ -140,110 +212,157 @@ const overrideCssModulesConfig = (config) => {
140
212
 
141
213
  ---
142
214
 
143
- ## Verifying the Configuration
215
+ ## Detailed Migration Guide
144
216
 
145
- ### 1. Rebuild Your Packs
217
+ ### Migrating from v8 (Default Exports) to v9 (Named Exports)
146
218
 
147
- After making the configuration changes, rebuild your webpack bundles:
219
+ #### 1. Update Import Statements
148
220
 
149
- ```bash
150
- # For development
151
- NODE_ENV=development bin/shakapacker
221
+ ```js
222
+ // Old (v8 - default export)
223
+ import styles from './Component.module.css';
152
224
 
153
- # Or with the dev server
154
- bin/shakapacker-dev-server
225
+ // New (v9 - named exports)
226
+ import { bright, container, button } from './Component.module.css';
155
227
  ```
156
228
 
157
- ### 2. Test in Your React Component
229
+ #### 2. Update Class References
158
230
 
159
- Update your component to use default imports:
231
+ ```js
232
+ // Old (v8)
233
+ <div className={styles.container}>
234
+ <button className={styles.button}>Click me</button>
235
+ <span className={styles.bright}>Highlighted text</span>
236
+ </div>
237
+
238
+ // New (v9)
239
+ <div className={container}>
240
+ <button className={button}>Click me</button>
241
+ <span className={bright}>Highlighted text</span>
242
+ </div>
243
+ ```
244
+
245
+ #### 3. Handle Kebab-Case Class Names
246
+
247
+ With v9's `exportLocalsConvention: 'camelCase'`, kebab-case class names are automatically converted:
248
+
249
+ ```css
250
+ /* styles.module.css */
251
+ .my-button { ... }
252
+ .primary-color { ... }
253
+ ```
160
254
 
161
255
  ```js
162
- // Before (named exports)
163
- import { bright } from './Foo.module.css';
256
+ // v9 imports (camelCase conversion)
257
+ import { myButton, primaryColor } from './styles.module.css';
164
258
 
165
- // After (default export)
166
- import styles from './Foo.module.css';
167
- console.log(styles); // { bright: 'Foo_bright__hash' }
259
+ // Use the camelCase versions in your components
260
+ <button className={myButton} />
168
261
  ```
169
262
 
170
- ### 3. Debug Webpack Configuration (Optional)
263
+ #### 4. Using a Codemod for Large Codebases
171
264
 
172
- To inspect the final webpack configuration:
265
+ For large codebases, you can create a codemod to automate the migration:
173
266
 
174
- ```bash
175
- NODE_ENV=development bin/shakapacker --profile --json > /tmp/webpack-stats.json
267
+ ```js
268
+ // css-modules-v9-migration.js
269
+ module.exports = function(fileInfo, api) {
270
+ const j = api.jscodeshift;
271
+ const root = j(fileInfo.source);
272
+
273
+ // Find CSS module imports
274
+ root.find(j.ImportDeclaration, {
275
+ source: { value: value => value.endsWith('.module.css') }
276
+ }).forEach(path => {
277
+ const defaultSpecifier = path.node.specifiers.find(
278
+ spec => spec.type === 'ImportDefaultSpecifier'
279
+ );
280
+
281
+ if (defaultSpecifier) {
282
+ // Convert default import to namespace import for analysis
283
+ // Then extract used properties and convert to named imports
284
+ // ... codemod implementation
285
+ }
286
+ });
287
+
288
+ return root.toSource();
289
+ };
176
290
  ```
177
291
 
178
- Then search for `css-loader` options in the generated JSON file.
292
+ Run with:
293
+ ```bash
294
+ npx jscodeshift -t css-modules-v9-migration.js src/
295
+ ```
179
296
 
180
297
  ---
181
298
 
182
- ## Benefits of Default Export Approach
299
+ ## Version Comparison
183
300
 
184
- 1. **Better Developer Experience**: Matches most React tutorials and documentation
185
- 2. **IDE Support**: Better autocomplete and IntelliSense for CSS class names
186
- 3. **Type Safety**: Easier to add TypeScript definitions for CSS modules
187
- 4. **Consistency**: Aligns with common React ecosystem practices
301
+ | Feature | v8 (and earlier) | v9 |
302
+ |---------|-----------------|----|
303
+ | Default behavior | Default export object | Named exports |
304
+ | Import syntax | `import styles from '...'` | `import { className } from '...'` |
305
+ | Class reference | `styles.className` | `className` |
306
+ | Export convention | `asIs` (no transformation) | `camelCase` |
307
+ | TypeScript warnings | May show warnings | No warnings |
308
+ | Tree-shaking | Limited | Optimized |
188
309
 
189
310
  ---
190
311
 
191
- ## Migration Guide
312
+ ## Benefits of Named Exports (v9 Default)
192
313
 
193
- If you're migrating from named exports to default exports:
314
+ 1. **No Build Warnings**: Eliminates webpack/TypeScript warnings about missing exports
315
+ 2. **Better Tree-Shaking**: Unused CSS class exports can be eliminated
316
+ 3. **Explicit Dependencies**: Clear about which CSS classes are being used
317
+ 4. **Modern Standards**: Aligns with ES modules and modern tooling
318
+ 5. **Type Safety**: TypeScript can validate individual class imports
194
319
 
195
- ### 1. Update Import Statements
320
+ ## Benefits of Default Exports (v8 Behavior)
196
321
 
197
- ```js
198
- // Old (named exports)
199
- import { bright, container, button } from './Component.module.css';
322
+ 1. **Familiar Pattern**: Matches most existing React tutorials
323
+ 2. **Namespace Import**: All classes available under one import
324
+ 3. **Less Verbose**: Single import for all classes
325
+ 4. **Legacy Compatibility**: Works with existing codebases
200
326
 
201
- // New (default export)
202
- import styles from './Component.module.css';
203
- ```
327
+ ---
204
328
 
205
- ### 2. Update Class References
329
+ ## Verifying the Configuration
206
330
 
207
- ```js
208
- // Old
209
- <div className={container}>
210
- <button className={button}>Click me</button>
211
- <span className={bright}>Highlighted text</span>
212
- </div>
331
+ ### 1. Rebuild Your Packs
213
332
 
214
- // New
215
- <div className={styles.container}>
216
- <button className={styles.button}>Click me</button>
217
- <span className={styles.bright}>Highlighted text</span>
218
- </div>
333
+ After making any configuration changes, rebuild your webpack bundles:
334
+
335
+ ```bash
336
+ # For development
337
+ NODE_ENV=development bin/shakapacker
338
+
339
+ # Or with the dev server
340
+ bin/shakapacker-dev-server
219
341
  ```
220
342
 
221
- ### 3. Consider Using a Codemod
343
+ ### 2. Test in Your React Component
222
344
 
223
- For large codebases, consider writing a codemod to automate the migration:
345
+ Verify your imports work correctly:
224
346
 
225
- ```bash
226
- # Example using jscodeshift (pseudocode)
227
- npx jscodeshift -t css-modules-migration.js src/
228
- ```
347
+ ```js
348
+ // v9 default (named exports)
349
+ import { bright } from './Foo.module.css';
350
+ console.log(bright); // 'Foo_bright__hash'
229
351
 
230
- ---
352
+ // Or if using v8 configuration (default export)
353
+ import styles from './Foo.module.css';
354
+ console.log(styles); // { bright: 'Foo_bright__hash' }
355
+ ```
231
356
 
232
- ## Future Shakapacker Configuration
357
+ ### 3. Debug Webpack Configuration (Optional)
233
358
 
234
- In future versions of Shakapacker, this configuration may be exposed via `config/shakapacker.yml`:
359
+ To inspect the final webpack configuration:
235
360
 
236
- ```yml
237
- # Future configuration (not yet implemented)
238
- css_modules:
239
- # true -> named exports (import { bright } ...)
240
- # false -> default export (import styles ...)
241
- named_export: false
361
+ ```bash
362
+ NODE_ENV=development bin/shakapacker --profile --json > /tmp/webpack-stats.json
242
363
  ```
243
364
 
244
- - **Current behavior:** Uses named exports when unset
245
- - **Future behavior:** New app templates will default to `false`
246
- - **Next major release:** The default will change to `false` when unset
365
+ Then search for `css-loader` options in the generated JSON file.
247
366
 
248
367
  ---
249
368
 
@@ -251,15 +370,26 @@ css_modules:
251
370
 
252
371
  ### CSS Classes Not Applying
253
372
 
254
- If your CSS classes aren't applying after the change:
373
+ If your CSS classes aren't applying after the upgrade:
255
374
 
256
- 1. **Check import syntax**: Ensure you're using `import styles from ...`
257
- 2. **Verify class names**: Use `console.log(styles)` to see available classes
258
- 3. **Rebuild webpack**: Clear cache and rebuild: `rm -rf tmp/cache && bin/shakapacker`
375
+ 1. **Check import syntax**: Ensure you're using the correct import style for your configuration
376
+ 2. **Verify class names**: Use `console.log` to see available classes
377
+ 3. **Check camelCase conversion**: Kebab-case names are converted to camelCase in v9
378
+ 4. **Rebuild webpack**: Clear cache and rebuild: `rm -rf tmp/cache && bin/shakapacker`
259
379
 
260
380
  ### TypeScript Support
261
381
 
262
- For TypeScript projects, create type definitions for your CSS modules:
382
+ #### For v9 (Named Exports)
383
+
384
+ ```typescript
385
+ // src/types/css-modules.d.ts
386
+ declare module '*.module.css' {
387
+ const classes: { [key: string]: string };
388
+ export = classes;
389
+ }
390
+ ```
391
+
392
+ #### For v8 Behavior (Default Export)
263
393
 
264
394
  ```typescript
265
395
  // src/types/css-modules.d.ts
@@ -281,8 +411,8 @@ The configuration changes should not impact build performance significantly. If
281
411
 
282
412
  ## Summary
283
413
 
284
- - **Current default**: Named exports (`import { bright } ...`)
285
- - **Recommended for DX**: Default export (`import styles ...`)
286
- - **Implementation**: Override CSS loader configuration in `commonWebpackConfig.js`
287
- - **Migration**: Update imports and class references systematically
288
- - **Future**: Shakapacker will provide native configuration options
414
+ - **v9 default**: Named exports with camelCase conversion
415
+ - **v8 default**: Default export object with no conversion
416
+ - **Migration path**: Update imports or override configuration
417
+ - **Benefits of v9**: No warnings, better tree-shaking, explicit dependencies
418
+ - **Keeping v8 behavior**: Override css-loader configuration as shown above
data/docs/deployment.md CHANGED
@@ -88,7 +88,16 @@ Now, you can set `brotli_static on;` in your nginx site config, as per the confi
88
88
 
89
89
  ## CDN
90
90
 
91
- If you are using a CDN setup, Shakapacker does NOT use the `ASSET_HOST` environment variable to prefix URLs for assets during bundle compilation. You must use the `SHAKAPACKER_ASSET_HOST` environment variable instead (`WEBPACKER_ASSET_HOST` if you're using any version of Webpacker or Shakapacker before Shakapacker v7).
91
+ Shakapacker supports serving JavaScript bundles and assets from a CDN. For a comprehensive guide on setting up CDN with Shakapacker, including CloudFlare configuration, troubleshooting, and advanced setups, see the [CDN Setup Guide](cdn_setup.md).
92
+
93
+ **Quick Setup**: Set the `SHAKAPACKER_ASSET_HOST` environment variable before compiling assets:
94
+
95
+ ```bash
96
+ export SHAKAPACKER_ASSET_HOST=https://cdn.example.com
97
+ RAILS_ENV=production bundle exec rails assets:precompile
98
+ ```
99
+
100
+ Note: Shakapacker does NOT use the `ASSET_HOST` environment variable. You must use `SHAKAPACKER_ASSET_HOST` instead (`WEBPACKER_ASSET_HOST` if using Shakapacker before v7).
92
101
 
93
102
  ## Capistrano
94
103
 
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.
@@ -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: []