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
data/docs/rspack.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Shakapacker supports [Rspack](https://rspack.rs) as an alternative assets bundler to Webpack. Rspack is a fast Rust-based web bundler with webpack-compatible API that can significantly speed up your build times.
|
4
4
|
|
5
|
+
**📖 For configuration options, see the [Configuration Guide](./configuration.md)**
|
6
|
+
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
First, install the required Rspack dependencies:
|
@@ -10,7 +12,7 @@ First, install the required Rspack dependencies:
|
|
10
12
|
npm install @rspack/core @rspack/cli -D
|
11
13
|
# or
|
12
14
|
yarn add @rspack/core @rspack/cli -D
|
13
|
-
# or
|
15
|
+
# or
|
14
16
|
pnpm add @rspack/core @rspack/cli -D
|
15
17
|
# or
|
16
18
|
bun add @rspack/core @rspack/cli -D
|
@@ -23,9 +25,8 @@ Note: These packages are already listed as optional peer dependencies in Shakapa
|
|
23
25
|
To enable Rspack, update your `config/shakapacker.yml`:
|
24
26
|
|
25
27
|
```yaml
|
26
|
-
default: &default
|
27
|
-
#
|
28
|
-
assets_bundler: 'rspack' # Change from 'webpack' to 'rspack'
|
28
|
+
default: &default # ... other config options
|
29
|
+
assets_bundler: "rspack" # Change from 'webpack' to 'rspack'
|
29
30
|
```
|
30
31
|
|
31
32
|
### Configuration Files
|
@@ -33,7 +34,7 @@ default: &default
|
|
33
34
|
Rspack uses its own configuration directory to keep things organized. Create your Rspack configuration file at `config/rspack/rspack.config.js`:
|
34
35
|
|
35
36
|
```javascript
|
36
|
-
const { generateRspackConfig } = require(
|
37
|
+
const { generateRspackConfig } = require("shakapacker/rspack")
|
37
38
|
|
38
39
|
module.exports = generateRspackConfig()
|
39
40
|
```
|
@@ -43,14 +44,12 @@ module.exports = generateRspackConfig()
|
|
43
44
|
If you need to customize your Rspack configuration:
|
44
45
|
|
45
46
|
```javascript
|
46
|
-
const { generateRspackConfig } = require(
|
47
|
+
const { generateRspackConfig } = require("shakapacker/rspack")
|
47
48
|
|
48
49
|
const rspackConfig = generateRspackConfig({
|
49
|
-
plugins: [
|
50
|
-
new SomeRspackCompatiblePlugin()
|
51
|
-
],
|
50
|
+
plugins: [new SomeRspackCompatiblePlugin()],
|
52
51
|
resolve: {
|
53
|
-
extensions: [
|
52
|
+
extensions: [".ts", ".tsx", ".js", ".jsx"]
|
54
53
|
}
|
55
54
|
})
|
56
55
|
|
@@ -62,14 +61,16 @@ module.exports = rspackConfig
|
|
62
61
|
If you have an existing `config/webpack/webpack.config.js`, you can migrate it to `config/rspack/rspack.config.js`:
|
63
62
|
|
64
63
|
**Old (webpack.config.js):**
|
64
|
+
|
65
65
|
```javascript
|
66
|
-
const { generateWebpackConfig } = require(
|
66
|
+
const { generateWebpackConfig } = require("shakapacker")
|
67
67
|
module.exports = generateWebpackConfig()
|
68
68
|
```
|
69
69
|
|
70
70
|
**New (rspack.config.js):**
|
71
|
+
|
71
72
|
```javascript
|
72
|
-
const { generateRspackConfig } = require(
|
73
|
+
const { generateRspackConfig } = require("shakapacker/rspack")
|
73
74
|
module.exports = generateRspackConfig()
|
74
75
|
```
|
75
76
|
|
@@ -89,11 +90,11 @@ Rspack has built-in loaders that are faster than their webpack counterparts:
|
|
89
90
|
|
90
91
|
Most webpack plugins work with Rspack, but some have Rspack-specific alternatives:
|
91
92
|
|
92
|
-
| Webpack Plugin
|
93
|
-
|
94
|
-
| `mini-css-extract-plugin` | `rspack.CssExtractRspackPlugin`
|
95
|
-
| `copy-webpack-plugin`
|
96
|
-
| `terser-webpack-plugin`
|
93
|
+
| Webpack Plugin | Rspack Alternative | Status |
|
94
|
+
| ------------------------- | ----------------------------------- | -------- |
|
95
|
+
| `mini-css-extract-plugin` | `rspack.CssExtractRspackPlugin` | Built-in |
|
96
|
+
| `copy-webpack-plugin` | `rspack.CopyRspackPlugin` | Built-in |
|
97
|
+
| `terser-webpack-plugin` | `rspack.SwcJsMinimizerRspackPlugin` | Built-in |
|
97
98
|
|
98
99
|
### Minification
|
99
100
|
|
@@ -136,28 +137,31 @@ The same dev server configuration in `shakapacker.yml` applies to both webpack a
|
|
136
137
|
Rspack typically provides:
|
137
138
|
|
138
139
|
- **2-10x faster** cold builds
|
139
|
-
- **5-20x faster** incremental builds
|
140
|
+
- **5-20x faster** incremental builds
|
140
141
|
- **Faster HMR** (Hot Module Replacement)
|
141
142
|
- **Lower memory usage**
|
142
143
|
|
143
144
|
## Migration Checklist
|
144
145
|
|
145
146
|
1. **Install Rspack dependencies:**
|
147
|
+
|
146
148
|
```bash
|
147
149
|
npm install @rspack/core @rspack/cli -D
|
148
150
|
```
|
149
151
|
|
150
152
|
2. **Update configuration:**
|
153
|
+
|
151
154
|
```yaml
|
152
155
|
# config/shakapacker.yml
|
153
156
|
default: &default
|
154
|
-
assets_bundler:
|
157
|
+
assets_bundler: "rspack"
|
155
158
|
```
|
156
159
|
|
157
160
|
3. **Create Rspack config:**
|
161
|
+
|
158
162
|
```javascript
|
159
163
|
// config/rspack/rspack.config.js
|
160
|
-
const { generateRspackConfig } = require(
|
164
|
+
const { generateRspackConfig } = require("shakapacker/rspack")
|
161
165
|
module.exports = generateRspackConfig()
|
162
166
|
```
|
163
167
|
|
@@ -187,4 +191,4 @@ If builds are unexpectedly slow:
|
|
187
191
|
|
188
192
|
- [Rspack Official Documentation](https://rspack.rs)
|
189
193
|
- [Rspack Migration Guide](https://rspack.rs/guide/migration/webpack)
|
190
|
-
- [Rspack Plugins](https://rspack.rs/plugins/webpack/)
|
194
|
+
- [Rspack Plugins](https://rspack.rs/plugins/webpack/)
|
@@ -2,10 +2,67 @@
|
|
2
2
|
|
3
3
|
> 💡 **Quick Start**: For a step-by-step migration guide from Webpack to Rspack, see [Common Upgrades Guide - Webpack to Rspack](./common-upgrades.md#migrating-from-webpack-to-rspack).
|
4
4
|
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
- [Overview](#overview)
|
8
|
+
- [Before You Migrate](#before-you-migrate)
|
9
|
+
- [Migration Timeline Expectations](#migration-timeline-expectations)
|
10
|
+
- [Testing Strategy](#testing-strategy)
|
11
|
+
- [Server-Side Rendering (SSR) Considerations](#server-side-rendering-ssr-considerations)
|
12
|
+
- [Key Differences from Webpack](#key-differences-from-webpack)
|
13
|
+
- [Migration Steps](#migration-steps)
|
14
|
+
- [Configuration Best Practices](#configuration-best-practices)
|
15
|
+
- [Common Issues and Solutions](#common-issues-and-solutions)
|
16
|
+
- [Performance Tips](#performance-tips)
|
17
|
+
- [Debugging Configuration](#debugging-configuration)
|
18
|
+
- [Resources](#resources)
|
19
|
+
|
5
20
|
## Overview
|
6
21
|
|
7
22
|
This guide documents the differences between webpack and Rspack configurations in Shakapacker, and provides migration guidance for users switching to Rspack.
|
8
23
|
|
24
|
+
[Rspack](https://rspack.rs/) is a high-performance bundler written in Rust, offering 5-10x faster build times than webpack with excellent webpack compatibility.
|
25
|
+
|
26
|
+
## Before You Migrate
|
27
|
+
|
28
|
+
### Migration Timeline Expectations
|
29
|
+
|
30
|
+
Based on real-world migrations, plan your migration time accordingly:
|
31
|
+
|
32
|
+
- **Simple projects** (no SSR, no CSS modules, no custom config): 1-2 hours
|
33
|
+
- **Standard projects** (CSS modules, basic SSR): 4-8 hours
|
34
|
+
- **Complex projects** (CSS modules, SSR, ReScript, custom config): 2-3 days
|
35
|
+
|
36
|
+
**Without good documentation**: A complex migration can take 3+ days with 11+ commits to resolve all issues.
|
37
|
+
|
38
|
+
**With this documentation**: Most issues can be resolved in 2-3 commits.
|
39
|
+
|
40
|
+
### Testing Strategy
|
41
|
+
|
42
|
+
When migrating from webpack to Rspack, follow this testing strategy to minimize issues:
|
43
|
+
|
44
|
+
1. **Test locally first**: Ensure you can run the full test suite locally before pushing
|
45
|
+
2. **Incremental migration**: Consider migrating to SWC first (while on webpack), test thoroughly, then migrate to Rspack
|
46
|
+
3. **Watch for test flakiness**: SSR-related issues (especially CSS extraction) can cause non-deterministic test failures
|
47
|
+
4. **Run full test suite**: Don't rely solely on CI - run tests locally to catch issues faster
|
48
|
+
|
49
|
+
### Server-Side Rendering (SSR) Considerations
|
50
|
+
|
51
|
+
⚠️ **If your application uses SSR**, be aware of these critical issues before migrating:
|
52
|
+
|
53
|
+
1. **CSS Extraction Differences**: Rspack uses different loader paths than webpack for CSS extraction
|
54
|
+
2. **CSS Modules Breaking Change**: Shakapacker 9 changed from default exports to named exports
|
55
|
+
3. **React Runtime Compatibility**: SWC's automatic runtime may not work with React on Rails SSR detection
|
56
|
+
|
57
|
+
**SSR Migration Checklist** (complete before migrating):
|
58
|
+
|
59
|
+
- [ ] Understand how your server bundle filters CSS extraction loaders
|
60
|
+
- [ ] Know whether you're using CSS modules and how they're imported
|
61
|
+
- [ ] Check if you're using React on Rails SSR (may need classic React runtime)
|
62
|
+
- [ ] Plan for potential configuration changes to handle both webpack and Rspack paths
|
63
|
+
|
64
|
+
**Detailed SSR solutions** are provided in the [Common Issues](#common-issues-and-solutions) section below.
|
65
|
+
|
9
66
|
## Key Differences from Webpack
|
10
67
|
|
11
68
|
### 1. Built-in Loaders
|
@@ -145,7 +202,7 @@ devServer: {
|
|
145
202
|
}
|
146
203
|
```
|
147
204
|
|
148
|
-
## Migration
|
205
|
+
## Migration Steps
|
149
206
|
|
150
207
|
### Quick Start: Using the Switch Bundler Task
|
151
208
|
|
@@ -194,7 +251,7 @@ rails shakapacker:switch_bundler --init-config
|
|
194
251
|
|
195
252
|
If you prefer to migrate manually or need more control:
|
196
253
|
|
197
|
-
|
254
|
+
#### Step 1: Update Dependencies
|
198
255
|
|
199
256
|
```bash
|
200
257
|
# Remove webpack dependencies
|
@@ -204,7 +261,7 @@ npm uninstall webpack webpack-cli webpack-dev-server
|
|
204
261
|
npm install --save-dev @rspack/core @rspack/cli
|
205
262
|
```
|
206
263
|
|
207
|
-
|
264
|
+
#### Step 2: Update Configuration Files
|
208
265
|
|
209
266
|
1. Create `config/rspack/rspack.config.js` based on your webpack config
|
210
267
|
2. Update `config/shakapacker.yml`:
|
@@ -213,24 +270,24 @@ npm install --save-dev @rspack/core @rspack/cli
|
|
213
270
|
assets_bundler: "rspack"
|
214
271
|
```
|
215
272
|
|
216
|
-
|
273
|
+
#### Step 3: Replace Loaders
|
217
274
|
|
218
275
|
- Replace `babel-loader` with `builtin:swc-loader`
|
219
276
|
- Remove `file-loader`, `url-loader`, `raw-loader` - use asset modules
|
220
277
|
- Update CSS loaders to use Rspack's built-in support
|
221
278
|
|
222
|
-
|
279
|
+
#### Step 4: Update Plugins
|
223
280
|
|
224
281
|
- Replace plugins with Rspack alternatives (see table above)
|
225
282
|
- Remove incompatible plugins
|
226
283
|
- Add Rspack-specific plugins as needed
|
227
284
|
|
228
|
-
|
285
|
+
#### Step 5: TypeScript Setup
|
229
286
|
|
230
287
|
1. Add `isolatedModules: true` to `tsconfig.json`
|
231
288
|
2. Optional: Add `ts-checker-rspack-plugin` for type checking
|
232
289
|
|
233
|
-
|
290
|
+
#### Step 6: Test Your Build
|
234
291
|
|
235
292
|
```bash
|
236
293
|
# Development build
|
@@ -240,26 +297,285 @@ bin/shakapacker
|
|
240
297
|
bin/shakapacker --mode production
|
241
298
|
```
|
242
299
|
|
300
|
+
#### Step 7: Review Migration Checklist
|
301
|
+
|
302
|
+
- [ ] Install Rspack dependencies
|
303
|
+
- [ ] Update `config/shakapacker.yml`
|
304
|
+
- [ ] Create `config/rspack/rspack.config.js`
|
305
|
+
- [ ] Replace incompatible plugins
|
306
|
+
- [ ] Update TypeScript config (add `isolatedModules: true`)
|
307
|
+
- [ ] Convert file loaders to asset modules
|
308
|
+
- [ ] Test development build
|
309
|
+
- [ ] Test production build
|
310
|
+
- [ ] Run test suite
|
311
|
+
- [ ] Update CI/CD pipelines
|
312
|
+
- [ ] Deploy to staging
|
313
|
+
- [ ] Monitor performance improvements
|
314
|
+
|
315
|
+
## Configuration Best Practices
|
316
|
+
|
317
|
+
### Configuration Organization
|
318
|
+
|
319
|
+
**Recommended approach**: Keep webpack and rspack configs in the same directory with conditional logic:
|
320
|
+
|
321
|
+
```javascript
|
322
|
+
// config/webpack/webpack.config.js (works for both bundlers)
|
323
|
+
const { config } = require("shakapacker")
|
324
|
+
const bundler =
|
325
|
+
config.assets_bundler === "rspack"
|
326
|
+
? require("@rspack/core")
|
327
|
+
: require("webpack")
|
328
|
+
|
329
|
+
// Use for plugins
|
330
|
+
clientConfig.plugins.push(
|
331
|
+
new bundler.ProvidePlugin({
|
332
|
+
/* ... */
|
333
|
+
})
|
334
|
+
)
|
335
|
+
|
336
|
+
serverConfig.plugins.unshift(
|
337
|
+
new bundler.optimize.LimitChunkCountPlugin({ maxChunks: 1 })
|
338
|
+
)
|
339
|
+
```
|
340
|
+
|
341
|
+
**Avoid**: Creating separate `config/rspack/` directory unless configs diverge significantly.
|
342
|
+
|
343
|
+
**Benefits**:
|
344
|
+
|
345
|
+
- Smaller diff when comparing configurations
|
346
|
+
- Easy to see what's different between bundlers
|
347
|
+
- Single source of truth for webpack/rspack config
|
348
|
+
- Easier maintenance and debugging
|
349
|
+
|
350
|
+
### CSS Modules Configuration Placement
|
351
|
+
|
352
|
+
**Critical**: CSS modules configuration overrides must be inside the config function:
|
353
|
+
|
354
|
+
```javascript
|
355
|
+
// ✅ CORRECT - Inside function (applied fresh each time)
|
356
|
+
const commonWebpackConfig = () => {
|
357
|
+
const baseConfig = generateWebpackConfig()
|
358
|
+
|
359
|
+
baseConfig.module.rules.forEach((rule) => {
|
360
|
+
// Override CSS modules here
|
361
|
+
})
|
362
|
+
|
363
|
+
return merge({}, baseConfig, commonOptions)
|
364
|
+
}
|
365
|
+
|
366
|
+
// ❌ INCORRECT - Outside function (may not apply consistently)
|
367
|
+
const baseConfig = generateWebpackConfig()
|
368
|
+
baseConfig.module.rules.forEach((rule) => {
|
369
|
+
// This may not work correctly
|
370
|
+
})
|
371
|
+
```
|
372
|
+
|
373
|
+
### Handling Breaking Changes
|
374
|
+
|
375
|
+
When upgrading to Shakapacker 9 with Rspack:
|
376
|
+
|
377
|
+
1. **CSS Modules default exports → named exports**: This is a breaking change. Either:
|
378
|
+
- Update your code to use named imports (recommended for new projects)
|
379
|
+
- Override the configuration to keep default exports (easier for existing large codebases)
|
380
|
+
|
381
|
+
2. **Document your decisions**: Add comments explaining why you chose a particular configuration approach
|
382
|
+
|
383
|
+
3. **Create patches for broken dependencies**: If ReScript or other compiled-to-JS dependencies are missing build configs, use `patch-package` and file upstream issues
|
384
|
+
|
385
|
+
### Common Pitfalls to Avoid
|
386
|
+
|
387
|
+
1. **Don't commit generated files**: Check your `.gitignore` for files that should not be committed (e.g., `i18n/translations.js`)
|
388
|
+
2. **Update lockfiles**: Always run your package manager after adding dependencies (especially `patch-package`)
|
389
|
+
3. **Test with frozen lockfile**: Ensure your CI runs with `--frozen-lockfile` or equivalent to catch lockfile issues
|
390
|
+
4. **Check Node version compatibility**: Verify your Node version meets all dependency requirements
|
391
|
+
5. **Don't make empty commits**: If CI fails but local passes, investigate the root cause - don't try to "trigger CI re-run" with empty commits
|
392
|
+
|
243
393
|
## Common Issues and Solutions
|
244
394
|
|
395
|
+
### Issue: CSS Modules Returning Undefined (CRITICAL)
|
396
|
+
|
397
|
+
**Error:** `Cannot read properties of undefined (reading 'className')` in SSR or `export 'default' (imported as 'css') was not found`
|
398
|
+
|
399
|
+
**Root Cause:** Shakapacker 9 changed the default CSS Modules configuration to use named exports (`namedExport: true`), which is a breaking change from v8's default export behavior.
|
400
|
+
|
401
|
+
**Solution:** If you want to keep the v8 default export behavior, override the CSS loader configuration:
|
402
|
+
|
403
|
+
```javascript
|
404
|
+
// config/webpack/commonWebpackConfig.js (or rspack equivalent)
|
405
|
+
const { generateWebpackConfig, merge } = require("shakapacker")
|
406
|
+
|
407
|
+
const commonWebpackConfig = () => {
|
408
|
+
const baseWebpackConfig = generateWebpackConfig()
|
409
|
+
|
410
|
+
// Override CSS modules to use default exports for backward compatibility
|
411
|
+
baseWebpackConfig.module.rules.forEach((rule) => {
|
412
|
+
if (rule.use && Array.isArray(rule.use)) {
|
413
|
+
const cssLoader = rule.use.find((loader) => {
|
414
|
+
const loaderName = typeof loader === "string" ? loader : loader?.loader
|
415
|
+
return loaderName?.includes("css-loader")
|
416
|
+
})
|
417
|
+
|
418
|
+
if (cssLoader?.options?.modules) {
|
419
|
+
cssLoader.options.modules.namedExport = false
|
420
|
+
cssLoader.options.modules.exportLocalsConvention = "camelCase"
|
421
|
+
}
|
422
|
+
}
|
423
|
+
})
|
424
|
+
|
425
|
+
return merge({}, baseWebpackConfig, commonOptions)
|
426
|
+
}
|
427
|
+
```
|
428
|
+
|
429
|
+
**Important:** This configuration must be inside the function so it applies to fresh config each time.
|
430
|
+
|
431
|
+
See [CSS Modules Export Mode](./css-modules-export-mode.md) for detailed migration guidance.
|
432
|
+
|
433
|
+
### Issue: Server-Side Rendering CSS Extraction (CRITICAL for SSR)
|
434
|
+
|
435
|
+
**Error:** Intermittent failures with `Cannot read properties of undefined (reading 'className')` or flaky tests
|
436
|
+
|
437
|
+
**Root Cause:** When configuring server bundles, the code that removes CSS extraction loaders must handle both webpack and Rspack loader paths. Rspack uses `cssExtractLoader.js` instead of `mini-css-extract-plugin`.
|
438
|
+
|
439
|
+
**Solution:** Update your server webpack config to filter both loader types:
|
440
|
+
|
441
|
+
```javascript
|
442
|
+
// config/webpack/serverWebpackConfig.js
|
443
|
+
rule.use = rule.use.filter((item) => {
|
444
|
+
let testValue
|
445
|
+
if (typeof item === "string") {
|
446
|
+
testValue = item
|
447
|
+
} else if (typeof item.loader === "string") {
|
448
|
+
testValue = item.loader
|
449
|
+
}
|
450
|
+
// Handle both Webpack and Rspack CSS extract loaders
|
451
|
+
return !(
|
452
|
+
testValue?.match(/mini-css-extract-plugin/) ||
|
453
|
+
testValue?.includes("cssExtractLoader") || // Rspack loader path!
|
454
|
+
testValue === "style-loader"
|
455
|
+
)
|
456
|
+
})
|
457
|
+
```
|
458
|
+
|
459
|
+
**Additional SSR Requirement:** When modifying CSS modules options for SSR, use spread operator to preserve common config:
|
460
|
+
|
461
|
+
```javascript
|
462
|
+
if (cssLoader && cssLoader.options && cssLoader.options.modules) {
|
463
|
+
// Preserve existing modules config but add exportOnlyLocals for SSR
|
464
|
+
cssLoader.options.modules = {
|
465
|
+
...cssLoader.options.modules, // Preserve namedExport and other settings!
|
466
|
+
exportOnlyLocals: true
|
467
|
+
}
|
468
|
+
}
|
469
|
+
```
|
470
|
+
|
471
|
+
### Issue: SWC React Runtime with SSR
|
472
|
+
|
473
|
+
**Error:** `Invalid call to renderToString. Possibly you have a renderFunction...`
|
474
|
+
|
475
|
+
**Root Cause:** React on Rails SSR detection logic expects a specific function signature that may not work with SWC's automatic React runtime.
|
476
|
+
|
477
|
+
**Solution:** Use classic React runtime in your SWC configuration:
|
478
|
+
|
479
|
+
```javascript
|
480
|
+
// config/swc.config.js
|
481
|
+
const customConfig = {
|
482
|
+
options: {
|
483
|
+
jsc: {
|
484
|
+
transform: {
|
485
|
+
react: {
|
486
|
+
runtime: "classic", // Changed from 'automatic' for SSR compatibility
|
487
|
+
refresh: env.isDevelopment && env.runningWebpackDevServer
|
488
|
+
}
|
489
|
+
}
|
490
|
+
}
|
491
|
+
}
|
492
|
+
}
|
493
|
+
```
|
494
|
+
|
495
|
+
### Issue: ReScript Module Resolution
|
496
|
+
|
497
|
+
**Error:** `Module not found: Can't resolve './Actions.bs.js'`
|
498
|
+
|
499
|
+
**Solution:** Add `.bs.js` to your resolve extensions:
|
500
|
+
|
501
|
+
```javascript
|
502
|
+
const commonOptions = {
|
503
|
+
resolve: {
|
504
|
+
extensions: [".css", ".ts", ".tsx", ".bs.js"] // Add .bs.js for ReScript
|
505
|
+
}
|
506
|
+
}
|
507
|
+
```
|
508
|
+
|
509
|
+
### Issue: ReScript Dependencies Missing Compiled Files
|
510
|
+
|
511
|
+
**Error:** `Module not found: Can't resolve '@some-package/src/Module.bs.js'`
|
512
|
+
|
513
|
+
**Root Cause:** Some ReScript packages ship only `.res` source files without compiled `.bs.js` files, or have broken `bsconfig.json` configurations.
|
514
|
+
|
515
|
+
**Solution:** Use `patch-package` to fix the dependency:
|
516
|
+
|
517
|
+
1. Install patch-package:
|
518
|
+
|
519
|
+
```bash
|
520
|
+
npm install --save-dev patch-package
|
521
|
+
```
|
522
|
+
|
523
|
+
2. Add postinstall script to `package.json`:
|
524
|
+
|
525
|
+
```json
|
526
|
+
{
|
527
|
+
"scripts": {
|
528
|
+
"postinstall": "patch-package"
|
529
|
+
}
|
530
|
+
}
|
531
|
+
```
|
532
|
+
|
533
|
+
3. Fix the package's `bsconfig.json` (example for a package missing `package-specs`):
|
534
|
+
|
535
|
+
```json
|
536
|
+
{
|
537
|
+
"name": "@package/name",
|
538
|
+
"sources": ["src"],
|
539
|
+
"package-specs": [
|
540
|
+
{
|
541
|
+
"module": "esmodule",
|
542
|
+
"in-source": true
|
543
|
+
}
|
544
|
+
],
|
545
|
+
"suffix": ".bs.js"
|
546
|
+
}
|
547
|
+
```
|
548
|
+
|
549
|
+
4. Generate the patch:
|
550
|
+
|
551
|
+
```bash
|
552
|
+
npx patch-package @package/name
|
553
|
+
```
|
554
|
+
|
555
|
+
5. Consider filing an issue with the upstream package maintainer.
|
556
|
+
|
245
557
|
### Issue: LimitChunkCountPlugin Error
|
246
558
|
|
247
559
|
**Error:** `Cannot read properties of undefined (reading 'tap')`
|
560
|
+
|
248
561
|
**Solution:** Remove `webpack.optimize.LimitChunkCountPlugin` and use `splitChunks` configuration instead.
|
249
562
|
|
250
563
|
### Issue: Missing Loaders
|
251
564
|
|
252
565
|
**Error:** Module parse errors
|
566
|
+
|
253
567
|
**Solution:** Check console logs for skipped loaders and install missing dependencies.
|
254
568
|
|
255
569
|
### Issue: CSS Extraction
|
256
570
|
|
257
571
|
**Error:** CSS not being extracted properly
|
572
|
+
|
258
573
|
**Solution:** Use `rspack.CssExtractRspackPlugin` instead of `mini-css-extract-plugin`.
|
259
574
|
|
260
575
|
### Issue: TypeScript Errors
|
261
576
|
|
262
577
|
**Error:** TypeScript compilation errors
|
578
|
+
|
263
579
|
**Solution:** Ensure `isolatedModules: true` is set in `tsconfig.json`.
|
264
580
|
|
265
581
|
## Performance Tips
|
@@ -269,6 +585,16 @@ bin/shakapacker --mode production
|
|
269
585
|
3. **Enable Caching:** Rspack has built-in persistent caching
|
270
586
|
4. **Use SWC:** The built-in SWC loader is significantly faster than Babel
|
271
587
|
|
588
|
+
**Expected Performance Improvements:**
|
589
|
+
|
590
|
+
| Build Type | Webpack | Rspack | Improvement |
|
591
|
+
| ---------------- | ------- | ------ | ----------- |
|
592
|
+
| Cold build | 60s | 8s | 7.5x faster |
|
593
|
+
| Hot reload | 3s | 0.5s | 6x faster |
|
594
|
+
| Production build | 120s | 15s | 8x faster |
|
595
|
+
|
596
|
+
**Note:** Actual improvements vary based on project size, configuration, and hardware. Rspack's Rust-based architecture provides consistent 5-10x performance gains across most scenarios.
|
597
|
+
|
272
598
|
## Debugging Configuration
|
273
599
|
|
274
600
|
To compare your webpack and rspack configurations during migration:
|
@@ -302,4 +628,5 @@ See the [Troubleshooting Guide](./troubleshooting.md#exporting-webpack--rspack-c
|
|
302
628
|
- [Rspack Documentation](https://rspack.rs)
|
303
629
|
- [Rspack Examples](https://github.com/rspack-contrib/rspack-examples)
|
304
630
|
- [Awesome Rspack](https://github.com/rspack-contrib/awesome-rspack)
|
305
|
-
- [Migration Guide](https://rspack.rs/guide/migration/webpack)
|
631
|
+
- [Rspack Migration Guide](https://rspack.rs/guide/migration/webpack)
|
632
|
+
- [Real-world Migration Example](https://github.com/shakacode/react-webpack-rails-tutorial/pull/680) - Complete migration from webpack to Rspack with SSR, CSS Modules, and ReScript
|
data/docs/sprockets.md
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
If you are still using Sprockets for some of your assets, you might want to include files from `node_modules` directory in your asset pipeline. This is useful, for example, if you want to reference a stylesheet from a node package in your `.scss` stylesheet.
|
6
6
|
|
7
7
|
In order to enable this, make sure you add `node_modules` to the asset load path by adding the following in an initializer (for example `config/initializers/assets.rb`)
|
8
|
+
|
8
9
|
```ruby
|
9
10
|
Rails.application.config.assets.paths << Rails.root.join('node_modules')
|
10
11
|
```
|
@@ -21,15 +21,15 @@ style-loader is how you are probably are used to serving CSS in development with
|
|
21
21
|
|
22
22
|
### benefits
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
- No [Flash Of Unstyled Content (FOUC)](https://en.wikipedia.org/wiki/Flash_of_unstyled_content) on HMR refreshes
|
25
|
+
- Smaller/faster incremental updates.
|
26
26
|
|
27
27
|
### drawbacks
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
- Inflated JS deliverable size; requires JS execution before CSS is available
|
30
|
+
- FOUC on initial page load
|
31
|
+
- Adds an extra dependency
|
32
|
+
- Divergence in delivery mechanism from production
|
33
33
|
|
34
34
|
## Why would I pick mini-css-extract-plugin?
|
35
35
|
|
@@ -37,12 +37,12 @@ mini-css-extract-plugin's behavior is much more true to a production deployment'
|
|
37
37
|
|
38
38
|
### benefits
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
- Required for production, so it's going to be in play anyhow. Using only it simplifies the config and eliminates the style-loader dependency.
|
41
|
+
- No FOUC on initial page loads
|
42
|
+
- CSS delivered via `<link>` tags matches the mechanism used in production (I have been guilty of omitting my `stylesheet_pack_tag` for my first deploy because CSS worked fine with just the `javascript_pack_tag` in development.)
|
43
43
|
|
44
44
|
### drawbacks
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
- Invokes a separate HTTP request, compared to style-loader
|
47
|
+
- Potential for FOUC on HMR refreshes
|
48
|
+
- More data transferred per refresh (full stylesheet reload, rather than just an incremental patch). Not likely to be noticed for local development, but still a technical difference. This may only be the case [when you're using local CSS modules](https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/src/hmr/hotModuleReplacement.js#L267-L273).
|
@@ -1,13 +1,16 @@
|
|
1
1
|
# Subresource integrity
|
2
|
+
|
2
3
|
It's a cryptographic hash that helps browsers check that the served js or css file has not been tampered in any way.
|
3
4
|
|
4
5
|
[MDN - Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)
|
5
6
|
|
6
7
|
## Important notes
|
8
|
+
|
7
9
|
- If you somehow modify the file after the hash was generated, it will automatically be considered as tampered, and the browser will not allow it to be executed.
|
8
10
|
- Enabling subresource integrity generation, will change the structure of `manifest.json`. Keep that in mind if you utilize this file in any other custom implementation.
|
9
11
|
|
10
12
|
Before:
|
13
|
+
|
11
14
|
```json
|
12
15
|
{
|
13
16
|
"application.js": "/path_to_asset"
|
@@ -15,6 +18,7 @@ Before:
|
|
15
18
|
```
|
16
19
|
|
17
20
|
After:
|
21
|
+
|
18
22
|
```json
|
19
23
|
{
|
20
24
|
"application.js": {
|
@@ -25,6 +29,7 @@ After:
|
|
25
29
|
```
|
26
30
|
|
27
31
|
## Possible CORS issues
|
32
|
+
|
28
33
|
Enabling subresource integrity for an asset, actually enforces CORS checks on that resource too. Which means that
|
29
34
|
if you haven't set that up properly beforehand, it will probably lead to CORS errors with cached assets.
|
30
35
|
|
@@ -36,19 +41,20 @@ By default, this setting is disabled, to ensure backwards compatibility, and let
|
|
36
41
|
This may change in the future, as it is a very nice security feature, and it should be enabled by default.
|
37
42
|
|
38
43
|
To enable it, just add this in `shakapacker.yml`
|
44
|
+
|
39
45
|
```yml
|
40
|
-
|
41
|
-
|
46
|
+
integrity:
|
47
|
+
enabled: true
|
42
48
|
```
|
43
49
|
|
44
|
-
For further customization, you can also utilize the options `hash_functions` that control the functions used to generate
|
50
|
+
For further customization, you can also utilize the options `hash_functions` that control the functions used to generate
|
45
51
|
integrity hashes. And `cross_origin` that sets the cross-origin loading attribute.
|
46
52
|
|
47
53
|
```yml
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
54
|
+
integrity:
|
55
|
+
enabled: true
|
56
|
+
hash_functions: ["sha256", "sha384", "sha512"]
|
57
|
+
cross_origin: "anonymous" # or "use-credentials"
|
52
58
|
```
|
53
59
|
|
54
60
|
This will utilize under the hood webpack-subresource-integrity plugin and will modify `manifest.json` to include integrity hashes.
|