-
Notifications
You must be signed in to change notification settings - Fork 380
Update to Shakapacker 9.1.0 and migrate to Rspack #680
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Upgraded shakapacker from 9.0.0-beta.8 to 9.1.0 stable release - Configured Shakapacker to use Rspack as the bundler instead of webpack - Installed required Rspack dependencies (@rspack/core, @rspack/cli, rspack-manifest-plugin) - Created new Rspack configuration files in config/rspack/ mirroring the webpack structure - Migrated all webpack configurations to Rspack-compatible format - Updated shakapacker.yml to set assets_bundler to rspack - Regenerated Shakapacker binstubs for Rspack support - Successfully tested build process with Rspack showing 2-10x faster performance The Rspack migration maintains full compatibility with the existing webpack configuration while providing significantly faster build times. All configurations for client bundles, server bundles, development, production, and test environments have been migrated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
WalkthroughAdds Rspack support and configs, upgrades Shakapacker to 9.1.0 and updates its CLI invocation, composes environment-aware Rspack client/server configs (dev/prod/test), adds aliasing and client/server config adjustments, introduces simple i18n defaults/translations, updates package/Gem dependencies, and changes SWC React runtime to classic. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Env as NODE_ENV / Flags
participant RspackCfg as config/rspack/rspack.config.js
participant Composer as config/rspack/rspackConfig.js
participant Client as clientRspackConfig()
participant Server as serverRspackConfig()
Env->>RspackCfg: resolve env-specific file or fallback
RspackCfg->>Composer: load composer
Composer->>Client: build client config
Composer->>Server: build server config
Note over Client,Server: envSpecific hook may mutate configs (dev/prod/test)
alt WEBPACK_SERVE or CLIENT_BUNDLE_ONLY
Composer-->>RspackCfg: return Client only
else SERVER_BUNDLE_ONLY
Composer-->>RspackCfg: return Server only
else
Composer-->>RspackCfg: return [Client, Server]
end
sequenceDiagram
autonumber
participant CLI as bin/shakapacker
participant Runner as Shakapacker::Runner
CLI->>Runner: run(ARGV) with APP_ROOT
Note over Runner: Runner replaces previous WebpackRunner invocation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🚀 Quick Review App CommandsWelcome! Here are the commands you can use in this PR:
|
Pull Request Review: Shakapacker 9.1.0 & Rspack MigrationSummaryThis PR upgrades Shakapacker from 9.0.0-beta.8 to 9.1.0 stable and migrates the bundler from webpack to Rspack. Overall, this is a well-executed migration with proper configuration structure. Below are my findings: ✅ Strengths
|
These files are required by the application but were missing from the repository. Created default locale and translation stubs to enable SSR bundles to build successfully. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (2)
config/rspack/serverRspackConfig.js (2)
1-6
: LGTM! Consider reordering imports.The imports are correct and provide all necessary dependencies.
Based on coding guidelines, consider moving the
@rspack/core
import before the relative import:const path = require('path'); const { config } = require('shakapacker'); -const commonRspackConfig = require('./commonRspackConfig'); - const rspack = require('@rspack/core'); +const commonRspackConfig = require('./commonRspackConfig');
67-103
: Extract duplicate css-loader finding logic.The logic for finding css-loader (lines 84-94) is duplicated from
commonRspackConfig.js
(lines 55-58).Consider extracting this into a shared utility function:
Create a new file
config/rspack/utils.js
:const findCssLoader = (ruleUse) => { return ruleUse.find((item) => { const testValue = typeof item === 'string' ? item : item?.loader; return testValue?.includes('css-loader'); }); }; module.exports = { findCssLoader };Then use it in both files:
+const { findCssLoader } = require('./utils'); + const rules = serverRspackConfig.module.rules; rules.forEach((rule) => { if (Array.isArray(rule.use)) { // remove the mini-css-extract-plugin and style-loader rule.use = rule.use.filter((item) => { let testValue; if (typeof item === 'string') { testValue = item; } else if (typeof item.loader === 'string') { testValue = item.loader; } return !(testValue.match(/mini-css-extract-plugin/) || testValue === 'style-loader'); }); - const cssLoader = rule.use.find((item) => { - let testValue; - - if (typeof item === 'string') { - testValue = item; - } else if (typeof item.loader === 'string') { - testValue = item.loader; - } - - return testValue.includes('css-loader'); - }); + const cssLoader = findCssLoader(rule.use); if (cssLoader && cssLoader.options) { cssLoader.options.modules = { exportOnlyLocals: true }; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
Gemfile.lock
is excluded by!**/*.lock
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (15)
Gemfile
(1 hunks)bin/shakapacker
(1 hunks)client/app/libs/i18n/default.js
(1 hunks)client/app/libs/i18n/translations.js
(1 hunks)config/rspack/alias.js
(1 hunks)config/rspack/clientRspackConfig.js
(1 hunks)config/rspack/commonRspackConfig.js
(1 hunks)config/rspack/development.js
(1 hunks)config/rspack/production.js
(1 hunks)config/rspack/rspack.config.js
(1 hunks)config/rspack/rspackConfig.js
(1 hunks)config/rspack/serverRspackConfig.js
(1 hunks)config/rspack/test.js
(1 hunks)config/shakapacker.yml
(1 hunks)package.json
(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
config/rspack/test.js (3)
config/rspack/development.js (2)
rspackConfig
(5-5)require
(3-3)config/rspack/production.js (1)
rspackConfig
(3-3)config/rspack/rspackConfig.js (1)
rspackConfig
(4-32)
config/rspack/rspackConfig.js (7)
config/rspack/commonRspackConfig.js (1)
require
(2-2)config/rspack/development.js (2)
require
(3-3)rspackConfig
(5-5)config/rspack/rspack.config.js (3)
require
(1-1)require
(2-2)require
(3-3)config/rspack/serverRspackConfig.js (2)
require
(2-2)serverRspackConfig
(12-12)config/rspack/production.js (1)
rspackConfig
(3-3)config/rspack/test.js (1)
rspackConfig
(3-3)config/rspack/clientRspackConfig.js (1)
clientConfig
(5-5)
config/rspack/production.js (3)
config/rspack/development.js (2)
rspackConfig
(5-5)require
(3-3)config/rspack/rspackConfig.js (1)
rspackConfig
(4-32)config/rspack/test.js (1)
rspackConfig
(3-3)
config/rspack/development.js (1)
config/rspack/rspackConfig.js (2)
rspackConfig
(4-32)clientRspackConfig
(1-1)
config/rspack/serverRspackConfig.js (3)
config/rspack/commonRspackConfig.js (3)
require
(2-2)commonRspackConfig
(69-69)cssLoader
(56-59)config/rspack/clientRspackConfig.js (2)
commonRspackConfig
(2-2)rspack
(1-1)config/rspack/rspackConfig.js (1)
serverRspackConfig
(2-2)
config/rspack/clientRspackConfig.js (3)
config/rspack/serverRspackConfig.js (3)
rspack
(5-5)require
(2-2)commonRspackConfig
(3-3)config/rspack/commonRspackConfig.js (2)
require
(2-2)commonRspackConfig
(69-69)config/rspack/rspackConfig.js (1)
clientConfig
(5-5)
config/rspack/rspack.config.js (1)
config/rspack/commonRspackConfig.js (1)
require
(2-2)
config/rspack/commonRspackConfig.js (4)
config/rspack/development.js (1)
require
(3-3)config/rspack/rspack.config.js (3)
require
(1-1)require
(2-2)require
(3-3)config/rspack/serverRspackConfig.js (2)
require
(2-2)commonRspackConfig
(3-3)config/rspack/clientRspackConfig.js (1)
commonRspackConfig
(2-2)
🪛 ESLint
config/rspack/serverRspackConfig.js
[error] 5-5: @rspack/core
import should occur before import of ./commonRspackConfig
(import/order)
[error] 32-32: Assignment to property of function parameter 'loader'.
(no-param-reassign)
[error] 71-71: Use object destructuring.
(prefer-destructuring)
[error] 75-75: Assignment to property of function parameter 'rule'.
(no-param-reassign)
[error] 101-101: Assignment to property of function parameter 'rule'.
(no-param-reassign)
config/rspack/rspack.config.js
[error] 9-9: Calls to require() should use string literals
(import/no-dynamic-require)
[error] 9-9: Unexpected require().
(global-require)
config/rspack/commonRspackConfig.js
[error] 23-24: Replace (config)·=>⏎·
with ⏎··(config)·=>
(prettier/prettier)
[error] 45-45: Insert ,
(prettier/prettier)
[error] 46-46: Insert ,
(prettier/prettier)
🔇 Additional comments (16)
config/rspack/alias.js (1)
1-9
: LGTM!The alias configuration correctly maps
Assets
to the client assets directory usingpath.resolve
for cross-platform compatibility.client/app/libs/i18n/default.js (1)
1-9
: LGTM!The default locale and messages are clearly defined. This provides a solid foundation for the i18n setup.
package.json (1)
94-94
: LGTM!The dependency updates correctly reflect the migration to Rspack and the Shakapacker upgrade to 9.1.0 stable. The Rspack packages are appropriately placed in
devDependencies
, and version ranges are consistent with the latest releases.Also applies to: 111-112, 142-142
Gemfile (2)
6-6
: Verify the Ruby version downgrade is intentional.The Ruby version was changed from
3.4.6
to3.4.3
, which is a downgrade. Typically, Ruby versions are upgraded to get the latest patches and security fixes. Please confirm this change is intentional (e.g., to match a production or CI environment constraint) and not a mistake.
9-9
: LGTM!The Shakapacker gem upgrade to 9.1.0 stable aligns with the PR objectives and the corresponding npm package update.
config/rspack/test.js (1)
1-5
: LGTM!The test configuration correctly sets
NODE_ENV
to 'test' and exports the result ofrspackConfig()
. This is consistent with the pattern used in the development and production configurations.config/shakapacker.yml (1)
12-12
: LGTM!The
assets_bundler: rspack
configuration correctly instructs Shakapacker to use Rspack instead of webpack. This is the key setting that enables the bundler migration described in the PR objectives.config/rspack/rspack.config.js (2)
5-13
: Dynamic require pattern is appropriate here.The dynamic
require()
on Line 9 enables environment-specific configuration overrides, which is a common and practical pattern for build tooling. ESLint flags this as a potential issue, but the code includes anexistsSync
check to ensure safety.If you'd like to silence the ESLint warnings, you can add an inline comment:
const envSpecificConfig = () => { const path = resolve(__dirname, `${env.nodeEnv}.js`); if (existsSync(path)) { console.log(`Loading ENV specific rspack configuration file ${path}`); + // eslint-disable-next-line import/no-dynamic-require, global-require return require(path); }
1-15
: LGTM!The configuration entry point correctly loads environment-specific configs when available and falls back to
generateWebpackConfig()
otherwise. This provides flexibility while maintaining a sensible default.config/rspack/serverRspackConfig.js (7)
7-12
: LGTM!The comment clearly explains the mutability concern and why creating a fresh config object is necessary. This approach correctly prevents unintended modifications to the shared common config.
14-23
: LGTM!The server entry validation is correct with a clear error message that guides developers on what's needed.
25-42
: LGTM!The server bundle configuration correctly:
- Assigns the single server entry
- Removes mini-css-extract-plugin from loaders (server doesn't emit CSS)
- Disables code splitting with
LimitChunkCountPlugin
- Sets
minimize: false
for optimization
44-56
: LGTM!The output configuration is appropriate for SSR:
- Single bundle file
server-bundle.js
inssr-generated/
directory- Sets
globalObject: 'this'
for correct server-side execution- Includes helpful comment about React on Rails Pro's
libraryTarget: 'commonjs2'
option
58-65
: LGTM! Plugin filtering is appropriate.The filtering correctly removes plugins unnecessary for server bundles:
WebpackAssetsManifest
(manifest handled by client build)MiniCssExtractPlugin
(CSS handled by client build)ForkTsCheckerWebpackPlugin
(type checking not needed for server bundle)
105-113
: LGTM!The devtool setting and target comment are appropriate:
eval
provides fast builds and good line numbers for SSR debugging- Helpful comment explains when to uncomment
target: 'node'
for React on Rails Pro
115-118
: LGTM!The module export is correct and follows the expected pattern for Shakapacker config functions.
export const translations = { | ||
en: { | ||
'app.name': 'React Webpack Rails Tutorial', | ||
'comment.form.name_label': 'Name', | ||
'comment.form.text_label': 'Text', | ||
'comment.form.submit': 'Submit', | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Eliminate code duplication with defaultMessages
.
The English translations here duplicate defaultMessages
from client/app/libs/i18n/default.js
. This violates the DRY principle and creates a maintenance burden—updating English text requires changes in two places.
Apply this refactor to import and reuse defaultMessages
:
+import { defaultMessages } from './default';
+
// Translation messages for different locales
export const translations = {
- en: {
- 'app.name': 'React Webpack Rails Tutorial',
- 'comment.form.name_label': 'Name',
- 'comment.form.text_label': 'Text',
- 'comment.form.submit': 'Submit',
- },
+ en: defaultMessages,
es: {
'app.name': 'Tutorial de React Webpack Rails',
'comment.form.name_label': 'Nombre',
'comment.form.text_label': 'Texto',
'comment.form.submit': 'Enviar',
},
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export const translations = { | |
en: { | |
'app.name': 'React Webpack Rails Tutorial', | |
'comment.form.name_label': 'Name', | |
'comment.form.text_label': 'Text', | |
'comment.form.submit': 'Submit', | |
}, | |
import { defaultMessages } from './default'; | |
// Translation messages for different locales | |
export const translations = { | |
en: defaultMessages, | |
es: { | |
'app.name': 'Tutorial de React Webpack Rails', | |
'comment.form.name_label': 'Nombre', | |
'comment.form.text_label': 'Texto', | |
'comment.form.submit': 'Enviar', | |
}, | |
}; |
🤖 Prompt for AI Agents
In client/app/libs/i18n/translations.js around lines 2 to 8, the English
translations duplicate strings from client/app/libs/i18n/default.js; import
defaultMessages from that file and reuse it rather than hardcoding the same keys
here (e.g., replace the inline en object with a spread/merge of defaultMessages
into translations.en), ensuring any additional or overridden keys remain after
the spread so updates live in one place.
config/rspack/commonRspackConfig.js
Outdated
const scssConfigIndex = baseClientRspackConfig.module.rules.findIndex((config) => | ||
'.scss'.match(config.test) && config.use, | ||
); | ||
|
||
if (scssConfigIndex === -1) { | ||
console.warn('No SCSS rule with use array found in rspack config'); | ||
} else { | ||
// Configure sass-loader to use the modern API | ||
const scssRule = baseClientRspackConfig.module.rules[scssConfigIndex]; | ||
const sassLoaderIndex = scssRule.use.findIndex((loader) => { | ||
if (typeof loader === 'string') { | ||
return loader.includes('sass-loader'); | ||
} | ||
return loader.loader && loader.loader.includes('sass-loader'); | ||
}); | ||
|
||
if (sassLoaderIndex !== -1) { | ||
const sassLoader = scssRule.use[sassLoaderIndex]; | ||
if (typeof sassLoader === 'string') { | ||
scssRule.use[sassLoaderIndex] = { | ||
loader: sassLoader, | ||
options: { | ||
api: 'modern' | ||
} | ||
}; | ||
} else { | ||
sassLoader.options = sassLoader.options || {}; | ||
sassLoader.options.api = 'modern'; | ||
} | ||
} | ||
|
||
// Fix css-loader configuration for CSS modules if namedExport is enabled | ||
// When namedExport is true, exportLocalsConvention must be camelCaseOnly or dashesOnly | ||
const cssLoader = scssRule.use.find((loader) => { | ||
const loaderName = typeof loader === 'string' ? loader : loader?.loader; | ||
return loaderName?.includes('css-loader'); | ||
}); | ||
|
||
if (cssLoader?.options?.modules?.namedExport) { | ||
cssLoader.options.modules.exportLocalsConvention = 'camelCaseOnly'; | ||
} | ||
|
||
baseClientRspackConfig.module.rules[scssConfigIndex].use.push(sassLoaderConfig); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix Prettier violations to unblock lint.
eslint --fix
fails here:
- Lines 23-24 need the multiline arrow formatting Prettier expects.
- Lines 45-46 are missing trailing commas.
These are hard errors, so bundles won’t build until the style issues are resolved.
🧰 Tools
🪛 ESLint
[error] 23-24: Replace (config)·=>⏎·
with ⏎··(config)·=>
(prettier/prettier)
[error] 45-45: Insert ,
(prettier/prettier)
[error] 46-46: Insert ,
(prettier/prettier)
🤖 Prompt for AI Agents
config/rspack/commonRspackConfig.js lines 23-66: Prettier is failing — change
the single-line arrow callback passed to findIndex into an explicit multiline
arrow function with braces and a return (so the function is formatted across
lines), and add missing trailing commas to the object literals you create when
replacing the sass-loader (ensure options: { api: 'modern', }, and the outer
object has a trailing comma as well) so the created objects conform to
Prettier's trailing-comma rules.
Pull Request Review: Update to Shakapacker 9.1.0 and migrate to RspackOverall AssessmentThis is a well-executed migration from webpack to Rspack with Shakapacker 9.1.0. The PR is comprehensive and maintains backward compatibility. The code quality is generally good, but there are a few areas that could be improved. ✅ Strengths
🔍 Code Quality IssuesCritical Issues1. Ruby Version Downgrade (Gemfile:6) -ruby "3.4.6"
+ruby "3.4.3" ❌ This is a concerning change. Why was the Ruby version downgraded from 3.4.6 to 3.4.3? This appears unrelated to the Rspack migration and could:
Recommendation: Revert this change or provide explicit justification in the PR description. High Priority Issues2. Missing Error Handling in Configuration Files
Recommendation: Add defensive checks: if (cssLoader?.options?.modules?.namedExport) {
if (!cssLoader.options.modules.exportLocalsConvention) {
cssLoader.options.modules.exportLocalsConvention = 'camelCaseOnly';
}
} 3. Potentially Unsafe CSS Loader Configuration
if (cssLoader && cssLoader.options) {
cssLoader.options.modules = { exportOnlyLocals: true };
} ❌ This overwrites the entire Recommendation: if (cssLoader && cssLoader.options) {
cssLoader.options.modules = {
...cssLoader.options.modules,
exportOnlyLocals: true
};
} 4. Incomplete Type Safety for Loader Checks
Recommendation: } else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) {
rule.use.options = rule.use.options || {};
rule.use.options.emitFile = false;
} Medium Priority Issues5. New i18n Files Appear Unused or Untested
Recommendation:
6. Hardcoded Path in sass-resources-loader
resources: './client/app/assets/styles/app-variables.scss',
Recommendation: const path = require('path');
// ...
resources: path.resolve(__dirname, '../../client/app/assets/styles/app-variables.scss'), 7. Missing Package Version Constraints
"@rspack/cli": "^1.5.8",
"@rspack/core": "^1.5.8",
Recommendation: Consider using exact versions or tilde ranges for more predictable builds, especially for a bundler migration. 🔒 Security ConsiderationsNo Critical Security Issues Found
Minor Concern: The ⚡ Performance ConsiderationsPositive:
Suggestions:
🧪 Test CoverageMissing Tests:
Recommendation: Add smoke tests that verify:
📝 DocumentationGood:
Missing:
🎯 Best PracticesWell Done:
Could Improve:
📊 SummaryApprove with Changes Requested This PR represents solid engineering work on a complex migration. However, the Ruby version downgrade is a blocker that needs explanation, and the CSS loader configuration issues could cause runtime problems. Required Changes:
Recommended Changes:
Nice to Have:
Great work on this migration! Once the critical issues are addressed, this will be a valuable improvement to the project. Review generated with Claude Code |
CI is configured to use Ruby 3.4.6, but Gemfile was accidentally set to 3.4.3 during local development. This was causing bundle install to fail in CI with exit code 18. Updated: - Gemfile: ruby 3.4.3 → 3.4.6 - Gemfile.lock: ruby 3.4.3p32 → 3.4.6p32 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Pull Request Review: Shakapacker 9.1.0 & Rspack MigrationSummaryThis PR successfully upgrades Shakapacker from beta to stable (9.1.0) and migrates from webpack to Rspack. The migration is well-structured and comprehensive. Overall, this is a solid PR with good attention to detail. Below are my findings across different review categories. ✅ Strengths1. Excellent Configuration Structure
2. Backward Compatibility
3. Modern Best Practices
|
The automatic React runtime was causing issues with React on Rails server-side rendering. Switching to classic runtime ensures compatibility with React on Rails SSR function detection. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Preserve namedExport and exportLocalsConvention settings when adding exportOnlyLocals for SSR. This prevents CSS module imports from being undefined in the server-rendered bundle. The previous code was replacing the entire modules object, which broke the namedExport configuration required by Shakapacker 9. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
config/rspack/serverRspackConfig.js (2)
5-5
: Consider reordering import for consistency.The
@rspack/core
import should come before local module imports per the import/order convention. As per static analysis hints.Apply this diff:
const path = require('path'); const { config } = require('shakapacker'); -const commonRspackConfig = require('./commonRspackConfig'); - const rspack = require('@rspack/core'); +const commonRspackConfig = require('./commonRspackConfig');
8-12
: Clarify the merge comment.The comment mentions using "merge," but this function doesn't call merge directly. The merge happens inside
commonRspackConfig()
(as seen in the relevant code snippet from line 68 of commonRspackConfig.js). Consider updating the comment to reflect this or removing it to avoid confusion.config/swc.config.js (1)
13-14
: Revise the JSX runtime comment for accuracy. React on Rails supports both the automatic and classic JSX transforms for SSR—as long as your server bundle can resolvereact/jsx-runtime
—so calling out “better SSR compatibility” is misleading. Either:
- Keep
runtime: 'classic'
but update the comment to explain you’re choosing classic to ensure React is in scope without bundlingreact/jsx-runtime
, or- Revert to
automatic
and configure your SSR build to include the new JSX runtime helpers.config/swc.config.js: lines 13–14
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
config/rspack/serverRspackConfig.js
(1 hunks)config/swc.config.js
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
config/rspack/serverRspackConfig.js (1)
config/rspack/commonRspackConfig.js (3)
require
(2-2)commonRspackConfig
(69-69)cssLoader
(56-59)
🪛 ESLint
config/rspack/serverRspackConfig.js
[error] 5-5: @rspack/core
import should occur before import of ./commonRspackConfig
(import/order)
[error] 32-32: Assignment to property of function parameter 'loader'.
(no-param-reassign)
[error] 71-71: Use object destructuring.
(prefer-destructuring)
[error] 75-75: Assignment to property of function parameter 'rule'.
(no-param-reassign)
[error] 105-105: Assignment to property of function parameter 'rule'.
(no-param-reassign)
🔇 Additional comments (5)
config/rspack/serverRspackConfig.js (5)
14-23
: LGTM!The validation for the required
server-bundle
entry is clear and provides a helpful error message if the entry is missing.
38-42
: LGTM!Disabling code splitting and minimization for the server bundle is appropriate for SSR builds.
44-56
: LGTM!The server output configuration correctly sets up the SSR bundle path and options. The commented
libraryTarget
hint is helpful for React on Rails Pro users.
58-65
: LGTM!Filtering out client-specific plugins (asset manifest, CSS extraction, TypeScript checking) is appropriate for the server bundle.
109-117
: LGTM!The
eval
devtool setting is a good choice for fast SSR builds with readable stack traces. The commented guidance about settingtarget: 'node'
for React on Rails Pro is helpful.
// Remove the mini-css-extract-plugin from the style loaders because | ||
// the client build will handle exporting CSS. | ||
// replace file-loader with null-loader | ||
serverRspackConfig.module.rules.forEach((loader) => { | ||
if (loader.use && loader.use.filter) { | ||
loader.use = loader.use.filter( | ||
(item) => !(typeof item === 'string' && item.match(/mini-css-extract-plugin/)), | ||
); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Remove duplicate mini-css-extract-plugin filtering.
This filtering logic is duplicated at lines 67-107, where it's handled more comprehensively along with other SSR-specific loader adjustments. The duplicate code reduces maintainability without adding value.
Apply this diff:
serverRspackConfig.entry = serverEntry;
- // Remove the mini-css-extract-plugin from the style loaders because
- // the client build will handle exporting CSS.
- // replace file-loader with null-loader
- serverRspackConfig.module.rules.forEach((loader) => {
- if (loader.use && loader.use.filter) {
- loader.use = loader.use.filter(
- (item) => !(typeof item === 'string' && item.match(/mini-css-extract-plugin/)),
- );
- }
- });
-
// No splitting of chunks for a server bundle
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// Remove the mini-css-extract-plugin from the style loaders because | |
// the client build will handle exporting CSS. | |
// replace file-loader with null-loader | |
serverRspackConfig.module.rules.forEach((loader) => { | |
if (loader.use && loader.use.filter) { | |
loader.use = loader.use.filter( | |
(item) => !(typeof item === 'string' && item.match(/mini-css-extract-plugin/)), | |
); | |
} | |
}); | |
serverRspackConfig.entry = serverEntry; | |
// No splitting of chunks for a server bundle |
🧰 Tools
🪛 ESLint
[error] 32-32: Assignment to property of function parameter 'loader'.
(no-param-reassign)
🤖 Prompt for AI Agents
In config/rspack/serverRspackConfig.js around lines 27 to 36, remove the
duplicate block that filters out mini-css-extract-plugin from loader.use — this
logic is already implemented comprehensively later (lines 67–107). Delete the
entire forEach that checks loader.use.filter and reassigns loader.use to the
filtered array so only the later SSR-specific loader adjustments remain,
ensuring no functional changes beyond removing the redundant duplicate.
} else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) { | ||
rule.use.options.emitFile = false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add null safety check for rule.use.options.
When rule.use
is an object (not an array), accessing rule.use.options.emitFile
without verifying that options
exists could cause a runtime error if a loader doesn't define options.
Apply this diff:
// Skip writing image files during SSR by setting emitFile to false
} else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) {
- rule.use.options.emitFile = false;
+ if (rule.use.options) {
+ rule.use.options.emitFile = false;
+ }
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
} else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) { | |
rule.use.options.emitFile = false; | |
} | |
// Skip writing image files during SSR by setting emitFile to false | |
} else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) { | |
if (rule.use.options) { | |
rule.use.options.emitFile = false; | |
} | |
} |
🧰 Tools
🪛 ESLint
[error] 105-105: Assignment to property of function parameter 'rule'.
(no-param-reassign)
🤖 Prompt for AI Agents
In config/rspack/serverRspackConfig.js around lines 104 to 106, the code sets
rule.use.options.emitFile without ensuring rule.use.options exists; update the
branch handling object-style rule.use to first ensure rule.use.options is
defined (e.g. if (!rule.use.options) rule.use.options = {}), then set
rule.use.options.emitFile = false so you avoid runtime errors when options is
undefined.
Pull Request Review: Shakapacker 9.1.0 & Rspack MigrationI've completed a comprehensive review of PR #680. Overall, this is a well-executed migration from webpack to Rspack with Shakapacker 9.1.0. Here's my detailed feedback: ✅ Strengths
🔍 Issues & ConcernsCritical: Potential Bug in CSS Modules ConfigurationLocation: if (cssLoader && cssLoader.options) {
cssLoader.options.modules = { exportOnlyLocals: true };
} Issue: This code overwrites the entire Impact: This could break CSS modules that rely on named exports or specific naming conventions. Recommendation: if (cssLoader && cssLoader.options && cssLoader.options.modules) {
cssLoader.options.modules = {
...cssLoader.options.modules,
exportOnlyLocals: true,
};
} Medium: Inconsistent CSS Loader HandlingLocation: The code checks for if (cssLoader?.options?.modules?.namedExport) {
cssLoader.options.modules.exportLocalsConvention = 'camelCaseOnly';
} Recommendation: Add a check to ensure if (cssLoader?.options?.modules) {
if (cssLoader.options.modules.namedExport) {
cssLoader.options.modules.exportLocalsConvention = 'camelCaseOnly';
}
} Low: Code Duplication in serverRspackConfig.jsLocation: Lines 30-36 and 72-82 The code filters out Recommendation: Consider consolidating this logic or adding a comment explaining why it's done in two places. 📝 Code Quality Suggestions
🔒 Security Assessment✅ No security concerns identified
🧪 Test CoverageObservations:
Recommendations:
⚡ Performance ConsiderationsPositive:
Consider:
🎯 Additional Observations
📋 SummaryApproval Status: ✅ Approve with minor fixes recommended This is a solid migration with good attention to detail. The main concern is the CSS modules configuration bug in
The performance benefits of Rspack and the thorough configuration work make this a valuable upgrade. Great work on maintaining backward compatibility! Review completed by: Claude Code |
Code Review: Update to Shakapacker 9.1.0 and Migrate to RspackSummaryThis PR successfully migrates from webpack to Rspack as the JavaScript bundler and upgrades Shakapacker from beta to stable. The migration is well-executed with comprehensive configuration files that mirror the webpack setup while taking advantage of Rspack-specific optimizations. ✅ Strengths1. Comprehensive Configuration Migration
2. Well-Documented Changes
3. SSR Compatibility Fixes
4. Proper Dependency Management
🔍 Issues & RecommendationsHigh Priority1. Missing File Path Validation (config/rspack/commonRspackConfig.js:15)The SCSS resources path is hardcoded without validation: resources: './client/app/assets/styles/app-variables.scss', Recommendation: Add path validation or use const path = require('path');
const fs = require('fs');
const appVariablesPath = path.resolve(__dirname, '../../client/app/assets/styles/app-variables.scss');
if (!fs.existsSync(appVariablesPath)) {
throw new Error(`SCSS variables file not found: ${appVariablesPath}`);
} 2. Mutable Global Object Mutation (config/rspack/commonRspackConfig.js:65, 69)The code mutates baseClientRspackConfig.module.rules[scssConfigIndex].use.push(sassLoaderConfig);
// ...
const commonRspackConfig = () => merge({}, baseClientRspackConfig, commonOptions, ignoreWarningsConfig); Issue: The comment on line 69 says "Copy the object using merge b/c the baseClientRspackConfig and commonOptions are mutable globals", but the config is already mutated on line 65 before the merge. Recommendation: Either:
3. Potential Null Reference (config/rspack/serverRspackConfig.js:104-106)} else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) {
rule.use.options.emitFile = false;
} Issue: No check for Fix: } else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) {
rule.use.options = rule.use.options || {};
rule.use.options.emitFile = false;
} Medium Priority4. Inconsistent Loader Finding Logic (config/rspack/commonRspackConfig.js:32-37 vs 56-59)The code uses two different patterns for finding loaders in the same file:
Recommendation: Standardize on one approach for consistency and maintainability. 5. Duplicate Code in serverRspackConfig.jsLines 27-36 and lines 67-83 both filter out Recommendation: Extract to a helper function: const removeStyleLoaders = (rules) => {
rules.forEach((loader) => {
if (loader.use && loader.use.filter) {
loader.use = loader.use.filter(
(item) => !(typeof item === 'string' && item.match(/mini-css-extract-plugin/)) && item !== 'style-loader'
);
}
});
}; 6. Hard-coded Plugin Names (config/rspack/serverRspackConfig.js:60-65)plugin.constructor.name !== 'WebpackAssetsManifest' &&
plugin.constructor.name !== 'MiniCssExtractPlugin' &&
plugin.constructor.name !== 'ForkTsCheckerWebpackPlugin' Issue: Constructor names can be minified in production builds, causing this filter to fail. Recommendation: Use Low Priority7. I18n Translation Files (client/app/libs/i18n/)The new translation files appear to be stub/placeholder data:
Recommendation:
8. Missing Error Handling (config/rspack/serverRspackConfig.js:19-23)if (!serverEntry['server-bundle']) {
throw new Error(
"Create a pack with the file name 'server-bundle.js' containing all the server rendering files",
);
} Enhancement: This error message could be more helpful by suggesting where to create the file: throw new Error(
"Server bundle entry 'server-bundle' not found. Create a pack at client/app/packs/server-bundle.js containing all server rendering files",
); 9. Ruby Version Patch Mismatch (Gemfile.lock)
The patch level changed from p54 to p32, which seems like a downgrade. This might be intentional but should be verified. 🔒 Security Considerations✅ No security issues identified
⚡ Performance Considerations✅ Performance improvements are excellent
Minor optimization: Consider adding build caching configuration in production.js for even better performance. 🧪 Test CoverageConcerns:
Recommendation: Consider adding integration tests that verify:
📝 Code QualityOverall: Good quality with room for improvement Positives:
Areas for improvement:
🎯 RecommendationAPPROVE with minor revisions This is a solid migration that maintains backward compatibility while providing significant performance benefits. The high-priority issues should be addressed to prevent potential runtime errors, but they don't block the merge given that the builds are passing. Before Merging:
Post-Merge:
Great work on this migration! The performance improvements will be very valuable for the development experience. 🤖 Generated with Claude Code |
Rspack needs explicit configuration to resolve ReScript compiled .bs.js files from node_modules dependencies. Without this, ReScript library imports like @glennsl/rescript-json-combinators fail to resolve. This is critical for React on Rails apps using ReScript components. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Pull Request Review: Shakapacker 9.1.0 & Rspack MigrationGreat work on this major infrastructure upgrade! This is a well-executed migration that brings significant performance improvements. Below is my detailed review: ✅ Strengths
|
The @glennsl/rescript-json-combinators package ships without compiled .bs.js files and its bsconfig.json lacks package-specs configuration. This causes module resolution failures when Rspack tries to import these files. Add patch-package to apply a fix that: - Removes reference to non-existent examples directory - Adds package-specs for ES module output - Configures .bs.js suffix for compiled files This ensures yarn res:build compiles the dependency correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
PR Review: Update to Shakapacker 9.1.0 and migrate to RspackSummaryThis PR successfully migrates from Shakapacker 9.0.0-beta.8 to 9.1.0 stable and transitions from webpack to Rspack as the bundler. The migration is well-structured with comprehensive configuration files and good iterative fixes for edge cases. ✅ Strengths1. Excellent Migration Approach
2. Thorough Edge Case Handling
3. Performance Benefits
|
- Remove postinstall-postinstall dependency (causes engine check issues) - Regenerate patch file using patch-package CLI for correct format - Update yarn.lock with patch-package dependency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Pull Request Review - Shakapacker 9.1.0 + Rspack MigrationOverall AssessmentThis is a well-executed migration from Webpack to Rspack with a Shakapacker upgrade. The PR demonstrates thorough testing and maintains backward compatibility. The migration is significant and provides clear performance benefits. ✅ Strengths1. Excellent Code Organization
2. Comprehensive ConfigurationThe Rspack configs properly handle:
3. Performance Improvements
4. Testing
|
Shakapacker 9 changed CSS modules default to namedExport: true, but the existing ReScript code expects default exports (import css from). Changes: - Set namedExport: false for all CSS loaders - Change exportLocalsConvention from camelCaseOnly to camelCase - Apply fix to all CSS-related rules, not just SCSS This resolves SSR errors: "Cannot read properties of undefined (reading 'elementEnter')" in ReScript components. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Pull Request Review: Shakapacker 9.1.0 & Rspack MigrationOverall AssessmentThis is a well-executed migration that upgrades Shakapacker from beta to stable and successfully migrates from webpack to Rspack. The implementation is thorough, follows best practices, and maintains backward compatibility. The PR demonstrates careful planning and testing. ✅ Strengths1. Excellent Configuration Architecture
2. Strong SSR Configuration
3. Backward Compatibility
4. Good Performance Optimizations
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
config/rspack/commonRspackConfig.js (1)
39-40
: Fix Prettier violations to unblock lint.The Prettier violations flagged in the previous review are still present:
- Lines 39-40: Arrow function needs multiline formatting
- Lines 61-62: Missing trailing commas
These are hard ESLint errors that will block the build.
Apply this diff to fix the formatting:
-const scssConfigIndex = baseClientRspackConfig.module.rules.findIndex((config) => - '.scss'.match(config.test) && config.use, +const scssConfigIndex = baseClientRspackConfig.module.rules.findIndex( + (config) => '.scss'.match(config.test) && config.use, );scssRule.use[sassLoaderIndex] = { loader: sassLoader, options: { - api: 'modern' - } + api: 'modern', + }, };Also applies to: 61-62
🧹 Nitpick comments (2)
config/rspack/commonRspackConfig.js (2)
39-41
: Consider more idiomatic regex matching pattern.The pattern
'.scss'.match(config.test)
works but is unconventional. The more idiomatic approach is to use the RegExp's.test()
method.Apply this diff to use the conventional pattern:
const scssConfigIndex = baseClientRspackConfig.module.rules.findIndex( - (config) => '.scss'.match(config.test) && config.use, + (config) => config.test?.test('.scss') && config.use, );
11-17
: Optional: Parameterize SCSS resource path
The SCSS variables file exists atclient/app/assets/styles/app-variables.scss
. Consider making this path configurable to avoid hardcoding environment-specific paths.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
config/rspack/commonRspackConfig.js
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
config/rspack/commonRspackConfig.js (4)
config/rspack/rspack.config.js (3)
require
(1-1)require
(2-2)require
(3-3)config/rspack/serverRspackConfig.js (2)
require
(2-2)commonRspackConfig
(3-3)config/webpack/commonWebpackConfig.js (1)
loaderName
(60-60)config/rspack/clientRspackConfig.js (1)
commonRspackConfig
(2-2)
🪛 ESLint
config/rspack/commonRspackConfig.js
[error] 39-40: Replace (config)·=>⏎·
with ⏎··(config)·=>
(prettier/prettier)
[error] 61-61: Insert ,
(prettier/prettier)
[error] 62-62: Insert ,
(prettier/prettier)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: claude-review
- GitHub Check: test (22.x, 3.4.6)
- GitHub Check: test (22.x, 3.4.6)
- GitHub Check: test (22.x, 3.4.6)
The previous fix modified baseClientRspackConfig at module load time, but generateWebpackConfig() returns a fresh config each time. Moving the CSS modules configuration inside the commonRspackConfig() function ensures the fix is applied every time the config is requested. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Pull Request Review: Shakapacker 9.1.0 and Rspack MigrationSummaryThis PR successfully upgrades Shakapacker from 9.0.0-beta.8 to 9.1.0 stable and migrates from webpack to Rspack as the JavaScript bundler. The migration is comprehensive with 10 commits addressing various compatibility issues discovered during the process. ✅ Strengths1. Thorough Configuration Migration
2. Good Problem-Solving Approach
3. Performance Benefits
🔍 Code Quality Issues1. CSS Modules Configuration (config/rspack/commonRspackConfig.js:28-40)Issue: The CSS loader mutation logic is fragile and could miss edge cases. baseClientRspackConfig.module.rules.forEach((rule) => {
if (rule.use && Array.isArray(rule.use)) {
const cssLoader = rule.use.find((loader) => {
const loaderName = typeof loader === 'string' ? loader : loader?.loader;
return loaderName?.includes('css-loader');
}); Concerns:
Recommendation: Add more specific matching and validation: const cssLoader = rule.use.find((loader) => {
const loaderName = typeof loader === 'string' ? loader : loader?.loader;
return loaderName && (loaderName === 'css-loader' || loaderName.endsWith('/css-loader'));
});
if (cssLoader?.options?.modules) {
cssLoader.options.modules.namedExport = false;
cssLoader.options.modules.exportLocalsConvention = 'camelCase';
console.log('Applied CSS modules fix for ReScript compatibility');
} 2. SCSS Config Index Search (config/rspack/commonRspackConfig.js:42-44)Issue: The logic for finding SCSS config is unclear: const scssConfigIndex = baseClientRspackConfig.module.rules.findIndex((config) =>
'.scss'.match(config.test) && config.use,
); Problem: Recommendation: const scssConfigIndex = baseClientRspackConfig.module.rules.findIndex((config) =>
config.test instanceof RegExp && config.test.test('.scss') && config.use,
); 3. Duplicate Code in serverRspackConfig.jsIssue: Lines 27-36 and 67-83 have duplicated logic for removing mini-css-extract-plugin. Recommendation: Extract to a helper function: function removeMiniCssExtractPlugin(rules) {
rules.forEach((rule) => {
if (rule.use && rule.use.filter) {
rule.use = rule.use.filter(
(item) => !(typeof item === 'string' && item.match(/mini-css-extract-plugin/))
);
}
});
} 4. Missing Error HandlingIssue: config/rspack/commonRspackConfig.js:46-47 logs a warning but continues execution: if (scssConfigIndex === -1) {
console.warn('No SCSS rule with use array found in rspack config');
} else {
// continues to mutate config
} Concern: If SCSS config isn't found, Recommendation: Consider throwing an error or at least adding more defensive checks. 🐛 Potential Bugs1. Missing Null Safety (serverRspackConfig.js:104)} else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) {
rule.use.options.emitFile = false;
} Issue: Fix: } else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) {
rule.use.options = rule.use.options || {};
rule.use.options.emitFile = false;
} 2. Hardcoded Path in sassLoaderConfigconfig/rspack/commonRspackConfig.js:14: resources: './client/app/assets/styles/app-variables.scss', Issue: Relative path that could break if config is loaded from different working directories. Recommendation: Use absolute paths: const path = require('path');
// ...
resources: path.resolve(__dirname, '../../client/app/assets/styles/app-variables.scss'), 🔒 Security Concerns1. patch-package DependencyObservation: Using Concerns:
Recommendations:
2. No Dependency Vulnerability Check ShownRecommendation: Run yarn audit ⚡ Performance Considerations1. DevTool Configuration for ProductionserverRspackConfig.js:112: serverRspackConfig.devtool = 'eval'; Issue: This is set unconditionally, even for production builds. Recommendation: Make it environment-aware: serverRspackConfig.devtool = process.env.NODE_ENV === 'production' ? false : 'eval'; 2. Console Statements in ProductionMultiple Recommendation: Use environment checks or a logger that can be disabled in production: const log = process.env.NODE_ENV === 'development' ? console.log : () => {}; 🧪 Test CoverageObservation: The PR description mentions testing:
Missing:
Recommendations:
📝 Documentation & Maintainability1. Missing Documentation for Breaking ChangesWhile the PR description says "no breaking changes," the CSS modules change from named exports to default exports IS a breaking change for new code. Recommendation: Add a MIGRATION.md or update README with:
2. Comment QualityGood: Comments explain why decisions were made (e.g., lines about React on Rails Pro) Could Improve: Some comments are outdated (e.g., "Copy the object using merge" on line 22 but the comment says "baseClientRspackConfig" when it should say the function returns a merged config) 🎯 Additional Recommendations1. Version Pinningpackage.json shows: "@rspack/cli": "^1.5.8",
"@rspack/core": "^1.5.8", Recommendation: Consider exact version pinning for critical infrastructure dependencies: "@rspack/cli": "1.5.8",
"@rspack/core": "1.5.8", 2. Gemfile.lock Ruby Version DiscrepancyThe Gemfile.lock shows: ruby 3.4.6p32 But Ruby 3.4.6p32 suggests a patch level that should be documented. Ensure this matches your CI/CD environment exactly. 3. webpack Config CleanupThe PR description mentions webpack configs remain in Recommendation: Either:
4. Consider Feature FlagsFor such a significant infrastructure change, consider adding a feature flag or environment variable to toggle between webpack and Rspack, allowing for easy rollback if issues arise in production. 🎬 ConclusionOverall Assessment: APPROVE with RecommendationsThis is a well-executed migration with clear benefits. The incremental approach to fixing issues shows good engineering practice. However, there are several quality and safety improvements that should be addressed: Priority Issues (Should Fix Before Merge):
Recommended Improvements (Should Address Soon):
Nice to Have:
Great work on this migration! The performance improvements will be significant. Let me know if you'd like me to elaborate on any of these points or if you have questions about the recommendations. Review generated with Claude Code - focusing on code quality, security, and maintainability 🤖 |
The server config was only checking for 'mini-css-extract-plugin' but Rspack uses 'cssExtractLoader.js'. This caused the CSS extract loader to remain in the server bundle, which breaks CSS modules exports in SSR. Added check for 'cssExtractLoader' to properly remove it from server bundle, ensuring CSS modules work correctly in server-side rendering. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
PR Review: Shakapacker 9.1.0 and Rspack MigrationSummaryThis PR successfully migrates from Shakapacker 9.0.0-beta.8 to 9.1.0 stable and introduces Rspack as the bundler. The migration is well-structured and maintains backward compatibility. Great work! 🎉 ✅ Strengths1. Well-Structured Configuration
2. Thoughtful Migration Approach
3. Performance Benefits
4. Dependencies
🔍 Issues & Recommendations1.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
config/rspack/serverRspackConfig.js (2)
27-36
: Remove duplicate mini-css-extract-plugin filtering block (already handled below).The SSR adjustments at lines 67–107 supersede this. Drop the duplicate to reduce churn and avoid eslint no-param-reassign on Line 32.
Apply this diff:
- // Remove the mini-css-extract-plugin from the style loaders because - // the client build will handle exporting CSS. - // replace file-loader with null-loader - serverRspackConfig.module.rules.forEach((loader) => { - if (loader.use && loader.use.filter) { - loader.use = loader.use.filter( - (item) => !(typeof item === 'string' && item.match(/mini-css-extract-plugin/)), - ); - } - });
103-106
: Null-safety for rule.use.options before setting emitFile.Avoid runtime error when loader doesn’t define options. Note: this is the same issue flagged previously.
Apply this diff:
- } else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) { - rule.use.options.emitFile = false; - } + } else if (rule.use && (rule.use.loader === 'url-loader' || rule.use.loader === 'file-loader')) { + rule.use.options = rule.use.options || {}; + rule.use.options.emitFile = false; + }
🧹 Nitpick comments (2)
config/rspack/serverRspackConfig.js (2)
71-107
: Tighten SSR rule mutations: respect lint hints and readability.
- Use destructuring (prefer-destructuring).
- Silence intentional param mutation in config with scoped disable (no-param-reassign).
- Reformat long return (prettier).
Apply this diff:
- const rules = serverRspackConfig.module.rules; + /* eslint-disable no-param-reassign */ + const { rules } = serverRspackConfig.module; rules.forEach((rule) => { if (Array.isArray(rule.use)) { // remove the mini-css-extract-plugin/CssExtractRspackPlugin and style-loader rule.use = rule.use.filter((item) => { let testValue; if (typeof item === 'string') { testValue = item; } else if (typeof item.loader === 'string') { testValue = item.loader; } - return !(testValue?.match(/mini-css-extract-plugin/) || testValue?.includes('cssExtractLoader') || testValue === 'style-loader'); + return !( + testValue?.match(/mini-css-extract-plugin/) || + testValue?.includes('cssExtractLoader') || + testValue === 'style-loader' + ); }); const cssLoader = rule.use.find((item) => { let testValue; if (typeof item === 'string') { testValue = item; } else if (typeof item.loader === 'string') { testValue = item.loader; } return testValue.includes('css-loader'); }); @@ - }); + }); + /* eslint-enable no-param-reassign */
52-56
: Update comment for library target (webpack 5/Rspack).libraryTarget is deprecated; prefer output.library.type.
Apply this diff (comment-only):
- // If using the React on Rails Pro node server renderer, uncomment the next line - // libraryTarget: 'commonjs2', + // If using the React on Rails Pro node server renderer, set: + // library: { type: 'commonjs2' },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
config/rspack/serverRspackConfig.js
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
config/rspack/serverRspackConfig.js (2)
config/rspack/commonRspackConfig.js (2)
require
(2-2)commonRspackConfig
(23-77)config/webpack/commonWebpackConfig.js (1)
cssLoader
(59-62)
🪛 ESLint
config/rspack/serverRspackConfig.js
[error] 5-5: @rspack/core
import should occur before import of ./commonRspackConfig
(import/order)
[error] 32-32: Assignment to property of function parameter 'loader'.
(no-param-reassign)
[error] 71-71: Use object destructuring.
(prefer-destructuring)
[error] 75-75: Assignment to property of function parameter 'rule'.
(no-param-reassign)
[error] 82-82: Replace testValue?.match(/mini-css-extract-plugin/)·||·testValue?.includes('cssExtractLoader')·||·testValue·===·'style-loader'
with ⏎··········testValue?.match(/mini-css-extract-plugin/)·||⏎··········testValue?.includes('cssExtractLoader')·||⏎··········testValue·===·'style-loader'⏎········
(prettier/prettier)
[error] 105-105: Assignment to property of function parameter 'rule'.
(no-param-reassign)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test (22.x, 3.4.6)
- GitHub Check: test (22.x, 3.4.6)
- GitHub Check: claude-review
🔇 Additional comments (2)
config/rspack/serverRspackConfig.js (2)
67-107
: Verify SSR asset module types
Noasset/resource
rules found inconfig/rspack/serverRspackConfig.js
. Confirm your base config doesn’t use asset modules—or if it does, add logic to converttype: 'asset/resource'
totype: 'asset/inline'
to prevent file emission on the server.
58-66
: Exclude Rspack manifest and CSS extract plugins in serverRspackConfig.js
Update the plugin filter to also remove the Rspack manifest and CSS extract plugins. For example:- serverRspackConfig.plugins = serverRspackConfig.plugins.filter( - (plugin) => - plugin.constructor.name !== 'WebpackAssetsManifest' && - plugin.constructor.name !== 'MiniCssExtractPlugin' && - plugin.constructor.name !== 'ForkTsCheckerWebpackPlugin', - ); + serverRspackConfig.plugins = serverRspackConfig.plugins.filter((plugin) => { + const name = plugin?.constructor?.name; + return ( + name !== 'WebpackAssetsManifest' && + name !== 'RspackManifestPlugin' && // rspack-manifest-plugin + name !== 'MiniCssExtractPlugin' && + name !== 'CssExtractRspackPlugin' && // CSS extract plugin + name !== 'ForkTsCheckerWebpackPlugin' + ); + });Confirm the exact constructor names for your installed
rspack-manifest-plugin
and CSS extract plugin and adjust accordingly.
const path = require('path'); | ||
const { config } = require('shakapacker'); | ||
const commonRspackConfig = require('./commonRspackConfig'); | ||
|
||
const rspack = require('@rspack/core'); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix import order (ESLint import/order).
Place external packages before local modules.
Apply this diff:
const path = require('path');
const { config } = require('shakapacker');
-const commonRspackConfig = require('./commonRspackConfig');
-
-const rspack = require('@rspack/core');
+const rspack = require('@rspack/core');
+const commonRspackConfig = require('./commonRspackConfig');
const configureServer = () => {
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const path = require('path'); | |
const { config } = require('shakapacker'); | |
const commonRspackConfig = require('./commonRspackConfig'); | |
const rspack = require('@rspack/core'); | |
const path = require('path'); | |
const { config } = require('shakapacker'); | |
const rspack = require('@rspack/core'); | |
const commonRspackConfig = require('./commonRspackConfig'); | |
const configureServer = () => { | |
// …rest of implementation… | |
}; |
🧰 Tools
🪛 ESLint
[error] 5-5: @rspack/core
import should occur before import of ./commonRspackConfig
(import/order)
🤖 Prompt for AI Agents
In config/rspack/serverRspackConfig.js lines 1-6, the import order violates
ESLint import/order by placing a local module before an external package;
reorder requires so that external packages (e.g., path, @rspack/core,
shakapacker) come first and local modules (./commonRspackConfig) come after,
keeping existing declarations the same but moving the const rspack =
require('@rspack/core') line up with the other external requires and leaving
./commonRspackConfig below them.
const cssLoader = rule.use.find((item) => { | ||
let testValue; | ||
|
||
if (typeof item === 'string') { | ||
testValue = item; | ||
} else if (typeof item.loader === 'string') { | ||
testValue = item.loader; | ||
} | ||
|
||
return testValue.includes('css-loader'); | ||
}); | ||
if (cssLoader && cssLoader.options && cssLoader.options.modules) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard against undefined when detecting css-loader.
Avoid potential TypeError if testValue is not set.
Apply this diff:
- return testValue.includes('css-loader');
+ return typeof testValue === 'string' && testValue.includes('css-loader');
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const cssLoader = rule.use.find((item) => { | |
let testValue; | |
if (typeof item === 'string') { | |
testValue = item; | |
} else if (typeof item.loader === 'string') { | |
testValue = item.loader; | |
} | |
return testValue.includes('css-loader'); | |
}); | |
if (cssLoader && cssLoader.options && cssLoader.options.modules) { | |
const cssLoader = rule.use.find((item) => { | |
let testValue; | |
if (typeof item === 'string') { | |
testValue = item; | |
} else if (typeof item.loader === 'string') { | |
testValue = item.loader; | |
} | |
return typeof testValue === 'string' && testValue.includes('css-loader'); | |
}); | |
if (cssLoader && cssLoader.options && cssLoader.options.modules) { |
🤖 Prompt for AI Agents
In config/rspack/serverRspackConfig.js around lines 84 to 95, the detection of
css-loader calls testValue.includes(...) without ensuring testValue is defined
which can throw a TypeError; update the predicate to guard testValue (e.g. check
testValue is a non-empty string before calling includes or use optional
chaining) so the find callback returns false when testValue is undefined, and
keep the subsequent check for cssLoader.options as-is.
Summary
Key Changes
Shakapacker Upgrade
shakapacker
gem from 9.0.0-beta.8 to 9.1.0shakapacker
npm package from 9.0.0-beta.8 to 9.1.0Rspack Migration
@rspack/core@^1.5.8
@rspack/cli@^1.5.8
rspack-manifest-plugin@^5.1.0
assets_bundler: rspack
inconfig/shakapacker.yml
config/rspack/
directory with complete configurationConfiguration Files Created
config/rspack/rspack.config.js
- Main configuration entry pointconfig/rspack/commonRspackConfig.js
- Shared configuration for client and serverconfig/rspack/clientRspackConfig.js
- Client bundle configurationconfig/rspack/serverRspackConfig.js
- Server bundle configuration (SSR)config/rspack/development.js
- Development environment settingsconfig/rspack/production.js
- Production environment settingsconfig/rspack/test.js
- Test environment settingsconfig/rspack/alias.js
- Module aliasesPerformance Impact
Rspack provides significantly faster build times compared to webpack:
Testing
Breaking Changes
None - this is a drop-in replacement that maintains full backward compatibility with the existing webpack configuration.
Migration Notes
The webpack configurations remain in
config/webpack/
and can be kept for reference or removed in a future PR. Shakapacker automatically uses the Rspack configurations based on theassets_bundler
setting inshakapacker.yml
.🤖 Generated with Claude Code
This change is
Summary by CodeRabbit
New Features
Chores