shakapacker 9.2.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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +6 -9
- data/.github/ISSUE_TEMPLATE/feature_request.md +6 -8
- data/.github/workflows/claude-code-review.yml +4 -5
- data/.github/workflows/claude.yml +1 -2
- data/.github/workflows/dummy.yml +4 -4
- data/.github/workflows/generator.yml +9 -9
- data/.github/workflows/node.yml +11 -2
- data/.github/workflows/ruby.yml +16 -16
- data/.github/workflows/test-bundlers.yml +9 -9
- data/.gitignore +4 -0
- data/CHANGELOG.md +19 -4
- data/CLAUDE.md +6 -1
- data/CONTRIBUTING.md +0 -1
- data/Gemfile.lock +1 -1
- data/README.md +14 -14
- data/TODO.md +10 -2
- data/TODO_v9.md +13 -3
- data/bin/export-bundler-config +1 -1
- data/conductor-setup.sh +1 -1
- data/conductor.json +1 -1
- data/docs/cdn_setup.md +13 -8
- data/docs/common-upgrades.md +2 -1
- data/docs/configuration.md +630 -0
- data/docs/css-modules-export-mode.md +120 -100
- data/docs/customizing_babel_config.md +16 -16
- data/docs/deployment.md +18 -0
- data/docs/developing_shakapacker.md +6 -0
- data/docs/optional-peer-dependencies.md +9 -4
- data/docs/peer-dependencies.md +17 -6
- data/docs/precompile_hook.md +342 -0
- data/docs/react.md +57 -47
- data/docs/releasing.md +0 -2
- data/docs/rspack.md +25 -21
- data/docs/rspack_migration_guide.md +335 -8
- data/docs/sprockets.md +1 -0
- data/docs/style_loader_vs_mini_css.md +12 -12
- data/docs/subresource_integrity.md +13 -7
- data/docs/transpiler-performance.md +40 -19
- data/docs/troubleshooting.md +0 -2
- data/docs/typescript-migration.md +48 -39
- data/docs/typescript.md +12 -8
- data/docs/using_esbuild_loader.md +10 -10
- data/docs/v6_upgrade.md +33 -20
- data/docs/v7_upgrade.md +8 -6
- data/docs/v8_upgrade.md +13 -12
- data/docs/v9_upgrade.md +2 -1
- data/eslint.config.fast.js +134 -0
- data/eslint.config.js +140 -0
- data/knip.ts +54 -0
- data/lib/install/bin/export-bundler-config +1 -1
- data/lib/install/config/shakapacker.yml +16 -5
- data/lib/shakapacker/compiler.rb +80 -0
- data/lib/shakapacker/configuration.rb +33 -5
- data/lib/shakapacker/dev_server_runner.rb +140 -1
- data/lib/shakapacker/doctor.rb +294 -65
- data/lib/shakapacker/instance.rb +8 -3
- data/lib/shakapacker/runner.rb +244 -8
- data/lib/shakapacker/version.rb +1 -1
- data/lib/tasks/shakapacker/doctor.rake +42 -2
- data/package/babel/preset.ts +7 -4
- data/package/config.ts +42 -30
- data/package/configExporter/cli.ts +799 -208
- data/package/configExporter/configFile.ts +520 -0
- data/package/configExporter/fileWriter.ts +12 -8
- data/package/configExporter/index.ts +9 -1
- data/package/configExporter/types.ts +36 -2
- data/package/configExporter/yamlSerializer.ts +22 -8
- data/package/dev_server.ts +1 -1
- data/package/environments/__type-tests__/rspack-plugin-compatibility.ts +11 -5
- data/package/environments/base.ts +18 -13
- data/package/environments/development.ts +1 -1
- data/package/environments/production.ts +4 -1
- data/package/index.d.ts +50 -3
- data/package/index.d.ts.template +50 -0
- data/package/index.ts +7 -7
- data/package/loaders.d.ts +2 -2
- data/package/optimization/rspack.ts +1 -1
- data/package/plugins/rspack.ts +15 -4
- data/package/plugins/webpack.ts +7 -3
- data/package/rspack/index.ts +10 -2
- data/package/rules/raw.ts +3 -2
- data/package/rules/sass.ts +1 -1
- data/package/types/README.md +15 -13
- data/package/types/index.ts +5 -5
- data/package/types.ts +0 -1
- data/package/utils/defaultConfigPath.ts +4 -1
- data/package/utils/errorCodes.ts +129 -100
- data/package/utils/errorHelpers.ts +34 -29
- data/package/utils/getStyleRule.ts +5 -2
- data/package/utils/helpers.ts +21 -11
- data/package/utils/pathValidation.ts +43 -35
- data/package/utils/requireOrError.ts +1 -1
- data/package/utils/snakeToCamelCase.ts +1 -1
- data/package/utils/typeGuards.ts +132 -83
- data/package/utils/validateDependencies.ts +1 -1
- data/package/webpack-types.d.ts +3 -3
- data/package/webpackDevServerConfig.ts +22 -10
- data/package-lock.json +2 -2
- data/package.json +36 -28
- data/scripts/type-check-no-emit.js +1 -1
- data/test/configExporter/configFile.test.js +392 -0
- data/test/configExporter/integration.test.js +275 -0
- data/test/helpers.js +1 -1
- data/test/package/configExporter.test.js +154 -0
- data/test/package/helpers.test.js +2 -2
- data/test/package/rules/sass-version-parsing.test.js +71 -0
- data/test/package/rules/sass.test.js +2 -4
- data/test/package/rules/sass1.test.js +1 -3
- data/test/package/rules/sass16.test.js +23 -0
- data/tools/README.md +15 -5
- data/tsconfig.eslint.json +2 -9
- data/yarn.lock +1894 -1492
- metadata +19 -3
- data/.eslintignore +0 -5
@@ -10,8 +10,8 @@ In pure JavaScript projects, you can use true named imports:
|
|
10
10
|
|
11
11
|
```js
|
12
12
|
// v9 - named exports in JavaScript
|
13
|
-
import { bright, container } from
|
14
|
-
|
13
|
+
import { bright, container } from "./Foo.module.css"
|
14
|
+
;<button className={bright} />
|
15
15
|
```
|
16
16
|
|
17
17
|
### TypeScript Usage
|
@@ -27,6 +27,7 @@ import * as styles from './Foo.module.css';
|
|
27
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
28
|
|
29
29
|
### Benefits of v9 Configuration
|
30
|
+
|
30
31
|
- Eliminates certain webpack warnings
|
31
32
|
- Provides better tree-shaking potential
|
32
33
|
- Aligns with modern JavaScript module standards
|
@@ -37,6 +38,7 @@ import * as styles from './Foo.module.css';
|
|
37
38
|
When `namedExport: true` is enabled (v9 default), css-loader requires `exportLocalsConvention` to be either `'camelCaseOnly'` or `'dashesOnly'`.
|
38
39
|
|
39
40
|
**The following will cause a build error:**
|
41
|
+
|
40
42
|
```js
|
41
43
|
modules: {
|
42
44
|
namedExport: true,
|
@@ -45,11 +47,13 @@ modules: {
|
|
45
47
|
```
|
46
48
|
|
47
49
|
**Error message:**
|
50
|
+
|
48
51
|
```
|
49
52
|
"exportLocalsConvention" with "camelCase" value is incompatible with "namedExport: true" option
|
50
53
|
```
|
51
54
|
|
52
55
|
**Correct v9 configuration:**
|
56
|
+
|
53
57
|
```js
|
54
58
|
modules: {
|
55
59
|
namedExport: true,
|
@@ -60,23 +64,26 @@ modules: {
|
|
60
64
|
**exportLocalsConvention options with namedExport:**
|
61
65
|
|
62
66
|
When `namedExport: true`, you can use:
|
67
|
+
|
63
68
|
- `'camelCaseOnly'` (v9 default): Exports ONLY the camelCase version (e.g., only `myButton`)
|
64
69
|
- `'dashesOnly'`: Exports ONLY the original kebab-case version (e.g., only `my-button`)
|
65
70
|
|
66
71
|
**Not compatible with namedExport: true:**
|
72
|
+
|
67
73
|
- `'camelCase'`: Exports both versions (both `my-button` and `myButton`) - only works with `namedExport: false` (v8 behavior)
|
68
74
|
|
69
75
|
**Configuration Quick Reference:**
|
70
76
|
|
71
|
-
| namedExport | exportLocalsConvention | `.my-button` exports
|
72
|
-
|
73
|
-
| `true`
|
74
|
-
| `true`
|
75
|
-
| `false`
|
76
|
-
| `false`
|
77
|
-
| `true`
|
77
|
+
| namedExport | exportLocalsConvention | `.my-button` exports | Use Case | Compatible? |
|
78
|
+
| ----------- | ---------------------- | --------------------------------- | ---------------------- | -------------- |
|
79
|
+
| `true` | `'camelCaseOnly'` | `myButton` | JavaScript conventions | ✅ Valid |
|
80
|
+
| `true` | `'dashesOnly'` | `'my-button'` | Preserve CSS naming | ✅ Valid |
|
81
|
+
| `false` | `'camelCase'` | Both `myButton` AND `'my-button'` | v8 compatibility | ✅ Valid |
|
82
|
+
| `false` | `'asIs'` | `'my-button'` | No transformation | ✅ Valid |
|
83
|
+
| `true` | `'camelCase'` | - | - | ❌ Build Error |
|
78
84
|
|
79
85
|
**When to use each option:**
|
86
|
+
|
80
87
|
- Use `'camelCaseOnly'` if you prefer standard JavaScript naming conventions
|
81
88
|
- Use `'dashesOnly'` if you want to preserve your CSS class names exactly as written
|
82
89
|
- Use `'camelCase'` (with `namedExport: false`) only if you need both versions available
|
@@ -87,8 +94,8 @@ In Shakapacker v8 and earlier, the default behavior was to use a **default expor
|
|
87
94
|
|
88
95
|
```js
|
89
96
|
// v8 and earlier default
|
90
|
-
import styles from
|
91
|
-
|
97
|
+
import styles from "./Foo.module.css"
|
98
|
+
;<button className={styles.bright} />
|
92
99
|
```
|
93
100
|
|
94
101
|
---
|
@@ -102,21 +109,23 @@ When upgrading to Shakapacker v9, you'll need to update your CSS Module imports
|
|
102
109
|
#### Option 1: Update Your Code (Recommended)
|
103
110
|
|
104
111
|
**For JavaScript projects:**
|
112
|
+
|
105
113
|
```js
|
106
114
|
// Before (v8)
|
107
|
-
import styles from
|
108
|
-
|
115
|
+
import styles from "./Component.module.css"
|
116
|
+
;<div className={styles.container}>
|
109
117
|
<button className={styles.button}>Click me</button>
|
110
118
|
</div>
|
111
119
|
|
112
120
|
// After (v9) - JavaScript
|
113
|
-
import { container, button } from
|
114
|
-
|
121
|
+
import { container, button } from "./Component.module.css"
|
122
|
+
;<div className={container}>
|
115
123
|
<button className={button}>Click me</button>
|
116
124
|
</div>
|
117
125
|
```
|
118
126
|
|
119
127
|
**For TypeScript projects:**
|
128
|
+
|
120
129
|
```typescript
|
121
130
|
// Before (v8)
|
122
131
|
import styles from './Component.module.css';
|
@@ -149,44 +158,44 @@ This approach modifies the common webpack configuration that applies to all envi
|
|
149
158
|
|
150
159
|
```js
|
151
160
|
// config/webpack/commonWebpackConfig.js
|
152
|
-
const { generateWebpackConfig, merge } = require(
|
161
|
+
const { generateWebpackConfig, merge } = require("shakapacker")
|
153
162
|
|
154
|
-
const baseClientWebpackConfig = generateWebpackConfig()
|
163
|
+
const baseClientWebpackConfig = generateWebpackConfig()
|
155
164
|
|
156
165
|
// Override CSS Modules configuration to use v8-style default exports
|
157
166
|
const overrideCssModulesConfig = (config) => {
|
158
167
|
// Find the CSS rule in the module rules
|
159
|
-
const cssRule = config.module.rules.find(
|
160
|
-
rule.test && rule.test.toString().includes(
|
161
|
-
)
|
168
|
+
const cssRule = config.module.rules.find(
|
169
|
+
(rule) => rule.test && rule.test.toString().includes("css")
|
170
|
+
)
|
162
171
|
|
163
172
|
if (cssRule && cssRule.use) {
|
164
|
-
const cssLoaderUse = cssRule.use.find(
|
165
|
-
use.loader && use.loader.includes(
|
166
|
-
)
|
173
|
+
const cssLoaderUse = cssRule.use.find(
|
174
|
+
(use) => use.loader && use.loader.includes("css-loader")
|
175
|
+
)
|
167
176
|
|
168
177
|
if (cssLoaderUse && cssLoaderUse.options && cssLoaderUse.options.modules) {
|
169
178
|
// Override v9 default to use v8-style default exports
|
170
|
-
cssLoaderUse.options.modules.namedExport = false
|
171
|
-
cssLoaderUse.options.modules.exportLocalsConvention =
|
179
|
+
cssLoaderUse.options.modules.namedExport = false
|
180
|
+
cssLoaderUse.options.modules.exportLocalsConvention = "asIs"
|
172
181
|
}
|
173
182
|
}
|
174
183
|
|
175
|
-
return config
|
176
|
-
}
|
184
|
+
return config
|
185
|
+
}
|
177
186
|
|
178
187
|
const commonOptions = {
|
179
188
|
resolve: {
|
180
|
-
extensions: [
|
181
|
-
}
|
182
|
-
}
|
189
|
+
extensions: [".css", ".ts", ".tsx"]
|
190
|
+
}
|
191
|
+
}
|
183
192
|
|
184
193
|
const commonWebpackConfig = () => {
|
185
|
-
const config = merge({}, baseClientWebpackConfig, commonOptions)
|
186
|
-
return overrideCssModulesConfig(config)
|
187
|
-
}
|
194
|
+
const config = merge({}, baseClientWebpackConfig, commonOptions)
|
195
|
+
return overrideCssModulesConfig(config)
|
196
|
+
}
|
188
197
|
|
189
|
-
module.exports = commonWebpackConfig
|
198
|
+
module.exports = commonWebpackConfig
|
190
199
|
```
|
191
200
|
|
192
201
|
### Option 2: Create `config/webpack/environment.js` (Alternative)
|
@@ -195,8 +204,8 @@ If you prefer using a separate environment file:
|
|
195
204
|
|
196
205
|
```js
|
197
206
|
// config/webpack/environment.js
|
198
|
-
const { environment } = require(
|
199
|
-
const getStyleRule = require(
|
207
|
+
const { environment } = require("@shakacode/shakapacker")
|
208
|
+
const getStyleRule = require("@shakacode/shakapacker/package/utils/getStyleRule")
|
200
209
|
|
201
210
|
// CSS Modules rule for *.module.css with v8-style default export
|
202
211
|
const cssModulesRule = getStyleRule(/\.module\.css$/i, [], {
|
@@ -204,14 +213,14 @@ const cssModulesRule = getStyleRule(/\.module\.css$/i, [], {
|
|
204
213
|
importLoaders: 2,
|
205
214
|
modules: {
|
206
215
|
auto: true,
|
207
|
-
namedExport: false,
|
208
|
-
exportLocalsConvention:
|
216
|
+
namedExport: false, // <-- override v9 default
|
217
|
+
exportLocalsConvention: "asIs" // keep class names as-is instead of camelCase
|
209
218
|
}
|
210
|
-
})
|
219
|
+
})
|
211
220
|
|
212
221
|
// Ensure this rule wins for *.module.css
|
213
222
|
if (cssModulesRule) {
|
214
|
-
environment.loaders.prepend(
|
223
|
+
environment.loaders.prepend("css-modules", cssModulesRule)
|
215
224
|
}
|
216
225
|
|
217
226
|
// Plain CSS rule for non-modules
|
@@ -219,13 +228,13 @@ const plainCssRule = getStyleRule(/(?<!\.module)\.css$/i, [], {
|
|
219
228
|
sourceMap: true,
|
220
229
|
importLoaders: 2,
|
221
230
|
modules: false
|
222
|
-
})
|
231
|
+
})
|
223
232
|
|
224
233
|
if (plainCssRule) {
|
225
|
-
environment.loaders.append(
|
234
|
+
environment.loaders.append("css", plainCssRule)
|
226
235
|
}
|
227
236
|
|
228
|
-
module.exports = environment
|
237
|
+
module.exports = environment
|
229
238
|
```
|
230
239
|
|
231
240
|
Then reference this in your environment-specific configs (development.js, production.js, etc.).
|
@@ -238,25 +247,32 @@ If you also use Sass modules, add similar configuration for SCSS files:
|
|
238
247
|
// For Option 1 approach, extend the overrideCssModulesConfig function:
|
239
248
|
const overrideCssModulesConfig = (config) => {
|
240
249
|
// Handle both CSS and SCSS rules
|
241
|
-
const styleRules = config.module.rules.filter(
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
250
|
+
const styleRules = config.module.rules.filter(
|
251
|
+
(rule) =>
|
252
|
+
rule.test &&
|
253
|
+
(rule.test.toString().includes("css") ||
|
254
|
+
rule.test.toString().includes("scss"))
|
255
|
+
)
|
256
|
+
|
257
|
+
styleRules.forEach((rule) => {
|
246
258
|
if (rule.use) {
|
247
|
-
const cssLoaderUse = rule.use.find(
|
248
|
-
use.loader && use.loader.includes(
|
249
|
-
)
|
250
|
-
|
251
|
-
if (
|
252
|
-
cssLoaderUse
|
253
|
-
cssLoaderUse.options
|
259
|
+
const cssLoaderUse = rule.use.find(
|
260
|
+
(use) => use.loader && use.loader.includes("css-loader")
|
261
|
+
)
|
262
|
+
|
263
|
+
if (
|
264
|
+
cssLoaderUse &&
|
265
|
+
cssLoaderUse.options &&
|
266
|
+
cssLoaderUse.options.modules
|
267
|
+
) {
|
268
|
+
cssLoaderUse.options.modules.namedExport = false
|
269
|
+
cssLoaderUse.options.modules.exportLocalsConvention = "asIs"
|
254
270
|
}
|
255
271
|
}
|
256
|
-
})
|
272
|
+
})
|
257
273
|
|
258
|
-
return config
|
259
|
-
}
|
274
|
+
return config
|
275
|
+
}
|
260
276
|
```
|
261
277
|
|
262
278
|
---
|
@@ -269,10 +285,10 @@ const overrideCssModulesConfig = (config) => {
|
|
269
285
|
|
270
286
|
```js
|
271
287
|
// Old (v8 - default export)
|
272
|
-
import styles from
|
288
|
+
import styles from "./Component.module.css"
|
273
289
|
|
274
290
|
// New (v9 - named exports)
|
275
|
-
import { bright, container, button } from
|
291
|
+
import { bright, container, button } from "./Component.module.css"
|
276
292
|
```
|
277
293
|
|
278
294
|
#### 2. Update Class References
|
@@ -305,8 +321,8 @@ With `exportLocalsConvention: 'camelCaseOnly'`, kebab-case class names are autom
|
|
305
321
|
|
306
322
|
```js
|
307
323
|
// v9 default - camelCase conversion
|
308
|
-
import { myButton, primaryColor } from
|
309
|
-
|
324
|
+
import { myButton, primaryColor } from "./styles.module.css"
|
325
|
+
;<button className={myButton} />
|
310
326
|
```
|
311
327
|
|
312
328
|
**Option B: Keep kebab-case with 'dashesOnly'**
|
@@ -339,30 +355,33 @@ For large codebases, you can create a codemod to automate the migration:
|
|
339
355
|
|
340
356
|
```js
|
341
357
|
// css-modules-v9-migration.js
|
342
|
-
module.exports = function(fileInfo, api) {
|
343
|
-
const j = api.jscodeshift
|
344
|
-
const root = j(fileInfo.source)
|
345
|
-
|
358
|
+
module.exports = function (fileInfo, api) {
|
359
|
+
const j = api.jscodeshift
|
360
|
+
const root = j(fileInfo.source)
|
361
|
+
|
346
362
|
// Find CSS module imports
|
347
|
-
root
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
+
root
|
364
|
+
.find(j.ImportDeclaration, {
|
365
|
+
source: { value: (value) => value.endsWith(".module.css") }
|
366
|
+
})
|
367
|
+
.forEach((path) => {
|
368
|
+
const defaultSpecifier = path.node.specifiers.find(
|
369
|
+
(spec) => spec.type === "ImportDefaultSpecifier"
|
370
|
+
)
|
371
|
+
|
372
|
+
if (defaultSpecifier) {
|
373
|
+
// Convert default import to namespace import for analysis
|
374
|
+
// Then extract used properties and convert to named imports
|
375
|
+
// ... codemod implementation
|
376
|
+
}
|
377
|
+
})
|
378
|
+
|
379
|
+
return root.toSource()
|
380
|
+
}
|
363
381
|
```
|
364
382
|
|
365
383
|
Run with:
|
384
|
+
|
366
385
|
```bash
|
367
386
|
npx jscodeshift -t css-modules-v9-migration.js src/
|
368
387
|
```
|
@@ -371,14 +390,14 @@ npx jscodeshift -t css-modules-v9-migration.js src/
|
|
371
390
|
|
372
391
|
## Version Comparison
|
373
392
|
|
374
|
-
| Feature
|
375
|
-
|
376
|
-
| Default behavior
|
377
|
-
| Import syntax
|
378
|
-
| Class reference
|
379
|
-
| Export convention
|
380
|
-
| TypeScript warnings | May show warnings
|
381
|
-
| Tree-shaking
|
393
|
+
| Feature | v8 (and earlier) | v9 |
|
394
|
+
| ------------------- | -------------------------- | --------------------------------- |
|
395
|
+
| Default behavior | Default export object | Named exports |
|
396
|
+
| Import syntax | `import styles from '...'` | `import { className } from '...'` |
|
397
|
+
| Class reference | `styles.className` | `className` |
|
398
|
+
| Export convention | `asIs` (no transformation) | `camelCaseOnly` |
|
399
|
+
| TypeScript warnings | May show warnings | No warnings |
|
400
|
+
| Tree-shaking | Limited | Optimized |
|
382
401
|
|
383
402
|
---
|
384
403
|
|
@@ -419,12 +438,12 @@ Verify your imports work correctly:
|
|
419
438
|
|
420
439
|
```js
|
421
440
|
// v9 default (named exports)
|
422
|
-
import { bright } from
|
423
|
-
console.log(bright)
|
441
|
+
import { bright } from "./Foo.module.css"
|
442
|
+
console.log(bright) // 'Foo_bright__hash'
|
424
443
|
|
425
444
|
// Or if using v8 configuration (default export)
|
426
|
-
import styles from
|
427
|
-
console.log(styles)
|
445
|
+
import styles from "./Foo.module.css"
|
446
|
+
console.log(styles) // { bright: 'Foo_bright__hash' }
|
428
447
|
```
|
429
448
|
|
430
449
|
### 3. Debug Webpack Configuration (Optional)
|
@@ -444,6 +463,7 @@ Then search for `css-loader` options in the generated JSON file.
|
|
444
463
|
### Build Error: exportLocalsConvention Incompatible with namedExport
|
445
464
|
|
446
465
|
If you see this error during build:
|
466
|
+
|
447
467
|
```
|
448
468
|
"exportLocalsConvention" with "camelCase" value is incompatible with "namedExport: true" option
|
449
469
|
```
|
@@ -477,9 +497,9 @@ If your CSS classes aren't applying after the upgrade:
|
|
477
497
|
|
478
498
|
```typescript
|
479
499
|
// src/types/css-modules.d.ts
|
480
|
-
declare module
|
481
|
-
const classes: { [key: string]: string }
|
482
|
-
export = classes
|
500
|
+
declare module "*.module.css" {
|
501
|
+
const classes: { [key: string]: string }
|
502
|
+
export = classes
|
483
503
|
}
|
484
504
|
```
|
485
505
|
|
@@ -487,9 +507,9 @@ declare module '*.module.css' {
|
|
487
507
|
|
488
508
|
```typescript
|
489
509
|
// src/types/css-modules.d.ts
|
490
|
-
declare module
|
491
|
-
const classes: { [key: string]: string }
|
492
|
-
export default classes
|
510
|
+
declare module "*.module.css" {
|
511
|
+
const classes: { [key: string]: string }
|
512
|
+
export default classes
|
493
513
|
}
|
494
514
|
```
|
495
515
|
|
@@ -1,14 +1,13 @@
|
|
1
1
|
# Customizing Babel Config
|
2
2
|
|
3
3
|
## Default Configuration
|
4
|
+
|
4
5
|
The default configuration of babel is done by using `package.json` to use the file within the `shakapacker` package.
|
5
6
|
|
6
7
|
```json
|
7
8
|
{
|
8
9
|
"babel": {
|
9
|
-
"presets": [
|
10
|
-
"./node_modules/shakapacker/package/babel/preset.js"
|
11
|
-
]
|
10
|
+
"presets": ["./node_modules/shakapacker/package/babel/preset.js"]
|
12
11
|
}
|
13
12
|
}
|
14
13
|
```
|
@@ -22,7 +21,7 @@ This is a very basic skeleton that you can use that includes the Shakapacker pre
|
|
22
21
|
```js
|
23
22
|
// babel.config.js
|
24
23
|
module.exports = function (api) {
|
25
|
-
const defaultConfigFunc = require(
|
24
|
+
const defaultConfigFunc = require("shakapacker/package/babel/preset.js")
|
26
25
|
const resultConfig = defaultConfigFunc(api)
|
27
26
|
|
28
27
|
const changesOnDefault = {
|
@@ -31,7 +30,7 @@ module.exports = function (api) {
|
|
31
30
|
].filter(Boolean),
|
32
31
|
plugins: [
|
33
32
|
// put custom plugins here
|
34
|
-
].filter(Boolean)
|
33
|
+
].filter(Boolean)
|
35
34
|
}
|
36
35
|
|
37
36
|
resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets]
|
@@ -55,30 +54,31 @@ And then update the configuration:
|
|
55
54
|
```js
|
56
55
|
// babel.config.js
|
57
56
|
module.exports = function (api) {
|
58
|
-
const defaultConfigFunc = require(
|
57
|
+
const defaultConfigFunc = require("shakapacker/package/babel/preset.js")
|
59
58
|
const resultConfig = defaultConfigFunc(api)
|
60
|
-
const isDevelopmentEnv = api.env(
|
61
|
-
const isProductionEnv = api.env(
|
62
|
-
const isTestEnv = api.env(
|
59
|
+
const isDevelopmentEnv = api.env("development")
|
60
|
+
const isProductionEnv = api.env("production")
|
61
|
+
const isTestEnv = api.env("test")
|
63
62
|
|
64
63
|
const changesOnDefault = {
|
65
64
|
presets: [
|
66
65
|
[
|
67
|
-
|
66
|
+
"@babel/preset-react",
|
68
67
|
{
|
69
68
|
development: isDevelopmentEnv || isTestEnv,
|
70
69
|
useBuiltIns: true
|
71
|
-
}
|
70
|
+
}
|
72
71
|
]
|
73
72
|
].filter(Boolean),
|
74
73
|
plugins: [
|
75
|
-
isProductionEnv && [
|
76
|
-
|
77
|
-
|
74
|
+
isProductionEnv && [
|
75
|
+
"babel-plugin-transform-react-remove-prop-types",
|
76
|
+
{
|
77
|
+
removeImport: true
|
78
78
|
}
|
79
79
|
],
|
80
|
-
process.env.WEBPACK_SERVE &&
|
81
|
-
].filter(Boolean)
|
80
|
+
process.env.WEBPACK_SERVE && "react-refresh/babel"
|
81
|
+
].filter(Boolean)
|
82
82
|
}
|
83
83
|
|
84
84
|
resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets]
|
data/docs/deployment.md
CHANGED
@@ -3,6 +3,24 @@
|
|
3
3
|
Shakapacker hooks up a new `shakapacker:compile` task to `assets:precompile`, which gets run whenever you run `assets:precompile`.
|
4
4
|
If you are not using Sprockets `shakapacker:compile` is automatically aliased to `assets:precompile`.
|
5
5
|
|
6
|
+
**📖 For configuration options, see the [Configuration Guide](./configuration.md)**
|
7
|
+
|
8
|
+
## Precompile Hook
|
9
|
+
|
10
|
+
Shakapacker supports running a custom command before webpack compilation via the `precompile_hook` configuration option. This is useful for dynamically generating entry points (e.g., for React on Rails) or performing other preparatory tasks.
|
11
|
+
|
12
|
+
**Note:** The precompile hook runs in both development and production environments. For complete documentation, see the [Precompile Hook Guide](precompile_hook.md).
|
13
|
+
|
14
|
+
Quick example for production deployment:
|
15
|
+
|
16
|
+
```yaml
|
17
|
+
# config/shakapacker.yml
|
18
|
+
production:
|
19
|
+
precompile_hook: "bin/rails react_on_rails:generate_packs"
|
20
|
+
```
|
21
|
+
|
22
|
+
This ensures your dynamic entry points are generated before `assets:precompile` runs.
|
23
|
+
|
6
24
|
## Heroku
|
7
25
|
|
8
26
|
In order for your Shakapacker app to run on Heroku, you'll need to do a bit of configuration before hand.
|
@@ -3,19 +3,25 @@
|
|
3
3
|
It's a little trickier for Rails developers to work on the JS code of a project like shakacode/shakapacker. So here are some tips!
|
4
4
|
|
5
5
|
## Use some test app
|
6
|
+
|
6
7
|
For example, for React on Rails Changes, I'm using [shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh](https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh).
|
7
8
|
This directory is the `TEST_APP_DIR`.
|
8
9
|
|
9
10
|
## Fork shakacode/shakapacker
|
11
|
+
|
10
12
|
Let's call the shakacode/shakapacker directory `SHAKAPACKER_DIR` which has shakacode/shakapacker's `package.json`.
|
11
13
|
|
12
14
|
## Changing the Package
|
15
|
+
|
13
16
|
### Setup with Yalc
|
17
|
+
|
14
18
|
Use [`yalc`](https://github.com/wclr/yalc) unless you like yak shaving weird errors.
|
19
|
+
|
15
20
|
1. In `SHAKAPACKER_DIR`, run `yalc publish`
|
16
21
|
2. In `TEST_APP_DIR`, run `yalc link shakapacker`
|
17
22
|
|
18
23
|
## Update the Package Code
|
24
|
+
|
19
25
|
1. Make some JS change in SHAKAPACKER_DIR
|
20
26
|
2. Run `yalc push` and your changes will be pushed to your `TEST_APP_DIR`'s node_modules.
|
21
27
|
3. You may need to run `yarn` in `TEST_APP_DIR` if you added or removed dependencies of shakacode/shakapacker.
|
@@ -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"
|
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(
|
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
|