-
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
Merged
Merged
Changes from 11 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
a951f4c
Update to Shakapacker 9.1.0 and migrate to Rspack
justin808 879d171
Add missing i18n translation files
justin808 087ec70
Fix Ruby version mismatch for CI
justin808 5d85f15
Fix SSR by using classic React runtime in SWC
justin808 3fe61f0
Fix CSS modules config for server bundle
justin808 fbc5781
Add .bs.js extension to resolve extensions for ReScript
justin808 76921b8
Add patch for rescript-json-combinators to generate .bs.js files
justin808 012b0b7
Fix yarn.lock and patch file for rescript-json-combinators
justin808 1685fb4
Fix CSS modules to use default exports for ReScript compatibility
justin808 28014b2
Move CSS modules fix into function to ensure it applies on each call
justin808 3da3dfc
Fix server bundle to properly filter Rspack CSS extract loader
justin808 71b934a
Remove generated i18n files that should be gitignored
justin808 752919b
Consolidate Rspack config into webpack directory with conditionals
justin808 4c761bb
Add bundler auto-detection to all webpack config files
justin808 431a8ee
Add comprehensive documentation and address code review feedback
justin808 2e03f56
Add performance benchmarks to README
justin808 5f92988
Correct performance benchmarks to show actual bundler times
justin808 0ab9eac
Refactor bundler detection and improve documentation
justin808 a32ebff
Add test coverage and improve documentation
justin808 84311cc
Fix CI failure and add bundler validation improvements
justin808 660aab3
Fix YAML alias parsing in RSpec bundler tests
justin808 2bdc624
Remove heavyweight RSpec bundler integration test
justin808 2af9d6f
Fix ESLint violations in bundlerUtils test
justin808 4d9d19e
Fix CSS plugin filtering and add cache immutability docs
justin808 13449f0
Migrate to modern ReScript .res.js suffix and remove patch
justin808 b7171e5
Add ror_components wrapper for ReScript component
justin808 8bae4aa
Remove generated .res.js files from git and add to .gitignore
justin808 ab8bd51
Add .bs.js to .gitignore for completeness
justin808 921844d
Remove patches/README.md
justin808 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// Default locale and messages for i18n | ||
export const defaultLocale = 'en'; | ||
|
||
export const defaultMessages = { | ||
'app.name': 'React Webpack Rails Tutorial', | ||
'comment.form.name_label': 'Name', | ||
'comment.form.text_label': 'Text', | ||
'comment.form.submit': 'Submit', | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// 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', | ||
}, | ||
es: { | ||
'app.name': 'Tutorial de React Webpack Rails', | ||
'comment.form.name_label': 'Nombre', | ||
'comment.form.text_label': 'Texto', | ||
'comment.form.submit': 'Enviar', | ||
}, | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const { resolve } = require('path'); | ||
|
||
module.exports = { | ||
resolve: { | ||
alias: { | ||
Assets: resolve(__dirname, '..', '..', 'client', 'app', 'assets'), | ||
}, | ||
}, | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const rspack = require('@rspack/core'); | ||
const commonRspackConfig = require('./commonRspackConfig'); | ||
|
||
const configureClient = () => { | ||
const clientConfig = commonRspackConfig(); | ||
|
||
clientConfig.plugins.push( | ||
new rspack.ProvidePlugin({ | ||
$: 'jquery', | ||
jQuery: 'jquery', | ||
ActionCable: '@rails/actioncable', | ||
}), | ||
); | ||
|
||
// server-bundle is special and should ONLY be built by the serverConfig | ||
// In case this entry is not deleted, a very strange "window" not found | ||
// error shows referring to window["webpackJsonp"]. That is because the | ||
// client config is going to try to load chunks. | ||
delete clientConfig.entry['server-bundle']; | ||
|
||
return clientConfig; | ||
}; | ||
|
||
module.exports = configureClient; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// Common configuration applying to client and server configuration | ||
const { generateWebpackConfig, merge } = require('shakapacker'); | ||
|
||
const commonOptions = { | ||
resolve: { | ||
extensions: ['.css', '.ts', '.tsx', '.bs.js'], | ||
}, | ||
}; | ||
|
||
// add sass resource loader | ||
const sassLoaderConfig = { | ||
loader: 'sass-resources-loader', | ||
options: { | ||
resources: './client/app/assets/styles/app-variables.scss', | ||
}, | ||
}; | ||
|
||
const ignoreWarningsConfig = { | ||
ignoreWarnings: [/Module not found: Error: Can't resolve 'react-dom\/client'/], | ||
}; | ||
|
||
// Copy the object using merge b/c the baseClientRspackConfig and commonOptions are mutable globals | ||
const commonRspackConfig = () => { | ||
const baseClientRspackConfig = generateWebpackConfig(); | ||
|
||
// Fix all CSS-related loaders to use default exports instead of named exports | ||
// Shakapacker 9 defaults to namedExport: true, but existing code expects default exports | ||
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'); | ||
}); | ||
|
||
if (cssLoader?.options?.modules) { | ||
cssLoader.options.modules.namedExport = false; | ||
cssLoader.options.modules.exportLocalsConvention = 'camelCase'; | ||
} | ||
} | ||
}); | ||
|
||
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'; | ||
} | ||
} | ||
|
||
baseClientRspackConfig.module.rules[scssConfigIndex].use.push(sassLoaderConfig); | ||
} | ||
|
||
return merge({}, baseClientRspackConfig, commonOptions, ignoreWarningsConfig); | ||
}; | ||
|
||
module.exports = commonRspackConfig; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
process.env.NODE_ENV = process.env.NODE_ENV || 'development'; | ||
|
||
const { devServer, inliningCss } = require('shakapacker'); | ||
|
||
const rspackConfig = require('./rspackConfig'); | ||
|
||
const developmentEnvOnly = (clientRspackConfig, _serverRspackConfig) => { | ||
// plugins | ||
if (inliningCss) { | ||
// Note, when this is run, we're building the server and client bundles in separate processes. | ||
// Thus, this plugin is not applied to the server bundle. | ||
|
||
// eslint-disable-next-line global-require | ||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); | ||
clientRspackConfig.plugins.push( | ||
new ReactRefreshWebpackPlugin({ | ||
overlay: { | ||
sockPort: devServer.port, | ||
}, | ||
}), | ||
); | ||
} | ||
}; | ||
|
||
module.exports = rspackConfig(developmentEnvOnly); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
process.env.NODE_ENV = process.env.NODE_ENV || 'production'; | ||
|
||
const rspackConfig = require('./rspackConfig'); | ||
|
||
const productionEnvOnly = (_clientRspackConfig, _serverRspackConfig) => { | ||
// place any code here that is for production only | ||
}; | ||
|
||
module.exports = rspackConfig(productionEnvOnly); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
const { env, generateWebpackConfig } = require('shakapacker'); | ||
const { existsSync } = require('fs'); | ||
const { resolve } = require('path'); | ||
|
||
const envSpecificConfig = () => { | ||
const path = resolve(__dirname, `${env.nodeEnv}.js`); | ||
if (existsSync(path)) { | ||
console.log(`Loading ENV specific rspack configuration file ${path}`); | ||
return require(path); | ||
} | ||
|
||
return generateWebpackConfig(); | ||
}; | ||
|
||
module.exports = envSpecificConfig(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
const clientRspackConfig = require('./clientRspackConfig'); | ||
const serverRspackConfig = require('./serverRspackConfig'); | ||
|
||
const rspackConfig = (envSpecific) => { | ||
const clientConfig = clientRspackConfig(); | ||
const serverConfig = serverRspackConfig(); | ||
|
||
if (envSpecific) { | ||
envSpecific(clientConfig, serverConfig); | ||
} | ||
|
||
let result; | ||
// For HMR, need to separate the the client and server rspack configurations | ||
if (process.env.WEBPACK_SERVE || process.env.CLIENT_BUNDLE_ONLY) { | ||
// eslint-disable-next-line no-console | ||
console.log('[React on Rails] Creating only the client bundles.'); | ||
result = clientConfig; | ||
} else if (process.env.SERVER_BUNDLE_ONLY) { | ||
// eslint-disable-next-line no-console | ||
console.log('[React on Rails] Creating only the server bundle.'); | ||
result = serverConfig; | ||
} else { | ||
// default is the standard client and server build | ||
// eslint-disable-next-line no-console | ||
console.log('[React on Rails] Creating both client and server bundles.'); | ||
result = [clientConfig, serverConfig]; | ||
} | ||
|
||
// To debug, uncomment next line and inspect "result" | ||
// debugger | ||
return result; | ||
}; | ||
|
||
module.exports = rspackConfig; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
fromclient/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
:📝 Committable suggestion
🤖 Prompt for AI Agents