diff --git a/.lefthook.yml b/.lefthook.yml index 1010a9413f..2bae0a18fb 100644 --- a/.lefthook.yml +++ b/.lefthook.yml @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 23cad6a84f..0deea13650 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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). diff --git a/CLAUDE.md b/CLAUDE.md index eee2c889ab..90c1825575 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 @@ -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/`) @@ -127,6 +137,94 @@ This project maintains both a Ruby gem and an NPM package: - **Examples**: Generated via rake tasks for different webpack configurations - **Rake tasks**: Defined in `rakelib/` for various development operations +## Debugging Webpack Configuration Issues + +When encountering issues with Webpack/Shakapacker configuration (e.g., components not rendering, CSS modules failing), use this debugging approach: + +### 1. Create Debug Scripts + +Create temporary debug scripts in the dummy app root to inspect the actual webpack configuration: + +```javascript +// debug-webpack-rules.js - Inspect all webpack rules +const { generateWebpackConfig } = require('shakapacker'); + +const config = generateWebpackConfig(); + +console.log('=== Webpack Rules ==='); +console.log(`Total rules: ${config.module.rules.length}\n`); + +config.module.rules.forEach((rule, index) => { + console.log(`\nRule ${index}:`); + console.log(' test:', rule.test); + console.log(' use:', Array.isArray(rule.use) ? rule.use.map(u => typeof u === 'string' ? u : u.loader) : rule.use); + + if (rule.test) { + console.log(' Matches .scss:', rule.test.test && rule.test.test('example.scss')); + console.log(' Matches .module.scss:', rule.test.test && rule.test.test('example.module.scss')); + } +}); +``` + +```javascript +// debug-webpack-with-config.js - Inspect config AFTER modifications +const commonWebpackConfig = require('./config/webpack/commonWebpackConfig'); + +const config = commonWebpackConfig(); + +console.log('=== Webpack Rules AFTER commonWebpackConfig ==='); +config.module.rules.forEach((rule, index) => { + if (rule.test && rule.test.test('example.module.scss')) { + console.log(`\nRule ${index} (CSS Modules):`); + if (Array.isArray(rule.use)) { + rule.use.forEach((loader, i) => { + if (loader.loader && loader.loader.includes('css-loader')) { + console.log(` css-loader options:`, loader.options); + } + }); + } + } +}); +``` + +### 2. Run Debug Scripts + +```bash +cd spec/dummy # or react_on_rails_pro/spec/dummy +NODE_ENV=test RAILS_ENV=test node debug-webpack-rules.js +NODE_ENV=test RAILS_ENV=test node debug-webpack-with-config.js +``` + +### 3. Analyze Output + +- Verify the rules array structure matches expectations +- Check that loader options are correctly set +- Confirm rules only match intended file patterns +- Ensure modifications don't break existing loaders + +### 4. Common Issues & Solutions + +**CSS Modules breaking after Shakapacker upgrade:** +- Shakapacker 9.0+ defaults to `namedExport: true` for CSS Modules +- Existing code using `import styles from './file.module.css'` will fail +- Override in webpack config: + ```javascript + loader.options.modules.namedExport = false; + loader.options.modules.exportLocalsConvention = 'camelCase'; + ``` + +**Rules not matching expected files:** +- Use `.test.test('example.file')` to check regex matching +- Shakapacker may combine multiple file extensions in single rules +- Test with actual filenames from your codebase + +### 5. Clean Up + +Always remove debug scripts before committing: +```bash +rm debug-*.js +``` + ## Important Notes - Use `yalc` for local development when testing with external apps diff --git a/Gemfile.development_dependencies b/Gemfile.development_dependencies index 30acfd8ab5..b3c3e13991 100644 --- a/Gemfile.development_dependencies +++ b/Gemfile.development_dependencies @@ -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" diff --git a/Gemfile.lock b/Gemfile.lock index 2d83409248..5b03f49118 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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) @@ -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) diff --git a/bin/lefthook/eslint-lint b/bin/lefthook/eslint-lint new file mode 100755 index 0000000000..4147c46e38 --- /dev/null +++ b/bin/lefthook/eslint-lint @@ -0,0 +1,64 @@ +#!/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 + +# Separate files into root and Pro directories +root_files=$(echo "$files" | grep -v '^react_on_rails_pro/' || true) +pro_files=$(echo "$files" | grep '^react_on_rails_pro/' || true) + +exit_code=0 + +# Lint root files +if [ -n "$root_files" ]; then + if [ "$CONTEXT" = "all-changed" ]; then + echo "🔍 ESLint on root changed files:" + else + echo "🔍 ESLint on root $CONTEXT files:" + fi + printf " %s\n" $root_files + + if ! yarn run eslint $root_files --report-unused-disable-directives --fix; then + exit_code=1 + fi + + # Re-stage files if running on staged or all-changed context + if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then + echo $root_files | xargs -r git add + fi +fi + +# Lint Pro files (using Pro's ESLint config) +if [ -n "$pro_files" ]; then + if [ "$CONTEXT" = "all-changed" ]; then + echo "🔍 ESLint on Pro changed files:" + else + echo "🔍 ESLint on Pro $CONTEXT files:" + fi + printf " %s\n" $pro_files + + # Strip react_on_rails_pro/ prefix for running in Pro directory + pro_files_relative=$(echo "$pro_files" | sed 's|^react_on_rails_pro/||') + + if ! (cd react_on_rails_pro && yarn run eslint $pro_files_relative --report-unused-disable-directives --fix); then + exit_code=1 + fi + + # Re-stage files if running on staged or all-changed context + if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then + echo $pro_files | xargs -r git add + fi +fi + +if [ $exit_code -eq 0 ]; then + echo "✅ ESLint checks passed" +fi + +exit $exit_code diff --git a/bin/lefthook/prettier-format b/bin/lefthook/prettier-format index 728f2f432c..44a7cbf786 100755 --- a/bin/lefthook/prettier-format +++ b/bin/lefthook/prettier-format @@ -10,17 +10,45 @@ if [ -z "$files" ]; then exit 0 fi -if [ "$CONTEXT" = "all-changed" ]; then - echo "💅 Prettier on all changed files:" -else - echo "💅 Prettier on $CONTEXT files:" +# Separate files into root and Pro directories +root_files=$(echo "$files" | grep -v '^react_on_rails_pro/' || true) +pro_files=$(echo "$files" | grep '^react_on_rails_pro/' || true) + +# Format root files +if [ -n "$root_files" ]; then + if [ "$CONTEXT" = "all-changed" ]; then + echo "💅 Prettier on root changed files:" + else + echo "💅 Prettier on root $CONTEXT files:" + fi + printf " %s\n" $root_files + + yarn run prettier --write $root_files + + # Re-stage files if running on staged or all-changed context + if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then + echo $root_files | xargs -r git add + fi fi -printf " %s\n" $files -yarn run prettier --write $files +# Format Pro files (using Pro's Prettier config) +if [ -n "$pro_files" ]; then + if [ "$CONTEXT" = "all-changed" ]; then + echo "💅 Prettier on Pro changed files:" + else + echo "💅 Prettier on Pro $CONTEXT files:" + fi + printf " %s\n" $pro_files -# Re-stage files if running on staged or all-changed context -if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then - echo $files | xargs -r git add - echo "✅ Re-staged formatted files" + # Strip react_on_rails_pro/ prefix for running in Pro directory + pro_files_relative=$(echo "$pro_files" | sed 's|^react_on_rails_pro/||') + + (cd react_on_rails_pro && yarn run prettier --write $pro_files_relative) + + # Re-stage files if running on staged or all-changed context + if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then + echo $pro_files | xargs -r git add + fi fi + +echo "✅ Prettier formatting complete" diff --git a/react_on_rails_pro/Gemfile.development_dependencies b/react_on_rails_pro/Gemfile.development_dependencies index c65a5319e2..165c1ef437 100644 --- a/react_on_rails_pro/Gemfile.development_dependencies +++ b/react_on_rails_pro/Gemfile.development_dependencies @@ -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" diff --git a/react_on_rails_pro/spec/dummy/config/shakapacker.yml b/react_on_rails_pro/spec/dummy/config/shakapacker.yml index 2e1c9fd659..dab40bdf81 100644 --- a/react_on_rails_pro/spec/dummy/config/shakapacker.yml +++ b/react_on_rails_pro/spec/dummy/config/shakapacker.yml @@ -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 diff --git a/react_on_rails_pro/spec/dummy/config/webpack/commonWebpackConfig.js b/react_on_rails_pro/spec/dummy/config/webpack/commonWebpackConfig.js index fb40e38181..608c219e7a 100644 --- a/react_on_rails_pro/spec/dummy/config/webpack/commonWebpackConfig.js +++ b/react_on_rails_pro/spec/dummy/config/webpack/commonWebpackConfig.js @@ -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( @@ -41,6 +48,34 @@ if (isHMR) { ); } -const commonWebpackConfig = () => merge({}, baseClientWebpackConfig, commonOptions, aliasConfig); +const commonWebpackConfig = () => { + const config = merge({}, baseClientWebpackConfig, commonOptions, aliasConfig); + + // Fix CSS modules for Shakapacker 9.x compatibility + // Shakapacker 9 defaults to namedExport: true, but our code uses default imports + // Override to use the old behavior for backward compatibility + config.module.rules.forEach((rule) => { + if (rule.test && (rule.test.test('example.module.scss') || rule.test.test('example.module.css'))) { + if (Array.isArray(rule.use)) { + rule.use.forEach((loader) => { + if ( + loader.loader && + loader.loader.includes('css-loader') && + loader.options && + loader.options.modules + ) { + // Disable named exports to support default imports + // eslint-disable-next-line no-param-reassign + loader.options.modules.namedExport = false; + // eslint-disable-next-line no-param-reassign + loader.options.modules.exportLocalsConvention = 'camelCase'; + } + }); + } + } + }); + + return config; +}; module.exports = commonWebpackConfig; diff --git a/react_on_rails_pro/spec/dummy/package.json b/react_on_rails_pro/spec/dummy/package.json index 055bc02474..a91a72f04a 100644 --- a/react_on_rails_pro/spec/dummy/package.json +++ b/react_on_rails_pro/spec/dummy/package.json @@ -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", diff --git a/react_on_rails_pro/spec/dummy/yarn.lock b/react_on_rails_pro/spec/dummy/yarn.lock index c7d322fe25..c3692e3bbb 100644 --- a/react_on_rails_pro/spec/dummy/yarn.lock +++ b/react_on_rails_pro/spec/dummy/yarn.lock @@ -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" @@ -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" diff --git a/react_on_rails_pro/spec/execjs-compatible-dummy/config/shakapacker.yml b/react_on_rails_pro/spec/execjs-compatible-dummy/config/shakapacker.yml index 62f1bb6648..a982f1cb5f 100644 --- a/react_on_rails_pro/spec/execjs-compatible-dummy/config/shakapacker.yml +++ b/react_on_rails_pro/spec/execjs-compatible-dummy/config/shakapacker.yml @@ -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'] diff --git a/react_on_rails_pro/spec/execjs-compatible-dummy/package.json b/react_on_rails_pro/spec/execjs-compatible-dummy/package.json index 7eab87e733..f9abb3a5b4 100644 --- a/react_on_rails_pro/spec/execjs-compatible-dummy/package.json +++ b/react_on_rails_pro/spec/execjs-compatible-dummy/package.json @@ -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", diff --git a/react_on_rails_pro/spec/execjs-compatible-dummy/yarn.lock b/react_on_rails_pro/spec/execjs-compatible-dummy/yarn.lock index 828980a87a..eb68c33550 100644 --- a/react_on_rails_pro/spec/execjs-compatible-dummy/yarn.lock +++ b/react_on_rails_pro/spec/execjs-compatible-dummy/yarn.lock @@ -3657,13 +3657,14 @@ setprototypeof@1.2.0: 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" @@ -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" diff --git a/spec/dummy/config/webpack/commonWebpackConfig.js b/spec/dummy/config/webpack/commonWebpackConfig.js index 41f8a5647e..a5aa600ccf 100644 --- a/spec/dummy/config/webpack/commonWebpackConfig.js +++ b/spec/dummy/config/webpack/commonWebpackConfig.js @@ -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); } diff --git a/spec/dummy/package.json b/spec/dummy/package.json index 5cbed3ab13..a646130a1b 100644 --- a/spec/dummy/package.json +++ b/spec/dummy/package.json @@ -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", diff --git a/spec/dummy/yarn.lock b/spec/dummy/yarn.lock index c2c72df59e..0ec540cac4 100644 --- a/spec/dummy/yarn.lock +++ b/spec/dummy/yarn.lock @@ -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"