Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pre-commit:
rubocop:
run: bin/lefthook/ruby-lint all-changed

eslint:
run: bin/lefthook/eslint-lint all-changed

prettier:
run: bin/lefthook/prettier-format all-changed

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,15 @@ Changes since the last non-beta release.
#### Changed

- **Shakapacker 9.0.0 Upgrade**: Upgraded Shakapacker from 8.2.0 to 9.0.0 with Babel transpiler configuration for compatibility. Key changes include:

- Configured `javascript_transpiler: babel` in shakapacker.yml (Shakapacker 9.0 defaults to SWC which has PropTypes handling issues)
- Added precompile hook support via `bin/shakapacker-precompile-hook` for ReScript builds and pack generation
- Configured CSS Modules to use default exports (`namedExport: false`) for backward compatibility with existing `import styles from` syntax
- Fixed webpack configuration to process SCSS rules and CSS loaders in a single pass for better performance
[PR 1904](https://github.com/shakacode/react_on_rails/pull/1904) by [justin808](https://github.com/justin808).

- **Shakapacker 9.1.0 Upgrade**: Upgraded Shakapacker from 9.0.0 to 9.1.0. This minor version update includes bug fixes and improvements. Updated webpack configuration in Pro dummy apps to use forEach pattern for better compatibility with multiple SCSS rules. [PR 1921](https://github.com/shakacode/react_on_rails/pull/1921) by [justin808](https://github.com/justin808).

#### Bug Fixes

- **Use as Git dependency**: All packages can now be installed as Git dependencies. This is useful for development and testing purposes. See [CONTRIBUTING.md](./CONTRIBUTING.md#git-dependencies) for documentation. [PR #1873](https://github.com/shakacode/react_on_rails/pull/1873) by [alexeyr-ci2](https://github.com/alexeyr-ci2).
Expand Down
14 changes: 12 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ These requirements are non-negotiable. CI will fail if not followed.

Git hooks will automatically run linting on **all changed files (staged + unstaged + untracked)** before each commit - making it fast while preventing CI failures!

Pre-commit hooks automatically run:
- **RuboCop** (auto-fix Ruby code style)
- **ESLint** (auto-fix JS/TS code style)
- **Prettier** (auto-format all supported files)
- **Trailing newline checks** (ensure all files end with newlines)

**Note:** Git hooks are for React on Rails gem developers only, not for users who install the gem.

## Development Commands
Expand Down Expand Up @@ -90,13 +96,17 @@ Git hooks will automatically run linting on **all changed files (staged + unstag

## Project Architecture

### Dual Package Structure
### Monorepo Structure

This project maintains both a Ruby gem and an NPM package:
This is a monorepo containing both the open-source package and the Pro package:

- **Open Source**: Root directory contains the main React on Rails gem and package
- **Pro Package**: `react_on_rails_pro/` contains the Pro features (separate linting/formatting config)
- **Ruby gem**: Located in `lib/`, provides Rails integration and server-side rendering
- **NPM package**: Located in `packages/react-on-rails/src/`, provides client-side React integration

**IMPORTANT**: The `react_on_rails_pro/` directory has its own Prettier/ESLint configuration. When CI runs, it lints both directories separately. The pre-commit hooks will catch issues in both directories.

### Core Components

#### Ruby Side (`lib/react_on_rails/`)
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.development_dependencies
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

gem "shakapacker", "9.0.0"
gem "shakapacker", "9.1.0"
gem "bootsnap", require: false
gem "rails", "~> 7.1"

Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ GEM
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
semantic_range (3.1.0)
shakapacker (9.0.0)
shakapacker (9.1.0)
activesupport (>= 5.2)
package_json
rack-proxy (>= 0.6.1)
Expand Down Expand Up @@ -440,7 +440,7 @@ DEPENDENCIES
scss_lint
sdoc
selenium-webdriver (= 4.9.0)
shakapacker (= 9.0.0)
shakapacker (= 9.1.0)
spring (~> 4.0)
sprockets (~> 4.0)
sqlite3 (~> 1.6)
Expand Down
27 changes: 27 additions & 0 deletions bin/lefthook/eslint-lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Lint and auto-fix JS/TS files with ESLint
set -euo pipefail

CONTEXT="${1:-staged}"
files="$(bin/lefthook/get-changed-files "$CONTEXT" '\.(js|jsx|ts|tsx)$')"

if [ -z "$files" ]; then
echo "✅ No JS/TS files to lint with ESLint"
exit 0
fi

if [ "$CONTEXT" = "all-changed" ]; then
echo "🔍 ESLint on all changed files:"
else
echo "🔍 ESLint on $CONTEXT files:"
fi
printf " %s\n" $files

# Run ESLint with auto-fix
yarn run eslint $files --report-unused-disable-directives --fix

# Re-stage files if running on staged or all-changed context
if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
echo $files | xargs -r git add
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Consider portability: xargs -r is GNU-specific.

The -r flag on line 25 prevents xargs from running when there's no input, but it's a GNU extension not available on macOS by default. The revised solution above using -0 with null-delimited input addresses this, as the array expansion will naturally handle the empty case.

🤖 Prompt for AI Agents
In bin/lefthook/eslint-lint around line 25, avoid the GNU-only xargs -r flag;
instead either guard the call so it only runs when there are files or feed
null-delimited input to a portable xargs. Replace the current pipeline that uses
xargs -r with a pattern that prints/outputs filenames separated by NUL and
invokes xargs -0 git add, or wrap the git-add pipeline in a simple shell
conditional that checks for non-empty files before calling xargs; this removes
the -r dependency and keeps behavior safe on macOS.

echo "✅ Re-staged fixed files"
fi
2 changes: 1 addition & 1 deletion react_on_rails_pro/Gemfile.development_dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ruby '3.3.7'

gem "react_on_rails", path: "../"

gem "shakapacker", "8.0.0"
gem "shakapacker", "9.1.0"
gem "bootsnap", require: false
gem "rails", "~> 7.1"
gem "puma", "~> 6"
Expand Down
1 change: 1 addition & 0 deletions react_on_rails_pro/spec/dummy/config/shakapacker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ default: &default
public_root_path: public
public_output_path: packs
nested_entries: true
javascript_transpiler: babel

cache_path: tmp/cache/webpacker
check_yarn_integrity: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,17 @@ const sassLoaderConfig = {
};

const baseClientWebpackConfig = generateWebpackConfig();
const scssConfigIndex = baseClientWebpackConfig.module.rules.findIndex((config) =>
'.scss'.match(config.test),
);
baseClientWebpackConfig.module.rules[scssConfigIndex].use.push(sassLoaderConfig);

// Add sass-resources-loader to all SCSS rules (both .scss and .module.scss)
baseClientWebpackConfig.module.rules.forEach((rule) => {
if (
Array.isArray(rule.use) &&
rule.test &&
(rule.test.test('example.scss') || rule.test.test('example.module.scss'))
) {
rule.use.push(sassLoaderConfig);
}
});

if (isHMR) {
baseClientWebpackConfig.plugins.push(
Expand Down
2 changes: 1 addition & 1 deletion react_on_rails_pro/spec/dummy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"sass": "^1.43.4",
"sass-loader": "^12.3.0",
"sass-resources-loader": "^2.0.0",
"shakapacker": "8.0.0",
"shakapacker": "9.1.0",
"style-loader": "^3.3.1",
"tailwindcss": "^3.2.7",
"terser-webpack-plugin": "5",
Expand Down
13 changes: 7 additions & 6 deletions react_on_rails_pro/spec/dummy/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5970,13 +5970,14 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"

shakapacker@8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-8.0.0.tgz#f29537c19078af7318758c92e7a1bca4cee96bdd"
integrity sha512-HCdpITzIKXzGEyUWQhKzPbpwwOsgTamaPH+0kXdhM59VQxZ3NWnT5cL3DlJdAT3sGsWCJskEl3eMkQlnh9DjhA==
shakapacker@9.1.0:
version "9.1.0"
resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-9.1.0.tgz#6d63c4d27b9358073dd8fc3c6e79252b96d36a36"
integrity sha512-PL0DuzNLFJMwr5s908ImMuvejmC20WuDa7EfAPpPFU1pM5U8cPqqC4kwSdXFLfVU0Or/UqeegNyIB1sGBdSPiw==
dependencies:
js-yaml "^4.1.0"
path-complete-extname "^1.0.0"
webpack-merge "^5.8.0"

shallow-clone@^3.0.0:
version "3.0.1"
Expand Down Expand Up @@ -6815,9 +6816,9 @@ webpack-manifest-plugin@^2.0.4:
object.entries "^1.1.0"
tapable "^1.0.0"

webpack-merge@5, webpack-merge@^5.7.3:
webpack-merge@5, webpack-merge@^5.7.3, webpack-merge@^5.8.0:
version "5.10.0"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177"
resolved "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177"
integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==
dependencies:
clone-deep "^4.0.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ default: &default
public_output_path: packs
cache_path: tmp/webpacker
webpack_compile_output: true
javascript_transpiler: babel

# Additional paths webpack should lookup modules
# ['app/assets', 'engine/foo/app/assets']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-on-rails": "link:.yalc/react-on-rails",
"shakapacker": "8.0.0",
"shakapacker": "9.1.0",
"style-loader": "^4.0.0",
"terser-webpack-plugin": "5",
"webpack": "5",
Expand Down
13 changes: 7 additions & 6 deletions react_on_rails_pro/spec/execjs-compatible-dummy/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3657,13 +3657,14 @@ [email protected]:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==

shakapacker@8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-8.0.0.tgz#f29537c19078af7318758c92e7a1bca4cee96bdd"
integrity sha512-HCdpITzIKXzGEyUWQhKzPbpwwOsgTamaPH+0kXdhM59VQxZ3NWnT5cL3DlJdAT3sGsWCJskEl3eMkQlnh9DjhA==
shakapacker@9.1.0:
version "9.1.0"
resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-9.1.0.tgz#6d63c4d27b9358073dd8fc3c6e79252b96d36a36"
integrity sha512-PL0DuzNLFJMwr5s908ImMuvejmC20WuDa7EfAPpPFU1pM5U8cPqqC4kwSdXFLfVU0Or/UqeegNyIB1sGBdSPiw==
dependencies:
js-yaml "^4.1.0"
path-complete-extname "^1.0.0"
webpack-merge "^5.8.0"

shallow-clone@^3.0.0:
version "3.0.1"
Expand Down Expand Up @@ -4050,9 +4051,9 @@ webpack-dev-server@4:
webpack-dev-middleware "^5.3.4"
ws "^8.13.0"

webpack-merge@5, webpack-merge@^5.7.3:
webpack-merge@5, webpack-merge@^5.7.3, webpack-merge@^5.8.0:
version "5.10.0"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177"
resolved "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177"
integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==
dependencies:
clone-deep "^4.0.1"
Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/config/webpack/commonWebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const sassLoaderConfig = {
baseClientWebpackConfig.module.rules.forEach((rule) => {
if (Array.isArray(rule.use)) {
// Add sass-resources-loader to all SCSS rules (both .scss and .module.scss)
if (rule.test && '.scss'.match(rule.test)) {
if (rule.test && (rule.test.test('example.scss') || rule.test.test('example.module.scss'))) {
rule.use.push(sassLoaderConfig);
}

Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"sass": "^1.43.4",
"sass-loader": "^12.3.0",
"sass-resources-loader": "^2.1.0",
"shakapacker": "9.0.0",
"shakapacker": "9.1.0",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "5.3.1",
"url-loader": "^4.0.0",
Expand Down
8 changes: 4 additions & 4 deletions spec/dummy/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5653,10 +5653,10 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"

shakapacker@9.0.0:
version "9.0.0"
resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-9.0.0.tgz#36fd2e81ffa3a01075222526b2b079bfd60a6efc"
integrity sha512-q+8VU3AQhPpCLlZmEmyooELmpa10FPXk631rrg46pLAYO40jnEeyK01BtI0SVNvz/nI+QFz1DwZE8NKVk/PRgw==
shakapacker@9.1.0:
version "9.1.0"
resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-9.1.0.tgz#6d63c4d27b9358073dd8fc3c6e79252b96d36a36"
integrity sha512-PL0DuzNLFJMwr5s908ImMuvejmC20WuDa7EfAPpPFU1pM5U8cPqqC4kwSdXFLfVU0Or/UqeegNyIB1sGBdSPiw==
dependencies:
js-yaml "^4.1.0"
path-complete-extname "^1.0.0"
Expand Down
Loading