diff --git a/.github/workflows/lint-js-and-ruby.yml b/.github/workflows/lint-js-and-ruby.yml
index e3544095d1..23f401333b 100644
--- a/.github/workflows/lint-js-and-ruby.yml
+++ b/.github/workflows/lint-js-and-ruby.yml
@@ -72,7 +72,7 @@ jobs:
run: cd spec/dummy && RAILS_ENV="test" bundle exec rake react_on_rails:generate_packs
- name: Detect dead code
run: |
- yarn run knip
+ yarn run knip --no-config-hints
yarn run knip --production
- name: Lint JS
run: yarn run eslint --report-unused-disable-directives
diff --git a/.github/workflows/pro-integration-tests.yml b/.github/workflows/pro-integration-tests.yml
index 47d802a767..2825e26f87 100644
--- a/.github/workflows/pro-integration-tests.yml
+++ b/.github/workflows/pro-integration-tests.yml
@@ -67,8 +67,15 @@ jobs:
sudo yarn global add yalc
yarn install --frozen-lockfile --no-progress --no-emoji
+ - name: Build and publish packages with yalc
+ run: |
+ cd ..
+ yarn run yalc:publish
+ cd react_on_rails_pro
+ yarn && yalc publish
+
- name: Install Node modules with Yarn for Pro dummy app
- run: cd spec/dummy && yarn install --frozen-lockfile --no-progress --no-emoji
+ run: cd spec/dummy && yarn install --ignore-scripts --no-progress --no-emoji
- name: Install Ruby Gems for Pro dummy app
run: |
@@ -180,8 +187,15 @@ jobs:
sudo yarn global add yalc
yarn install --frozen-lockfile --no-progress --no-emoji
+ - name: Build and publish packages with yalc
+ run: |
+ cd ..
+ yarn run yalc:publish
+ cd react_on_rails_pro
+ yarn && yalc publish
+
- name: Install Node modules with Yarn for Pro dummy app
- run: cd spec/dummy && yarn install --frozen-lockfile --no-progress --no-emoji
+ run: cd spec/dummy && yarn install --ignore-scripts --no-progress --no-emoji
- name: Ensure minimum required Chrome version
run: |
@@ -365,8 +379,15 @@ jobs:
sudo yarn global add yalc
yarn install --frozen-lockfile --no-progress --no-emoji
+ - name: Build and publish packages with yalc
+ run: |
+ cd ..
+ yarn run yalc:publish
+ cd react_on_rails_pro
+ yarn && yalc publish
+
- name: Install Node modules with Yarn for Pro dummy app
- run: cd spec/dummy && yarn install --frozen-lockfile --no-progress --no-emoji
+ run: cd spec/dummy && yarn install --ignore-scripts --no-progress --no-emoji
- name: Ensure minimum required Chrome version
run: |
diff --git a/Gemfile.development_dependencies b/Gemfile.development_dependencies
index e11cd21c92..8f3b21e397 100644
--- a/Gemfile.development_dependencies
+++ b/Gemfile.development_dependencies
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-gem "shakapacker", "8.2.0"
+gem "shakapacker", "9.3.0"
gem "bootsnap", require: false
gem "rails", "~> 7.1"
@@ -46,7 +46,7 @@ group :development, :test do
end
group :test do
- gem "capybara"
+ gem "capybara", ">= 3.40"
gem "capybara-screenshot"
gem "coveralls", require: false
gem "equivalent-xml"
diff --git a/Gemfile.lock b/Gemfile.lock
index 5fe05932b3..c3962dc1ec 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -86,8 +86,8 @@ GEM
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
- addressable (2.8.6)
- public_suffix (>= 2.0.2, < 6.0)
+ addressable (2.8.7)
+ public_suffix (>= 2.0.2, < 7.0)
amazing_print (1.6.0)
ast (2.4.2)
base64 (0.2.0)
@@ -171,10 +171,10 @@ GEM
net-pop
net-smtp
marcel (1.0.4)
- matrix (0.4.2)
+ matrix (0.4.3)
method_source (1.1.0)
mini_mime (1.1.5)
- mini_portile2 (2.8.7)
+ mini_portile2 (2.8.9)
minitest (5.24.1)
msgpack (1.7.2)
mutex_m (0.2.0)
@@ -188,7 +188,7 @@ GEM
net-smtp (0.5.0)
net-protocol
nio4r (2.7.3)
- nokogiri (1.16.6)
+ nokogiri (1.18.10)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
ostruct (0.6.1)
@@ -213,16 +213,16 @@ GEM
pry (>= 0.12.0)
psych (5.1.2)
stringio
- public_suffix (5.0.5)
+ public_suffix (6.0.2)
puma (6.4.2)
nio4r (~> 2.0)
- racc (1.8.0)
- rack (3.1.4)
+ racc (1.8.1)
+ rack (3.2.4)
rack-proxy (0.7.7)
rack
rack-session (2.0.0)
rack (>= 3.0.0)
- rack-test (2.1.0)
+ rack-test (2.2.0)
rack (>= 1.3)
rackup (2.1.0)
rack (>= 3)
@@ -263,7 +263,7 @@ GEM
ffi (~> 1.0)
rdoc (6.7.0)
psych (>= 4.0.0)
- regexp_parser (2.9.2)
+ regexp_parser (2.11.3)
reline (0.5.9)
io-console (~> 0.5)
rexml (3.2.7)
@@ -342,7 +342,7 @@ GEM
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
semantic_range (3.1.0)
- shakapacker (8.2.0)
+ shakapacker (9.3.0)
activesupport (>= 5.2)
package_json
rack-proxy (>= 0.6.1)
@@ -407,7 +407,7 @@ DEPENDENCIES
amazing_print
benchmark
bootsnap
- capybara
+ capybara (>= 3.40)
capybara-screenshot
coveralls
debug
@@ -440,7 +440,7 @@ DEPENDENCIES
scss_lint
sdoc
selenium-webdriver (= 4.9.0)
- shakapacker (= 8.2.0)
+ shakapacker (= 9.3.0)
spring (~> 4.0)
sprockets (~> 4.0)
sqlite3 (~> 1.6)
diff --git a/TURBO_NAVIGATION_TEST_ISSUE.md b/TURBO_NAVIGATION_TEST_ISSUE.md
new file mode 100644
index 0000000000..3416545692
--- /dev/null
+++ b/TURBO_NAVIGATION_TEST_ISSUE.md
@@ -0,0 +1,188 @@
+# Issue: Add Playwright Test to Catch Turbo Navigation Regression
+
+## Summary
+
+A regression was discovered where JavaScript fails to work after navigating between pages using Turbo links (only works on hard refresh). This issue existed in the codebase for over a year but wasn't caught by automated tests.
+
+## Background
+
+### What Happened
+
+**Bug introduced in:** PR #1620 (commit 56ee2bd9, ~1 year ago)
+
+- Added Turbo (Hotwire) support to replace Turbolinks
+- Updated client-bundle.js to import `@hotwired/turbo-rails`
+- Set `turbo: true` in ReactOnRails options
+- **Forgot to update layout file** from `data-turbolinks-track` to `data-turbo-track`
+
+**Bug fixed in:** PR #1896 (commit f03b935d)
+
+- Updated `spec/dummy/app/views/layouts/application.html.erb`
+- Changed `data-turbolinks-track: true` to `data-turbo-track: 'reload'`
+- Re-added `defer: true` for proper Turbo compatibility
+
+### Impact
+
+Users experienced broken JavaScript when:
+
+1. Landing on a page (hard refresh) → ✅ JavaScript works
+2. Clicking a link to navigate → ❌ JavaScript breaks
+3. Hard refreshing again → ✅ JavaScript works again
+
+This severely degraded the user experience with Turbo navigation.
+
+## The Test Gap
+
+This bug went undetected for over a year, indicating a gap in test coverage for:
+
+- Turbo navigation flows
+- JavaScript execution after client-side navigation
+- React component hydration after Turbo page loads
+
+## Proposed Solution: Playwright E2E Test
+
+Add a Playwright test that verifies:
+
+### Test Scenario
+
+```javascript
+test('React components work after Turbo navigation', async ({ page }) => {
+ // 1. Hard refresh - load first page
+ await page.goto('/react_router');
+
+ // 2. Verify JavaScript works on initial load
+ await expect(page.locator('input#name')).toBeVisible();
+ await page.fill('input#name', 'Initial Page');
+ await expect(page.locator('h3')).toContainText('Initial Page');
+
+ // 3. Click a Turbo link to navigate to second page
+ await page.click('a[href="/react_router/second_page"]');
+ await page.waitForURL('/react_router/second_page');
+
+ // 4. Verify JavaScript STILL works after Turbo navigation
+ await expect(page.locator('input#name')).toBeVisible();
+ await page.fill('input#name', 'After Turbo Navigation');
+ await expect(page.locator('h3')).toContainText('After Turbo Navigation');
+
+ // 5. Navigate back
+ await page.click('a[href="/react_router"]');
+ await page.waitForURL('/react_router');
+
+ // 6. Verify JavaScript works after navigating back
+ await expect(page.locator('input#name')).toBeVisible();
+ await page.fill('input#name', 'After Back Navigation');
+ await expect(page.locator('h3')).toContainText('After Back Navigation');
+});
+```
+
+### What This Test Catches
+
+✅ JavaScript execution after Turbo navigation
+✅ React component hydration on client-side page loads
+✅ Proper data attributes for Turbo compatibility
+✅ Component lifecycle management with Turbo
+
+## Verification Steps
+
+To verify the Playwright test works correctly:
+
+### Step 1: Ensure Test Passes with Fix
+
+```bash
+# Current state (with fix) - test should PASS
+npm run test:e2e -- --grep "Turbo navigation"
+```
+
+### Step 2: Revert the Fix
+
+```bash
+# Revert to broken state
+git show f03b935d:spec/dummy/app/views/layouts/application.html.erb > spec/dummy/app/views/layouts/application.html.erb
+
+# Change line 13 back to:
+# <%= javascript_pack_tag('client-bundle', 'data-turbolinks-track': true) %>
+```
+
+### Step 3: Verify Test Fails
+
+```bash
+# With reverted fix - test should FAIL
+npm run test:e2e -- --grep "Turbo navigation"
+
+# Expected failure:
+# Error: Timeout waiting for element 'input#name' after Turbo navigation
+```
+
+### Step 4: Restore the Fix
+
+```bash
+# Restore the fix
+git checkout HEAD spec/dummy/app/views/layouts/application.html.erb
+
+# Test should PASS again
+npm run test:e2e -- --grep "Turbo navigation"
+```
+
+## Implementation Checklist
+
+- [ ] Create Playwright test file: `spec/dummy/spec/playwright/turbo_navigation.spec.js`
+- [ ] Add test that verifies React components work after Turbo navigation
+- [ ] Verify test passes with current fix in place
+- [ ] Manually revert fix and confirm test fails (proves test is effective)
+- [ ] Restore fix and confirm test passes again
+- [ ] Add test to CI pipeline
+- [ ] Document in CONTRIBUTING.md that Turbo navigation must be tested
+
+## Additional Test Cases to Consider
+
+1. **Multiple navigations**: Navigate through 3-4 pages to ensure no memory leaks
+2. **Back/forward buttons**: Test browser back/forward with Turbo
+3. **Turbo Frames**: Test components inside turbo frames
+4. **Turbo Streams**: Test components updated via turbo streams (Pro feature)
+5. **Redux stores**: Verify store state persists/resets appropriately
+
+## Files to Create/Modify
+
+```tree
+spec/dummy/spec/playwright/
+ ├── turbo_navigation.spec.js (new)
+ └── support/
+ └── turbo_helpers.js (new - optional helper functions)
+
+.github/workflows/
+ └── playwright.yml (update to run new tests)
+
+docs/contributor-info/
+ └── testing-turbo-navigation.md (new - documentation)
+```
+
+## Success Criteria
+
+- [ ] Playwright test exists and passes in CI
+- [ ] Test catches the regression when fix is reverted
+- [ ] Test is documented and maintainable
+- [ ] Test runs in <30 seconds
+- [ ] No false positives in CI
+
+## References
+
+- **Original Turbo PR**: #1620 (56ee2bd9)
+- **Fix commit**: f03b935d
+- **Turbo documentation**: docs/building-features/turbolinks.md
+- **Related issue**: This regression went undetected for 1+ year
+
+## Notes for Implementer
+
+- Use React on Rails Pro dummy app for testing (has more Turbo features)
+- Consider using Playwright's `page.route()` to simulate slow networks
+- Add `data-testid` attributes to components if needed for reliable selectors
+- Test both development and production webpack builds
+- Ensure test works with different Turbo Drive settings (`turbo: true/false`)
+
+---
+
+**Priority**: High - This prevents regressions in core Turbo functionality
+
+**Estimated effort**: 2-4 hours (including documentation and verification)
+
+**Labels**: testing, playwright, turbo, e2e, regression-prevention
diff --git a/eslint-rules/README.md b/eslint-rules/README.md
new file mode 100644
index 0000000000..ed543449e1
--- /dev/null
+++ b/eslint-rules/README.md
@@ -0,0 +1,110 @@
+# Custom ESLint Rules
+
+This directory contains custom ESLint rules specific to React on Rails.
+
+## Rules
+
+### `no-use-client-in-server-files`
+
+Prevents the `'use client'` directive from being used in `.server.tsx` and `.server.ts` files.
+
+#### Why This Rule Exists
+
+Files ending with `.server.tsx` are intended for server-side rendering in React Server Components (RSC) architecture. The `'use client'` directive forces webpack to bundle these files as client components, which creates a fundamental contradiction and causes errors when using React's `react-server` conditional exports.
+
+This issue became apparent with Shakapacker 9.3.0+, which properly honors `resolve.conditionNames` in webpack configurations. When webpack resolves imports with the `react-server` condition, React's server exports intentionally omit client-only APIs like:
+
+- `createContext`, `useContext`
+- `useState`, `useEffect`, `useLayoutEffect`, `useReducer`
+- `Component`, `PureComponent`
+- Other hooks (`use*` functions)
+
+#### Examples
+
+❌ **Incorrect** - Will trigger an error:
+
+```typescript
+// Component.server.tsx
+'use client';
+
+import React from 'react';
+
+export function MyComponent() {
+ return
Component
;
+}
+```
+
+✅ **Correct** - No directive in server files:
+
+```typescript
+// Component.server.tsx
+import React from 'react';
+
+export function MyComponent() {
+ return Component
;
+}
+```
+
+✅ **Correct** - Use `'use client'` in client files:
+
+```typescript
+// Component.client.tsx or Component.tsx
+'use client';
+
+import React, { useState } from 'react';
+
+export function MyComponent() {
+ const [count, setCount] = useState(0);
+ return Count: {count}
;
+}
+```
+
+#### Auto-fix
+
+This rule includes an automatic fixer that will remove the `'use client'` directive from `.server.tsx` files when you run ESLint with the `--fix` option:
+
+```bash
+npx eslint --fix path/to/file.server.tsx
+```
+
+#### Related
+
+- **Issue:** [Shakapacker #805 - Breaking change in 9.3.0](https://github.com/shakacode/shakapacker/issues/805)
+- **Fix PR:** [React on Rails #1896](https://github.com/shakacode/react_on_rails/pull/1896)
+- **Commit:** [86979dca - Remove 'use client' from .server.tsx files](https://github.com/shakacode/react_on_rails/commit/86979dca)
+
+#### Configuration
+
+This rule is automatically enabled in the React on Rails ESLint configuration at the `error` level. It's defined in `eslint.config.ts`:
+
+```typescript
+plugins: {
+ 'react-on-rails': {
+ rules: {
+ 'no-use-client-in-server-files': noUseClientInServerFiles,
+ },
+ },
+},
+
+rules: {
+ 'react-on-rails/no-use-client-in-server-files': 'error',
+ // ... other rules
+}
+```
+
+## Testing
+
+To run tests for the custom rules:
+
+```bash
+node eslint-rules/no-use-client-in-server-files.test.cjs
+```
+
+## Adding New Custom Rules
+
+To add a new custom ESLint rule:
+
+1. Create the rule file in this directory (use `.cjs` extension for CommonJS)
+2. Create a corresponding test file (e.g., `rule-name.test.cjs`)
+3. Import and register the rule in `eslint.config.ts`
+4. Add documentation to this README
diff --git a/eslint-rules/no-use-client-in-server-files.cjs b/eslint-rules/no-use-client-in-server-files.cjs
new file mode 100644
index 0000000000..1951a806f2
--- /dev/null
+++ b/eslint-rules/no-use-client-in-server-files.cjs
@@ -0,0 +1,77 @@
+/**
+ * @fileoverview Prevent 'use client' directive in .server.tsx files
+ * @author React on Rails Team
+ */
+
+/**
+ * ESLint rule to prevent 'use client' directives in .server.tsx files.
+ *
+ * Files ending with .server.tsx are intended for server-side rendering in
+ * React Server Components architecture. The 'use client' directive forces
+ * webpack to bundle these as client components, which causes errors when
+ * using React's react-server conditional exports with Shakapacker 9.3.0+.
+ *
+ * @type {import('eslint').Rule.RuleModule}
+ */
+module.exports = {
+ meta: {
+ type: 'problem',
+ docs: {
+ description: "Prevent 'use client' directive in .server.tsx files",
+ category: 'Best Practices',
+ recommended: true,
+ url: 'https://github.com/shakacode/react_on_rails/pull/1896',
+ },
+ messages: {
+ useClientInServerFile:
+ "Files with '.server.tsx' extension should not have 'use client' directive. " +
+ 'Server files are for React Server Components and should not use client-only APIs. ' +
+ 'If this component needs client-side features, rename it to .client.tsx or .tsx instead.',
+ },
+ schema: [],
+ fixable: 'code',
+ },
+
+ create(context) {
+ const filename = context.filename || context.getFilename();
+
+ // Only check .server.tsx files
+ if (!filename.endsWith('.server.tsx') && !filename.endsWith('.server.ts')) {
+ return {};
+ }
+
+ return {
+ Program(node) {
+ const sourceCode = context.sourceCode || context.getSourceCode();
+ const text = sourceCode.getText();
+
+ // Check for 'use client' directive at the start of the file
+ // Handle both single and double quotes, with or without semicolon
+ const useClientPattern = /^\s*['"]use client['"];?\s*$/m;
+ const match = text.match(useClientPattern);
+
+ if (match) {
+ // Find the exact position of the directive
+ const directiveIndex = text.indexOf(match[0]);
+
+ context.report({
+ node,
+ messageId: 'useClientInServerFile',
+ fix(fixer) {
+ // Remove the 'use client' directive and any trailing newlines
+ const start = directiveIndex;
+ let end = directiveIndex + match[0].length;
+
+ // Also remove the newline after the directive if present
+ if (text[end] === '\n') {
+ end += 1;
+ }
+
+ return fixer.removeRange([start, end]);
+ },
+ });
+ }
+ },
+ };
+ },
+};
diff --git a/eslint-rules/no-use-client-in-server-files.test.cjs b/eslint-rules/no-use-client-in-server-files.test.cjs
new file mode 100644
index 0000000000..da4567fdf8
--- /dev/null
+++ b/eslint-rules/no-use-client-in-server-files.test.cjs
@@ -0,0 +1,161 @@
+/**
+ * @fileoverview Tests for no-use-client-in-server-files rule
+ */
+
+const { RuleTester } = require('eslint');
+const rule = require('./no-use-client-in-server-files.cjs');
+
+const ruleTester = new RuleTester({
+ languageOptions: {
+ ecmaVersion: 2022,
+ sourceType: 'module',
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ },
+});
+
+ruleTester.run('no-use-client-in-server-files', rule, {
+ valid: [
+ {
+ code: `
+import React from 'react';
+
+export function ServerComponent() {
+ return Server Component
;
+}
+`,
+ filename: 'Component.server.tsx',
+ },
+ {
+ code: `
+import { renderToString } from 'react-dom/server';
+
+export function render() {
+ return renderToString(Hello
);
+}
+`,
+ filename: 'ComponentRenderer.server.tsx',
+ },
+ {
+ code: `
+'use client';
+
+import React from 'react';
+
+export function ClientComponent() {
+ return Client Component
;
+}
+`,
+ filename: 'Component.client.tsx',
+ },
+ {
+ code: `
+'use client';
+
+import React from 'react';
+
+export function ClientComponent() {
+ return Client Component
;
+}
+`,
+ filename: 'Component.tsx',
+ },
+ {
+ code: `
+import React from 'react';
+
+// This is fine - no 'use client' directive
+export function ServerComponent() {
+ return Server
;
+}
+`,
+ filename: 'App.server.ts',
+ },
+ ],
+
+ invalid: [
+ {
+ code: `'use client';
+
+import React from 'react';
+
+export function Component() {
+ return Component
;
+}
+`,
+ filename: 'Component.server.tsx',
+ errors: [
+ {
+ messageId: 'useClientInServerFile',
+ },
+ ],
+ output: `import React from 'react';
+
+export function Component() {
+ return Component
;
+}
+`,
+ },
+ {
+ code: `"use client";
+
+import React from 'react';
+`,
+ filename: 'Component.server.tsx',
+ errors: [
+ {
+ messageId: 'useClientInServerFile',
+ },
+ ],
+ output: `import React from 'react';
+`,
+ },
+ {
+ code: `'use client'
+
+import React from 'react';
+`,
+ filename: 'Component.server.tsx',
+ errors: [
+ {
+ messageId: 'useClientInServerFile',
+ },
+ ],
+ output: `import React from 'react';
+`,
+ },
+ {
+ code: ` 'use client';
+
+import wrapServerComponentRenderer from 'react-on-rails-pro/wrapServerComponentRenderer/server';
+`,
+ filename: 'AsyncOnServerSyncOnClient.server.tsx',
+ errors: [
+ {
+ messageId: 'useClientInServerFile',
+ },
+ ],
+ output: `import wrapServerComponentRenderer from 'react-on-rails-pro/wrapServerComponentRenderer/server';
+`,
+ },
+ {
+ code: `'use client';
+
+import React from 'react';
+`,
+ filename: 'Component.server.ts',
+ errors: [
+ {
+ messageId: 'useClientInServerFile',
+ },
+ ],
+ output: `import React from 'react';
+`,
+ },
+ ],
+});
+
+console.log('All tests passed!');
diff --git a/eslint.config.ts b/eslint.config.ts
index 13b6e5a40a..8ec7eac7e2 100644
--- a/eslint.config.ts
+++ b/eslint.config.ts
@@ -1,4 +1,5 @@
import path from 'node:path';
+import { fileURLToPath } from 'node:url';
import { globalIgnores } from 'eslint/config';
import jest from 'eslint-plugin-jest';
import prettierRecommended from 'eslint-plugin-prettier/recommended';
@@ -8,16 +9,21 @@ import tsEslint from 'typescript-eslint';
import { includeIgnoreFile } from '@eslint/compat';
import js from '@eslint/js';
import { FlatCompat } from '@eslint/eslintrc';
+import noUseClientInServerFiles from './eslint-rules/no-use-client-in-server-files.cjs';
+
+const filename = fileURLToPath(import.meta.url);
+// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
+const dirname = path.dirname(filename) as string;
const compat = new FlatCompat({
- baseDirectory: __dirname,
+ baseDirectory: dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
const config = tsEslint.config([
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
- includeIgnoreFile(path.resolve(__dirname, '.gitignore')),
+ includeIgnoreFile(path.resolve(dirname, '.gitignore')),
globalIgnores([
// compiled code
'packages/*/lib/',
@@ -84,7 +90,18 @@ const config = tsEslint.config([
},
},
+ plugins: {
+ 'react-on-rails': {
+ rules: {
+ 'no-use-client-in-server-files': noUseClientInServerFiles,
+ },
+ },
+ },
+
rules: {
+ // Custom React on Rails rules
+ 'react-on-rails/no-use-client-in-server-files': 'error',
+
'no-shadow': 'off',
'no-console': 'off',
'function-paren-newline': 'off',
diff --git a/knip.ts b/knip.ts
index 12801f717a..97f8e0c837 100644
--- a/knip.ts
+++ b/knip.ts
@@ -10,6 +10,7 @@ const config: KnipConfig = {
ignoreBinaries: [
// Has to be installed globally
'yalc',
+ // Used in package.json scripts (devDependency, so unlisted in production mode)
'nps',
// Pro package binaries used in Pro workflows
'playwright',
@@ -109,8 +110,9 @@ const config: KnipConfig = {
'bin/.*',
],
ignoreDependencies: [
- // Knip thinks it can be a devDependency, but it's supposed to be in dependencies.
+ // Build-time dependencies not detected by Knip in any mode
'@babel/runtime',
+ 'mini-css-extract-plugin',
// There's no ReScript plugin for Knip
'@rescript/react',
// The Babel plugin fails to detect it
@@ -120,17 +122,15 @@ const config: KnipConfig = {
'node-libs-browser',
// The below dependencies are not detected by the Webpack plugin
// due to the config issue.
- 'css-loader',
'expose-loader',
'file-loader',
'imports-loader',
- 'mini-css-extract-plugin',
'null-loader',
- 'sass',
- 'sass-loader',
'sass-resources-loader',
'style-loader',
'url-loader',
+ // Transitive dependency of shakapacker but listed as direct dependency
+ 'webpack-merge',
],
},
},
diff --git a/lib/generators/react_on_rails/base_generator.rb b/lib/generators/react_on_rails/base_generator.rb
index 6f8746a08e..78860c9019 100644
--- a/lib/generators/react_on_rails/base_generator.rb
+++ b/lib/generators/react_on_rails/base_generator.rb
@@ -2,6 +2,7 @@
require "rails/generators"
require "fileutils"
+require "yaml"
require_relative "generator_messages"
require_relative "generator_helper"
module ReactOnRails
@@ -37,12 +38,16 @@ def copy_base_files
app/views/layouts/hello_world.html.erb
Procfile.dev
Procfile.dev-static-assets
- Procfile.dev-prod-assets]
+ Procfile.dev-prod-assets
+ bin/shakapacker-precompile-hook]
base_templates = %w[config/initializers/react_on_rails.rb]
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
base_templates.each do |file|
template("#{base_path}/#{file}.tt", file)
end
+
+ # Make the hook script executable
+ File.chmod(0o755, "bin/shakapacker-precompile-hook") if File.exist?("bin/shakapacker-precompile-hook")
end
def copy_js_bundle_files
@@ -171,11 +176,21 @@ def add_react_dependencies
react_deps = %w[
react
react-dom
- @babel/preset-react
prop-types
- babel-plugin-transform-react-remove-prop-types
- babel-plugin-macros
]
+
+ # Add compiler-specific dependencies
+ # If using swc, add swc packages; otherwise add babel packages
+ react_deps += if using_swc?
+ %w[@swc/core swc-loader]
+ else
+ %w[
+ @babel/preset-react
+ babel-plugin-transform-react-remove-prop-types
+ babel-plugin-macros
+ ]
+ end
+
return if add_npm_dependencies(react_deps)
success = system("npm", "install", *react_deps)
@@ -208,6 +223,25 @@ def add_dev_dependencies
handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
end
+ def using_swc?
+ # Check shakapacker.yml for javascript_compiler setting
+ # Parse YAML to properly handle comments and get actual configured value
+ shakapacker_config_path = File.join(destination_root, "config", "shakapacker.yml")
+ return false unless File.exist?(shakapacker_config_path)
+
+ begin
+ config = YAML.safe_load_file(shakapacker_config_path)
+ # Check default section for javascript_compiler setting
+ javascript_compiler = config.dig("default", "javascript_compiler")
+ # Return true only if explicitly set to "swc"
+ javascript_compiler == "swc"
+ rescue StandardError => e
+ # If YAML parsing fails, default to babel (false)
+ puts "Warning: Could not parse shakapacker.yml: #{e.message}"
+ false
+ end
+ end
+
def install_js_dependencies
# Detect which package manager to use
success = if File.exist?(File.join(destination_root, "yarn.lock"))
diff --git a/lib/generators/react_on_rails/generator_helper.rb b/lib/generators/react_on_rails/generator_helper.rb
index 8ebb641592..fa34cea669 100644
--- a/lib/generators/react_on_rails/generator_helper.rb
+++ b/lib/generators/react_on_rails/generator_helper.rb
@@ -2,6 +2,7 @@
require "rainbow"
require "json"
+require_relative "generator_messages"
module GeneratorHelper
def package_json
@@ -95,4 +96,35 @@ def add_documentation_reference(message, source)
def component_extension(options)
options.typescript? ? "tsx" : "jsx"
end
+
+ # Detects the package manager based on lock files and returns the appropriate command and exact flag
+ # Returns: [package_manager, exact_flag, add_command]
+ # Examples: ["yarn", "--exact", "add"], ["npm", "--save-exact", "install"]
+ def detect_package_manager_and_exact_flag
+ lock_files = {
+ "yarn.lock" => ["yarn", "--exact", "add"],
+ "pnpm-lock.yaml" => ["pnpm", "--save-exact", "add"],
+ "bun.lockb" => ["bun", "--exact", "add"],
+ "package-lock.json" => ["npm", "--save-exact", "install"]
+ }
+
+ detected = []
+ lock_files.each do |lock_file, config|
+ detected << [lock_file, config] if File.exist?(File.join(destination_root, lock_file))
+ end
+
+ # Warn if multiple lock files detected
+ if detected.size > 1
+ GeneratorMessages.add_warning(<<~MSG.strip)
+ ⚠️ Multiple package manager lock files detected:
+ #{detected.map { |lf, _| " • #{lf}" }.join("\n")}
+
+ This can cause dependency conflicts. Consider using only one package manager.
+ Using #{detected.first[0]} based on file precedence.
+ MSG
+ end
+
+ # Return first detected, or default to npm
+ detected.empty? ? ["npm", "--save-exact", "install"] : detected.first[1]
+ end
end
diff --git a/lib/generators/react_on_rails/install_generator.rb b/lib/generators/react_on_rails/install_generator.rb
index b5769628d5..ec9f843aeb 100644
--- a/lib/generators/react_on_rails/install_generator.rb
+++ b/lib/generators/react_on_rails/install_generator.rb
@@ -37,6 +37,10 @@ class InstallGenerator < Rails::Generators::Base
# Removed: --skip-shakapacker-install (Shakapacker is now a required dependency)
def run_generators
+ # Set environment variable to skip validation during generator run
+ # This is inherited by all invoked generators
+ ENV["REACT_ON_RAILS_SKIP_VALIDATION"] = "true"
+
if installation_prerequisites_met? || options.ignore_warnings?
invoke_generators
add_bin_scripts
@@ -55,6 +59,7 @@ def run_generators
GeneratorMessages.add_error(error)
end
ensure
+ ENV.delete("REACT_ON_RAILS_SKIP_VALIDATION")
print_generator_messages
end
@@ -234,7 +239,7 @@ def ensure_shakapacker_in_gemfile
return if shakapacker_in_gemfile?
puts Rainbow("📝 Adding Shakapacker to Gemfile...").yellow
- success = system("bundle add shakapacker --strict")
+ success = system("bundle add shakapacker --version=9.3.0")
return if success
handle_shakapacker_gemfile_error
@@ -278,7 +283,7 @@ def handle_shakapacker_gemfile_error
• Gemfile permissions
Please try manually:
- bundle add shakapacker --strict
+ bundle add shakapacker --version=9.3.0
Then re-run: rails generate react_on_rails:install
MSG
@@ -430,25 +435,20 @@ def add_js_dependencies
def add_react_on_rails_package
major_minor_patch_only = /\A\d+\.\d+\.\d+\z/
- # Try to use package_json gem first, fall back to direct npm commands
+ # Use detected package manager with --save-exact flag to ensure exact version matching
react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
- ["react-on-rails@#{ReactOnRails::VERSION}"]
+ "react-on-rails@#{ReactOnRails::VERSION}"
else
puts "Adding the latest react-on-rails NPM module. " \
"Double check this is correct in package.json"
- ["react-on-rails"]
+ "react-on-rails"
end
puts "Installing React on Rails package..."
- if add_npm_dependencies(react_on_rails_pkg)
- @added_dependencies_to_package_json = true
- return
- end
-
- puts "Using direct npm commands as fallback"
- success = system("npm", "install", *react_on_rails_pkg)
+ package_manager, exact_flag, add_command = detect_package_manager_and_exact_flag
+ success = system(package_manager, add_command, exact_flag, react_on_rails_pkg)
@ran_direct_installs = true if success
- handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
+ handle_npm_failure("react-on-rails package", [react_on_rails_pkg]) unless success
end
def add_react_dependencies
@@ -466,7 +466,8 @@ def add_react_dependencies
return
end
- success = system("npm", "install", *react_deps)
+ package_manager, _exact_flag, add_command = detect_package_manager_and_exact_flag
+ success = system(package_manager, add_command, *react_deps)
@ran_direct_installs = true if success
handle_npm_failure("React dependencies", react_deps) unless success
end
@@ -484,7 +485,8 @@ def add_css_dependencies
return
end
- success = system("npm", "install", *css_deps)
+ package_manager, _exact_flag, add_command = detect_package_manager_and_exact_flag
+ success = system(package_manager, add_command, *css_deps)
@ran_direct_installs = true if success
handle_npm_failure("CSS dependencies", css_deps) unless success
end
@@ -494,13 +496,18 @@ def add_dev_dependencies
dev_deps = %w[
@pmmmwh/react-refresh-webpack-plugin
react-refresh
+ @swc/core
+ swc-loader
]
if add_npm_dependencies(dev_deps, dev: true)
@added_dependencies_to_package_json = true
return
end
- success = system("npm", "install", "--save-dev", *dev_deps)
+ package_manager, _exact_flag, add_command = detect_package_manager_and_exact_flag
+ # For dev dependencies, we need to add the --dev or -D flag depending on the package manager
+ dev_flag = package_manager == "npm" ? "--save-dev" : "-D"
+ success = system(package_manager, add_command, dev_flag, *dev_deps)
@ran_direct_installs = true if success
handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
end
diff --git a/lib/generators/react_on_rails/templates/base/base/bin/shakapacker-precompile-hook b/lib/generators/react_on_rails/templates/base/base/bin/shakapacker-precompile-hook
new file mode 100644
index 0000000000..9e755e09aa
--- /dev/null
+++ b/lib/generators/react_on_rails/templates/base/base/bin/shakapacker-precompile-hook
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+# Shakapacker precompile hook for React on Rails
+#
+# This script runs before webpack compilation to generate pack files
+# for auto-bundled components. It's called automatically by Shakapacker
+# when configured in config/shakapacker.yml:
+# precompile_hook: 'bin/shakapacker-precompile-hook'
+
+require_relative "../config/environment"
+
+begin
+ puts Rainbow("🔄 Running React on Rails precompile hook...").cyan
+ ReactOnRails::PacksGenerator.instance.generate_packs_if_stale
+rescue StandardError => e
+ warn Rainbow("❌ Error in precompile hook: #{e.message}").red
+ warn e.backtrace.first(5).join("\n")
+ exit 1
+end
diff --git a/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml b/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml
index 8f76d350b2..2a1994fbdd 100644
--- a/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml
+++ b/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml
@@ -42,6 +42,11 @@ default: &default
# Raises an error if there is a mismatch in the shakapacker gem and npm package being used
ensure_consistent_versioning: true
+ # Hook to run before webpack compilation (e.g., for generating dynamic entry points)
+ # SECURITY: Only reference trusted scripts within your project. The hook command will be
+ # validated to ensure it points to a file within the project root.
+ precompile_hook: 'bin/shakapacker-precompile-hook'
+
# Select whether the compiler will use SHA digest ('digest' option) or most recent modified timestamp ('mtime') to determine freshness
compiler_strategy: digest
diff --git a/lib/react_on_rails/configuration.rb b/lib/react_on_rails/configuration.rb
index 20be673d42..efac595d42 100644
--- a/lib/react_on_rails/configuration.rb
+++ b/lib/react_on_rails/configuration.rb
@@ -238,7 +238,11 @@ def adjust_precompile_task
raise(ReactOnRails::Error, compile_command_conflict_message) if ReactOnRails::PackerUtils.precompile?
precompile_tasks = lambda {
- Rake::Task["react_on_rails:generate_packs"].invoke
+ # Skip generate_packs if shakapacker has a precompile hook configured
+ unless ReactOnRails::PackerUtils.shakapacker_precompile_hook_configured?
+ Rake::Task["react_on_rails:generate_packs"].invoke
+ end
+
Rake::Task["react_on_rails:assets:webpack"].invoke
# VERSIONS is per the shakacode/shakapacker clean method definition.
diff --git a/lib/react_on_rails/dev/pack_generator.rb b/lib/react_on_rails/dev/pack_generator.rb
index 9e74bf0631..4387033b52 100644
--- a/lib/react_on_rails/dev/pack_generator.rb
+++ b/lib/react_on_rails/dev/pack_generator.rb
@@ -7,12 +7,18 @@ module Dev
class PackGenerator
class << self
def generate(verbose: false)
+ # Skip if shakapacker has a precompile hook configured
+ if ReactOnRails::PackerUtils.shakapacker_precompile_hook_configured?
+ puts "⏭️ Skipping pack generation (handled by shakapacker precompile hook)" if verbose
+ return
+ end
+
if verbose
puts "📦 Generating React on Rails packs..."
- success = system "bundle exec rake react_on_rails:generate_packs"
+ success = run_pack_generation
else
print "📦 Generating packs... "
- success = system "bundle exec rake react_on_rails:generate_packs > /dev/null 2>&1"
+ success = run_pack_generation(silent: true)
puts success ? "✅" : "❌"
end
@@ -21,6 +27,63 @@ def generate(verbose: false)
puts "❌ Pack generation failed"
exit 1
end
+
+ private
+
+ def run_pack_generation(silent: false)
+ # If we're already inside a Bundler context AND Rails is available (e.g., called from bin/dev),
+ # we can directly require and run the task. Otherwise, use bundle exec.
+ if defined?(Bundler) && rails_available?
+ run_rake_task_directly(silent: silent)
+ else
+ run_via_bundle_exec(silent: silent)
+ end
+ end
+
+ def rails_available?
+ return false unless defined?(Rails)
+ return false unless Rails.respond_to?(:application)
+ return false if Rails.application.nil?
+
+ true
+ end
+
+ def run_rake_task_directly(silent: false)
+ require "rake"
+
+ # Load tasks only if not already loaded (don't clear all tasks)
+ Rails.application.load_tasks unless Rake::Task.task_defined?("react_on_rails:generate_packs")
+
+ if silent
+ original_stdout = $stdout
+ original_stderr = $stderr
+ $stdout = StringIO.new
+ $stderr = StringIO.new
+ end
+
+ begin
+ task = Rake::Task["react_on_rails:generate_packs"]
+ task.reenable # Allow re-execution if called multiple times
+ task.invoke
+ true
+ rescue StandardError => e
+ warn "Error generating packs: #{e.message}" unless silent
+ false
+ ensure
+ if silent
+ $stdout = original_stdout
+ $stderr = original_stderr
+ end
+ end
+ end
+
+ def run_via_bundle_exec(silent: false)
+ if silent
+ system "bundle exec rake react_on_rails:generate_packs > /dev/null 2>&1"
+ else
+ system "bundle exec rake react_on_rails:generate_packs"
+ end
+ end
end
end
end
diff --git a/lib/react_on_rails/dev/server_manager.rb b/lib/react_on_rails/dev/server_manager.rb
index 29169e8578..64d0cdea17 100644
--- a/lib/react_on_rails/dev/server_manager.rb
+++ b/lib/react_on_rails/dev/server_manager.rb
@@ -248,7 +248,7 @@ def help_mode_details
<<~MODES
#{Rainbow('🔥 HMR Development mode (default)').cyan.bold} - #{Rainbow('Procfile.dev').green}:
#{Rainbow('•').yellow} #{Rainbow('Hot Module Replacement (HMR) enabled').white}
- #{Rainbow('•').yellow} #{Rainbow('React on Rails pack generation before Procfile start').white}
+ #{Rainbow('•').yellow} #{Rainbow('React on Rails pack generation (via precompile hook or bin/dev)').white}
#{Rainbow('•').yellow} #{Rainbow('Webpack dev server for fast recompilation').white}
#{Rainbow('•').yellow} #{Rainbow('Source maps for debugging').white}
#{Rainbow('•').yellow} #{Rainbow('May have Flash of Unstyled Content (FOUC)').white}
@@ -257,7 +257,7 @@ def help_mode_details
#{Rainbow('📦 Static development mode').cyan.bold} - #{Rainbow('Procfile.dev-static-assets').green}:
#{Rainbow('•').yellow} #{Rainbow('No HMR (static assets with auto-recompilation)').white}
- #{Rainbow('•').yellow} #{Rainbow('React on Rails pack generation before Procfile start').white}
+ #{Rainbow('•').yellow} #{Rainbow('React on Rails pack generation (via precompile hook or bin/dev)').white}
#{Rainbow('•').yellow} #{Rainbow('Webpack watch mode for auto-recompilation').white}
#{Rainbow('•').yellow} #{Rainbow('CSS extracted to separate files (no FOUC)').white}
#{Rainbow('•').yellow} #{Rainbow('Development environment (faster builds than production)').white}
@@ -265,7 +265,7 @@ def help_mode_details
#{Rainbow('•').yellow} #{Rainbow('Access at:').white} #{Rainbow('http://localhost:3000/').cyan.underline}
#{Rainbow('🏭 Production-assets mode').cyan.bold} - #{Rainbow('Procfile.dev-prod-assets').green}:
- #{Rainbow('•').yellow} #{Rainbow('React on Rails pack generation before Procfile start').white}
+ #{Rainbow('•').yellow} #{Rainbow('React on Rails pack generation (via precompile hook or assets:precompile)').white}
#{Rainbow('•').yellow} #{Rainbow('Asset precompilation with NODE_ENV=production (webpack optimizations)').white}
#{Rainbow('•').yellow} #{Rainbow('RAILS_ENV=development by default for assets:precompile (avoids credentials)').white}
#{Rainbow('•').yellow} #{Rainbow('Use --rails-env=production for assets:precompile only (not server processes)').white}
@@ -281,16 +281,20 @@ def help_mode_details
def run_production_like(_verbose: false, route: nil, rails_env: nil)
procfile = "Procfile.dev-prod-assets"
+ features = [
+ "Precompiling assets with production optimizations",
+ "Running Rails server on port 3001",
+ "No HMR (Hot Module Replacement)",
+ "CSS extracted to separate files (no FOUC)"
+ ]
+
+ # NOTE: Pack generation happens automatically during assets:precompile
+ # either via precompile hook or via the configuration.rb adjust_precompile_task
+
print_procfile_info(procfile, route: route)
print_server_info(
"🏭 Starting production-like development server...",
- [
- "Generating React on Rails packs",
- "Precompiling assets with production optimizations",
- "Running Rails server on port 3001",
- "No HMR (Hot Module Replacement)",
- "CSS extracted to separate files (no FOUC)"
- ],
+ features,
3001,
route: route
)
@@ -409,15 +413,22 @@ def run_production_like(_verbose: false, route: nil, rails_env: nil)
def run_static_development(procfile, verbose: false, route: nil)
print_procfile_info(procfile, route: route)
+
+ features = [
+ "Using shakapacker --watch (no HMR)",
+ "CSS extracted to separate files (no FOUC)",
+ "Development environment (source maps, faster builds)",
+ "Auto-recompiles on file changes"
+ ]
+
+ # Add pack generation info if not using precompile hook
+ unless ReactOnRails::PackerUtils.shakapacker_precompile_hook_configured?
+ features.unshift("Generating React on Rails packs")
+ end
+
print_server_info(
"⚡ Starting development server with static assets...",
- [
- "Generating React on Rails packs",
- "Using shakapacker --watch (no HMR)",
- "CSS extracted to separate files (no FOUC)",
- "Development environment (source maps, faster builds)",
- "Auto-recompiles on file changes"
- ],
+ features,
route: route
)
diff --git a/lib/react_on_rails/engine.rb b/lib/react_on_rails/engine.rb
index 6369839f0f..6b139c841e 100644
--- a/lib/react_on_rails/engine.rb
+++ b/lib/react_on_rails/engine.rb
@@ -6,8 +6,23 @@ module ReactOnRails
class Engine < ::Rails::Engine
# Validate package versions and compatibility on Rails startup
# This ensures the application fails fast if versions don't match or packages are misconfigured
+ # Skip validation during installation tasks (e.g., shakapacker:install, react_on_rails:install)
initializer "react_on_rails.validate_version_and_package_compatibility" do
config.after_initialize do
+ # Skip validation if package.json doesn't exist yet (during initial setup)
+ package_json = VersionChecker::NodePackageVersion.package_json_path
+ next unless File.exist?(package_json)
+
+ # Skip validation when generators explicitly set this flag (packages may not be installed yet)
+ next if ENV["REACT_ON_RAILS_SKIP_VALIDATION"] == "true"
+
+ # Skip validation if react-on-rails package is not installed yet (during generator run)
+ # This allows generators to complete before the package is installed
+ node_package_version = VersionChecker::NodePackageVersion.build
+ has_base = node_package_version.react_on_rails_package?
+ has_pro = node_package_version.react_on_rails_pro_package?
+ next unless has_base || has_pro
+
Rails.logger.info "[React on Rails] Validating package version and compatibility..."
VersionChecker.build.validate_version_and_package_compatibility!
Rails.logger.info "[React on Rails] Package validation successful"
diff --git a/lib/react_on_rails/packer_utils.rb b/lib/react_on_rails/packer_utils.rb
index d6e6511000..4cdbaf3a00 100644
--- a/lib/react_on_rails/packer_utils.rb
+++ b/lib/react_on_rails/packer_utils.rb
@@ -166,5 +166,18 @@ def self.raise_shakapacker_version_incompatible_for_basic_pack_generation
raise ReactOnRails::Error, msg
end
+
+ # Check if shakapacker.yml has a precompile_hook configured
+ # This prevents react_on_rails from running generate_packs redundantly
+ def self.shakapacker_precompile_hook_configured?
+ return false unless defined?(::Shakapacker)
+
+ config_data = ::Shakapacker.config.send(:data)
+ hook = config_data[:precompile_hook]
+
+ hook.present?
+ rescue StandardError
+ false
+ end
end
end
diff --git a/package-scripts.yml b/package-scripts.yml
index 26657f1441..6027491034 100644
--- a/package-scripts.yml
+++ b/package-scripts.yml
@@ -26,7 +26,7 @@ scripts:
# 4. If it failed, print an error message (still follow https://docs.npmjs.com/cli/v8/using-npm/scripts#best-practices).
script: >
[ -f packages/react-on-rails/lib/ReactOnRails.full.js ] ||
- (npm run build >/dev/null 2>&1 || true) &&
+ (yarn run build >/dev/null 2>&1 || true) &&
[ -f packages/react-on-rails/lib/ReactOnRails.full.js ] ||
{ echo 'Building react-on-rails seems to have failed!'; }
diff --git a/packages/react-on-rails-pro/src/RSCProvider.tsx b/packages/react-on-rails-pro/src/RSCProvider.tsx
index 3a25161d0e..3fa5043810 100644
--- a/packages/react-on-rails-pro/src/RSCProvider.tsx
+++ b/packages/react-on-rails-pro/src/RSCProvider.tsx
@@ -12,14 +12,17 @@
* https://github.com/shakacode/react_on_rails/blob/master/REACT-ON-RAILS-PRO-LICENSE.md
*/
-import * as React from 'react';
+import type { ReactNode } from 'react';
+import ReactClient from 'react/index.js';
import type { ClientGetReactServerComponentProps } from './getReactServerComponent.client.ts';
import { createRSCPayloadKey } from './utils.ts';
+const React = ReactClient;
+
type RSCContextType = {
- getComponent: (componentName: string, componentProps: unknown) => Promise;
+ getComponent: (componentName: string, componentProps: unknown) => Promise;
- refetchComponent: (componentName: string, componentProps: unknown) => Promise;
+ refetchComponent: (componentName: string, componentProps: unknown) => Promise;
};
const RSCContext = React.createContext(undefined);
@@ -46,9 +49,9 @@ const RSCContext = React.createContext(undefined);
export const createRSCProvider = ({
getServerComponent,
}: {
- getServerComponent: (props: ClientGetReactServerComponentProps) => Promise;
+ getServerComponent: (props: ClientGetReactServerComponentProps) => Promise;
}) => {
- const fetchRSCPromises: Record> = {};
+ const fetchRSCPromises: Record> = {};
const getComponent = (componentName: string, componentProps: unknown) => {
const key = createRSCPayloadKey(componentName, componentProps);
@@ -74,7 +77,7 @@ export const createRSCProvider = ({
const contextValue = { getComponent, refetchComponent };
- return ({ children }: { children: React.ReactNode }) => {
+ return ({ children }: { children: ReactNode }) => {
return {children};
};
};
diff --git a/packages/react-on-rails-pro/src/RSCRoute.tsx b/packages/react-on-rails-pro/src/RSCRoute.tsx
index 84d2a4b34c..3c736d71e7 100644
--- a/packages/react-on-rails-pro/src/RSCRoute.tsx
+++ b/packages/react-on-rails-pro/src/RSCRoute.tsx
@@ -14,21 +14,22 @@
///
-'use client';
-
-import * as React from 'react';
+import type { ReactNode } from 'react';
+import ReactClient from 'react/index.js';
import { useRSC } from './RSCProvider.tsx';
import { ServerComponentFetchError } from './ServerComponentFetchError.ts';
+const React = ReactClient;
+
/**
* Error boundary component for RSCRoute that adds server component name and props to the error
* So, the parent ErrorBoundary can refetch the server component
*/
class RSCRouteErrorBoundary extends React.Component<
- { children: React.ReactNode; componentName: string; componentProps: unknown },
+ { children: ReactNode; componentName: string; componentProps: unknown },
{ error: Error | null }
> {
- constructor(props: { children: React.ReactNode; componentName: string; componentProps: unknown }) {
+ constructor(props: { children: ReactNode; componentName: string; componentProps: unknown }) {
super(props);
this.state = { error: null };
}
@@ -75,7 +76,7 @@ export type RSCRouteProps = {
componentProps: unknown;
};
-const PromiseWrapper = ({ promise }: { promise: Promise }) => {
+const PromiseWrapper = ({ promise }: { promise: Promise }) => {
// React.use is available in React 18.3+
const promiseResult = React.use(promise);
@@ -88,7 +89,7 @@ const PromiseWrapper = ({ promise }: { promise: Promise }) => {
return promiseResult;
};
-const RSCRoute = ({ componentName, componentProps }: RSCRouteProps): React.ReactNode => {
+const RSCRoute = ({ componentName, componentProps }: RSCRouteProps): ReactNode => {
const { getComponent } = useRSC();
const componentPromise = getComponent(componentName, componentProps);
return (
diff --git a/rakelib/shakapacker_examples.rake b/rakelib/shakapacker_examples.rake
index c17f2f8e0a..a819788ff8 100644
--- a/rakelib/shakapacker_examples.rake
+++ b/rakelib/shakapacker_examples.rake
@@ -34,7 +34,7 @@ namespace :shakapacker_examples do # rubocop:disable Metrics/BlockLength
sh_in_dir(example_type.dir, "touch .gitignore")
sh_in_dir(example_type.dir,
"echo \"gem 'react_on_rails', path: '#{relative_gem_root}'\" >> #{example_type.gemfile}")
- sh_in_dir(example_type.dir, "echo \"gem 'shakapacker', '>= 8.2.0'\" >> #{example_type.gemfile}")
+ sh_in_dir(example_type.dir, "echo \"gem 'shakapacker', '>= 9.3.0'\" >> #{example_type.gemfile}")
bundle_install_in(example_type.dir)
sh_in_dir(example_type.dir, "rake shakapacker:install")
sh_in_dir(example_type.dir, example_type.generator_shell_commands)
diff --git a/react_on_rails_pro/Gemfile.development_dependencies b/react_on_rails_pro/Gemfile.development_dependencies
index c65a5319e2..92c9ead62b 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.3.0"
gem "bootsnap", require: false
gem "rails", "~> 7.1"
gem "puma", "~> 6"
diff --git a/react_on_rails_pro/spec/dummy/client/app/components/HelloWorld.module.scss b/react_on_rails_pro/spec/dummy/client/app/components/HelloWorld.module.scss
index ae58c25083..3b77eb394e 100644
--- a/react_on_rails_pro/spec/dummy/client/app/components/HelloWorld.module.scss
+++ b/react_on_rails_pro/spec/dummy/client/app/components/HelloWorld.module.scss
@@ -1,3 +1,5 @@
+@import "../assets/styles/app-variables.scss";
+
.brightColor {
color: $bright-color;
-}
\ No newline at end of file
+}
diff --git a/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncOnServerSyncOnClient.server.tsx b/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncOnServerSyncOnClient.server.tsx
index 43a81025e5..71f0f0448e 100644
--- a/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncOnServerSyncOnClient.server.tsx
+++ b/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/AsyncOnServerSyncOnClient.server.tsx
@@ -1,5 +1,3 @@
-'use client';
-
import wrapServerComponentRenderer from 'react-on-rails-pro/wrapServerComponentRenderer/server';
import AsyncOnServerSyncOnClient from '../components/AsyncOnServerSyncOnClient';
diff --git a/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/LazyApolloGraphQLApp.server.tsx b/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/LazyApolloGraphQLApp.server.tsx
index 22c3e3d2eb..23d92a1222 100644
--- a/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/LazyApolloGraphQLApp.server.tsx
+++ b/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/LazyApolloGraphQLApp.server.tsx
@@ -1,5 +1,3 @@
-'use client';
-
import React from 'react';
import { renderToString } from 'react-dom/server';
import { getMarkupFromTree } from '@apollo/client/react/ssr';
diff --git a/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ServerComponentRouter.server.tsx b/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ServerComponentRouter.server.tsx
index bb32707ecd..9ff1886628 100644
--- a/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ServerComponentRouter.server.tsx
+++ b/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/ServerComponentRouter.server.tsx
@@ -1,5 +1,3 @@
-'use client';
-
import * as React from 'react';
import { StaticRouter } from 'react-router-dom/server.js';
import { RailsContext, ReactComponentOrRenderFunction } from 'react-on-rails-pro';
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..05f2a03295 100644
--- a/react_on_rails_pro/spec/dummy/config/webpack/commonWebpackConfig.js
+++ b/react_on_rails_pro/spec/dummy/config/webpack/commonWebpackConfig.js
@@ -29,7 +29,9 @@ const baseClientWebpackConfig = generateWebpackConfig();
const scssConfigIndex = baseClientWebpackConfig.module.rules.findIndex((config) =>
'.scss'.match(config.test),
);
-baseClientWebpackConfig.module.rules[scssConfigIndex].use.push(sassLoaderConfig);
+if (scssConfigIndex !== -1 && baseClientWebpackConfig.module.rules[scssConfigIndex]?.use) {
+ baseClientWebpackConfig.module.rules[scssConfigIndex].use.push(sassLoaderConfig);
+}
if (isHMR) {
baseClientWebpackConfig.plugins.push(
diff --git a/react_on_rails_pro/spec/dummy/package.json b/react_on_rails_pro/spec/dummy/package.json
index 055bc02474..f20b4e7e71 100644
--- a/react_on_rails_pro/spec/dummy/package.json
+++ b/react_on_rails_pro/spec/dummy/package.json
@@ -63,7 +63,6 @@
"sass": "^1.43.4",
"sass-loader": "^12.3.0",
"sass-resources-loader": "^2.0.0",
- "shakapacker": "8.0.0",
"style-loader": "^3.3.1",
"tailwindcss": "^3.2.7",
"terser-webpack-plugin": "5",
@@ -79,6 +78,7 @@
"@babel/preset-typescript": "^7.23.2",
"@playwright/test": "^1.56.1",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.3",
+ "@swc/core": "^1.7.0",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/typography": "^0.5.9",
@@ -88,6 +88,8 @@
"jsdom": "^16.4.0",
"pino-pretty": "^13.0.0",
"preload-webpack-plugin": "^3.0.0-alpha.1",
+ "shakapacker": "9.3.0",
+ "swc-loader": "^0.2.6",
"typescript": "^5.2.2",
"webpack-dev-server": "^4.7.3"
},
diff --git a/react_on_rails_pro/spec/dummy/yarn.lock b/react_on_rails_pro/spec/dummy/yarn.lock
index c7d322fe25..3b1c509cfd 100644
--- a/react_on_rails_pro/spec/dummy/yarn.lock
+++ b/react_on_rails_pro/spec/dummy/yarn.lock
@@ -1245,6 +1245,87 @@
resolved "https://registry.yarnpkg.com/@shakacode/use-ssr-computation.runtime/-/use-ssr-computation.runtime-2.0.0.tgz#3944be3dd57e036d794def69bd7a10cc26978e95"
integrity sha512-cWeekG6ehf3TtBUWmKtitQgXZOcqLlodmzCccWniAsE+1VmwcIJzCagTu72Ocq8fCtgfdMs94XSu314zfeWFAw==
+"@swc/core-darwin-arm64@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.14.0.tgz#1db614b52ed7369f47be2a1c6b5e80b6be923898"
+ integrity sha512-uHPC8rlCt04nvYNczWzKVdgnRhxCa3ndKTBBbBpResOZsRmiwRAvByIGh599j+Oo6Z5eyTPrgY+XfJzVmXnN7Q==
+
+"@swc/core-darwin-x64@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.14.0.tgz#900e56924994d0e723e6088e2a2e1a1c08c59a95"
+ integrity sha512-2SHrlpl68vtePRknv9shvM9YKKg7B9T13tcTg9aFCwR318QTYo+FzsKGmQSv9ox/Ua0Q2/5y2BNjieffJoo4nA==
+
+"@swc/core-linux-arm-gnueabihf@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.14.0.tgz#3c84966a8c6e308b0788d1c7875bce23c65134c6"
+ integrity sha512-SMH8zn01dxt809svetnxpeg/jWdpi6dqHKO3Eb11u4OzU2PK7I5uKS6gf2hx5LlTbcJMFKULZiVwjlQLe8eqtg==
+
+"@swc/core-linux-arm64-gnu@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.14.0.tgz#5190097d2ca4ea8b198f46a3abe2272331575b54"
+ integrity sha512-q2JRu2D8LVqGeHkmpVCljVNltG0tB4o4eYg+dElFwCS8l2Mnt9qurMCxIeo9mgoqz0ax+k7jWtIRHktnVCbjvQ==
+
+"@swc/core-linux-arm64-musl@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.14.0.tgz#420f510102a37feda0e3dfb8d21651515251476b"
+ integrity sha512-uofpVoPCEUjYIv454ZEZ3sLgMD17nIwlz2z7bsn7rl301Kt/01umFA7MscUovFfAK2IRGck6XB+uulMu6aFhKQ==
+
+"@swc/core-linux-x64-gnu@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.14.0.tgz#953f741d577a81f6e1e1b434856c48eb674cdeb7"
+ integrity sha512-quTTx1Olm05fBfv66DEBuOsOgqdypnZ/1Bh3yGXWY7ANLFeeRpCDZpljD9BSjdsNdPOlwJmEUZXMHtGm3v1TZQ==
+
+"@swc/core-linux-x64-musl@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.14.0.tgz#bdf241062d1433ba617ffe1451dccde8923a28a2"
+ integrity sha512-caaNAu+aIqT8seLtCf08i8C3/UC5ttQujUjejhMcuS1/LoCKtNiUs4VekJd2UGt+pyuuSrQ6dKl8CbCfWvWeXw==
+
+"@swc/core-win32-arm64-msvc@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.14.0.tgz#960919015bc31c46a8fc10df5c384add651df91e"
+ integrity sha512-EeW3jFlT3YNckJ6V/JnTfGcX7UHGyh6/AiCPopZ1HNaGiXVCKHPpVQZicmtyr/UpqxCXLrTgjHOvyMke7YN26A==
+
+"@swc/core-win32-ia32-msvc@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.14.0.tgz#826a76b2af0e4df4dee3674e91734cb85eb7b21f"
+ integrity sha512-dPai3KUIcihV5hfoO4QNQF5HAaw8+2bT7dvi8E5zLtecW2SfL3mUZipzampXq5FHll0RSCLzlrXnSx+dBRZIIQ==
+
+"@swc/core-win32-x64-msvc@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.14.0.tgz#75fe708a702f57f176fd640eb9af394cf767be91"
+ integrity sha512-nm+JajGrTqUA6sEHdghDlHMNfH1WKSiuvljhdmBACW4ta4LC3gKurX2qZuiBARvPkephW9V/i5S8QPY1PzFEqg==
+
+"@swc/core@^1.7.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core/-/core-1.14.0.tgz#ff7d287fbac6b6fd3adedf7b440cadfd0c389df6"
+ integrity sha512-oExhY90bes5pDTVrei0xlMVosTxwd/NMafIpqsC4dMbRYZ5KB981l/CX8tMnGsagTplj/RcG9BeRYmV6/J5m3w==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+ "@swc/types" "^0.1.25"
+ optionalDependencies:
+ "@swc/core-darwin-arm64" "1.14.0"
+ "@swc/core-darwin-x64" "1.14.0"
+ "@swc/core-linux-arm-gnueabihf" "1.14.0"
+ "@swc/core-linux-arm64-gnu" "1.14.0"
+ "@swc/core-linux-arm64-musl" "1.14.0"
+ "@swc/core-linux-x64-gnu" "1.14.0"
+ "@swc/core-linux-x64-musl" "1.14.0"
+ "@swc/core-win32-arm64-msvc" "1.14.0"
+ "@swc/core-win32-ia32-msvc" "1.14.0"
+ "@swc/core-win32-x64-msvc" "1.14.0"
+
+"@swc/counter@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
+ integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
+
+"@swc/types@^0.1.25":
+ version "0.1.25"
+ resolved "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz#b517b2a60feb37dd933e542d93093719e4cf1078"
+ integrity sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+
"@tailwindcss/aspect-ratio@^0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz#9ffd52fee8e3c8b20623ff0dcb29e5c21fb0a9ba"
@@ -2262,6 +2343,15 @@ cliui@^5.0.0:
strip-ansi "^5.2.0"
wrap-ansi "^5.1.0"
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -2997,7 +3087,7 @@ es5-shim@^4.5.9:
resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.6.7.tgz#bc67ae0fc3dd520636e0a1601cc73b450ad3e955"
integrity sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==
-escalade@^3.2.0:
+escalade@^3.1.1, escalade@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
@@ -3443,7 +3533,7 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-get-caller-file@^2.0.1:
+get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
@@ -5970,13 +6060,15 @@ 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.3.0:
+ version "9.3.0"
+ resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-9.3.0.tgz#a73f1d17aebf85768da522ec2552d5f2867f8481"
+ integrity sha512-q3gug4dZhJRLe8LHQOwG5jx7Jik0T+ZcMxEhiTyEAuIN8cIt4eek6gCn4OQdIqhdZXAiUBCUpfIHdWt9yUO9/g==
dependencies:
js-yaml "^4.1.0"
path-complete-extname "^1.0.0"
+ webpack-merge "^5.8.0"
+ yargs "^17.7.2"
shallow-clone@^3.0.0:
version "3.0.1"
@@ -6172,7 +6264,7 @@ stream-http@^2.7.2:
to-arraybuffer "^1.0.0"
xtend "^4.0.0"
-"string-width-cjs@npm:string-width@^4.2.0":
+"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -6190,15 +6282,6 @@ string-width@^3.0.0, string-width@^3.1.0:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
-string-width@^4.1.0:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
string-width@^5.0.1, string-width@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
@@ -6222,7 +6305,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -6236,13 +6319,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
dependencies:
ansi-regex "^4.1.0"
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -6330,6 +6406,13 @@ svgo@^2.7.0:
picocolors "^1.0.0"
stable "^0.1.8"
+swc-loader@^0.2.6:
+ version "0.2.6"
+ resolved "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz#bf0cba8eeff34bb19620ead81d1277fefaec6bc8"
+ integrity sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+
symbol-observable@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205"
@@ -6815,7 +6898,7 @@ 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"
integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==
@@ -6936,6 +7019,15 @@ wrap-ansi@^5.1.0:
string-width "^3.0.0"
strip-ansi "^5.0.0"
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
@@ -6980,6 +7072,11 @@ y18n@^4.0.0:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
yallist@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
@@ -7003,6 +7100,11 @@ yargs-parser@^15.0.0:
camelcase "^5.0.0"
decamelize "^1.2.0"
+yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
yargs@14.2.0:
version "14.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.0.tgz#f116a9242c4ed8668790b40759b4906c276e76c3"
@@ -7020,6 +7122,19 @@ yargs@14.2.0:
y18n "^4.0.0"
yargs-parser "^15.0.0"
+yargs@^17.7.2:
+ version "17.7.2"
+ resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
+
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
diff --git a/react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile b/react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile
index 466feb7f95..dfff5f4495 100644
--- a/react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile
+++ b/react_on_rails_pro/spec/execjs-compatible-dummy/Gemfile
@@ -2,7 +2,7 @@
source "https://rubygems.org"
-ruby "3.3.7"
+ruby ">= 3.0.0", "< 3.5.0"
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.1", ">= 7.1.3.2"
@@ -61,7 +61,7 @@ group :test do
gem "selenium-webdriver"
end
-gem "shakapacker", "= 8.0"
+gem "shakapacker", "= 9.3.0"
gem "react_on_rails", path: "../../.."
gem "react_on_rails_pro", path: "../.."
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..1f6cd2885d 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.3.0",
"style-loader": "^4.0.0",
"terser-webpack-plugin": "5",
"webpack": "5",
@@ -44,7 +44,9 @@
},
"devDependencies": {
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
+ "@swc/core": "^1.7.0",
"react-refresh": "^0.14.2",
+ "swc-loader": "^0.2.6",
"webpack-dev-server": "4"
}
}
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..4b79f9d520 100644
--- a/react_on_rails_pro/spec/execjs-compatible-dummy/yarn.lock
+++ b/react_on_rails_pro/spec/execjs-compatible-dummy/yarn.lock
@@ -934,6 +934,87 @@
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
+"@swc/core-darwin-arm64@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.14.0.tgz#1db614b52ed7369f47be2a1c6b5e80b6be923898"
+ integrity sha512-uHPC8rlCt04nvYNczWzKVdgnRhxCa3ndKTBBbBpResOZsRmiwRAvByIGh599j+Oo6Z5eyTPrgY+XfJzVmXnN7Q==
+
+"@swc/core-darwin-x64@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.14.0.tgz#900e56924994d0e723e6088e2a2e1a1c08c59a95"
+ integrity sha512-2SHrlpl68vtePRknv9shvM9YKKg7B9T13tcTg9aFCwR318QTYo+FzsKGmQSv9ox/Ua0Q2/5y2BNjieffJoo4nA==
+
+"@swc/core-linux-arm-gnueabihf@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.14.0.tgz#3c84966a8c6e308b0788d1c7875bce23c65134c6"
+ integrity sha512-SMH8zn01dxt809svetnxpeg/jWdpi6dqHKO3Eb11u4OzU2PK7I5uKS6gf2hx5LlTbcJMFKULZiVwjlQLe8eqtg==
+
+"@swc/core-linux-arm64-gnu@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.14.0.tgz#5190097d2ca4ea8b198f46a3abe2272331575b54"
+ integrity sha512-q2JRu2D8LVqGeHkmpVCljVNltG0tB4o4eYg+dElFwCS8l2Mnt9qurMCxIeo9mgoqz0ax+k7jWtIRHktnVCbjvQ==
+
+"@swc/core-linux-arm64-musl@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.14.0.tgz#420f510102a37feda0e3dfb8d21651515251476b"
+ integrity sha512-uofpVoPCEUjYIv454ZEZ3sLgMD17nIwlz2z7bsn7rl301Kt/01umFA7MscUovFfAK2IRGck6XB+uulMu6aFhKQ==
+
+"@swc/core-linux-x64-gnu@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.14.0.tgz#953f741d577a81f6e1e1b434856c48eb674cdeb7"
+ integrity sha512-quTTx1Olm05fBfv66DEBuOsOgqdypnZ/1Bh3yGXWY7ANLFeeRpCDZpljD9BSjdsNdPOlwJmEUZXMHtGm3v1TZQ==
+
+"@swc/core-linux-x64-musl@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.14.0.tgz#bdf241062d1433ba617ffe1451dccde8923a28a2"
+ integrity sha512-caaNAu+aIqT8seLtCf08i8C3/UC5ttQujUjejhMcuS1/LoCKtNiUs4VekJd2UGt+pyuuSrQ6dKl8CbCfWvWeXw==
+
+"@swc/core-win32-arm64-msvc@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.14.0.tgz#960919015bc31c46a8fc10df5c384add651df91e"
+ integrity sha512-EeW3jFlT3YNckJ6V/JnTfGcX7UHGyh6/AiCPopZ1HNaGiXVCKHPpVQZicmtyr/UpqxCXLrTgjHOvyMke7YN26A==
+
+"@swc/core-win32-ia32-msvc@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.14.0.tgz#826a76b2af0e4df4dee3674e91734cb85eb7b21f"
+ integrity sha512-dPai3KUIcihV5hfoO4QNQF5HAaw8+2bT7dvi8E5zLtecW2SfL3mUZipzampXq5FHll0RSCLzlrXnSx+dBRZIIQ==
+
+"@swc/core-win32-x64-msvc@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.14.0.tgz#75fe708a702f57f176fd640eb9af394cf767be91"
+ integrity sha512-nm+JajGrTqUA6sEHdghDlHMNfH1WKSiuvljhdmBACW4ta4LC3gKurX2qZuiBARvPkephW9V/i5S8QPY1PzFEqg==
+
+"@swc/core@^1.7.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core/-/core-1.14.0.tgz#ff7d287fbac6b6fd3adedf7b440cadfd0c389df6"
+ integrity sha512-oExhY90bes5pDTVrei0xlMVosTxwd/NMafIpqsC4dMbRYZ5KB981l/CX8tMnGsagTplj/RcG9BeRYmV6/J5m3w==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+ "@swc/types" "^0.1.25"
+ optionalDependencies:
+ "@swc/core-darwin-arm64" "1.14.0"
+ "@swc/core-darwin-x64" "1.14.0"
+ "@swc/core-linux-arm-gnueabihf" "1.14.0"
+ "@swc/core-linux-arm64-gnu" "1.14.0"
+ "@swc/core-linux-arm64-musl" "1.14.0"
+ "@swc/core-linux-x64-gnu" "1.14.0"
+ "@swc/core-linux-x64-musl" "1.14.0"
+ "@swc/core-win32-arm64-msvc" "1.14.0"
+ "@swc/core-win32-ia32-msvc" "1.14.0"
+ "@swc/core-win32-x64-msvc" "1.14.0"
+
+"@swc/counter@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
+ integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
+
+"@swc/types@^0.1.25":
+ version "0.1.25"
+ resolved "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz#b517b2a60feb37dd933e542d93093719e4cf1078"
+ integrity sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+
"@trysound/sax@0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
@@ -1387,7 +1468,12 @@ ansi-html@^0.0.9:
resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.9.tgz#6512d02342ae2cc68131952644a129cb734cd3f0"
integrity sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==
-ansi-styles@^4.1.0:
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
@@ -1615,6 +1701,15 @@ ci-info@^3.2.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4"
integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -1994,6 +2089,11 @@ electron-to-chromium@^1.5.73:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.134.tgz#d90008c4f8a506c1a6d1b329f922d83e18904101"
integrity sha512-zSwzrLg3jNP3bwsLqWHmS5z2nIOQ5ngMnfMZOWWtXnqqQkPVyOipxK98w+1beLw1TB+EImPNcG8wVP/cLVs2Og==
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
emojis-list@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
@@ -2058,7 +2158,7 @@ es-module-lexer@^1.2.1:
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78"
integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==
-escalade@^3.2.0:
+escalade@^3.1.1, escalade@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
@@ -2269,6 +2369,11 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
@@ -2521,6 +2626,11 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
@@ -3465,6 +3575,11 @@ regjsparser@^0.12.0:
dependencies:
jsesc "~3.0.2"
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
require-from-string@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
@@ -3657,13 +3772,15 @@ 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.3.0:
+ version "9.3.0"
+ resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-9.3.0.tgz#a73f1d17aebf85768da522ec2552d5f2867f8481"
+ integrity sha512-q3gug4dZhJRLe8LHQOwG5jx7Jik0T+ZcMxEhiTyEAuIN8cIt4eek6gCn4OQdIqhdZXAiUBCUpfIHdWt9yUO9/g==
dependencies:
js-yaml "^4.1.0"
path-complete-extname "^1.0.0"
+ webpack-merge "^5.8.0"
+ yargs "^17.7.2"
shallow-clone@^3.0.0:
version "3.0.1"
@@ -3774,6 +3891,15 @@ statuses@2.0.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
+string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
@@ -3788,6 +3914,13 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
strip-final-newline@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
@@ -3838,6 +3971,13 @@ svgo@^3.3.2:
csso "^5.0.5"
picocolors "^1.0.0"
+swc-loader@^0.2.6:
+ version "0.2.6"
+ resolved "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz#bf0cba8eeff34bb19620ead81d1277fefaec6bc8"
+ integrity sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+
tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
@@ -4050,9 +4190,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"
@@ -4119,6 +4259,15 @@ wildcard@^2.0.0:
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67"
integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@@ -4129,6 +4278,11 @@ ws@^8.13.0:
resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
yallist@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
@@ -4138,3 +4292,21 @@ yaml@^1.10.0:
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+
+yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs@^17.7.2:
+ version "17.7.2"
+ resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
diff --git a/script/convert b/script/convert
index b68d7c26fa..e580349b09 100755
--- a/script/convert
+++ b/script/convert
@@ -17,9 +17,9 @@ end
# Keep shakapacker.yml since we're using Shakapacker 8+
# move("../spec/dummy/config/shakapacker.yml", "../spec/dummy/config/webpacker.yml")
-# Shakapacker - use version with async script loading support (8.2.0+)
-gsub_file_content("../Gemfile.development_dependencies", /gem "shakapacker", "[^"]*"/, 'gem "shakapacker", "8.2.0"')
-gsub_file_content("../spec/dummy/package.json", /"shakapacker": "[^"]*",/, '"shakapacker": "8.2.0",')
+# Shakapacker - use version with async script loading support (9.3.0+)
+gsub_file_content("../Gemfile.development_dependencies", /gem "shakapacker", "[^"]*"/, 'gem "shakapacker", "9.3.0"')
+gsub_file_content("../spec/dummy/package.json", /"shakapacker": "[^"]*",/, '"shakapacker": "9.3.0",')
# The below packages don't work on the oldest supported Node version and aren't needed there anyway
# Note: All dev dependencies remain in root package.json even after workspace migration
diff --git a/spec/dummy/Gemfile.lock b/spec/dummy/Gemfile.lock
index 7641720904..15e401d182 100644
--- a/spec/dummy/Gemfile.lock
+++ b/spec/dummy/Gemfile.lock
@@ -100,11 +100,11 @@ GEM
msgpack (~> 1.2)
builder (3.3.0)
byebug (11.1.3)
- capybara (3.39.2)
+ capybara (3.40.0)
addressable
matrix
mini_mime (>= 0.1.3)
- nokogiri (~> 1.8)
+ nokogiri (~> 1.11)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
@@ -173,7 +173,7 @@ GEM
net-pop
net-smtp
marcel (1.1.0)
- matrix (0.4.2)
+ matrix (0.4.3)
method_source (1.0.0)
mini_mime (1.1.5)
mini_portile2 (2.8.9)
@@ -223,7 +223,7 @@ GEM
puma (6.4.0)
nio4r (~> 2.0)
racc (1.8.1)
- rack (3.2.1)
+ rack (3.2.4)
rack-proxy (0.7.7)
rack
rack-session (2.1.1)
@@ -270,7 +270,7 @@ GEM
rdoc (6.14.2)
erb
psych (>= 4.0.0)
- regexp_parser (2.8.1)
+ regexp_parser (2.11.3)
reline (0.6.2)
io-console (~> 0.5)
rexml (3.2.6)
@@ -346,7 +346,7 @@ GEM
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
semantic_range (3.1.0)
- shakapacker (8.2.0)
+ shakapacker (9.3.0)
activesupport (>= 5.2)
package_json
rack-proxy (>= 0.6.1)
@@ -409,7 +409,7 @@ DEPENDENCIES
amazing_print
benchmark
bootsnap
- capybara
+ capybara (>= 3.40)
capybara-screenshot
coveralls
debug
@@ -441,7 +441,7 @@ DEPENDENCIES
scss_lint
sdoc
selenium-webdriver (= 4.9.0)
- shakapacker (= 8.2.0)
+ shakapacker (= 9.3.0)
spring (~> 4.0)
sprockets (~> 4.0)
sqlite3 (~> 1.6)
diff --git a/spec/dummy/app/views/layouts/application.html.erb b/spec/dummy/app/views/layouts/application.html.erb
index ca89d84d47..54071c346e 100644
--- a/spec/dummy/app/views/layouts/application.html.erb
+++ b/spec/dummy/app/views/layouts/application.html.erb
@@ -10,7 +10,7 @@
<%= yield :head %>
- <%= javascript_pack_tag('client-bundle', 'data-turbolinks-track': true) %>
+ <%= javascript_pack_tag('client-bundle', 'data-turbo-track': 'reload', defer: true) %>
<%= csrf_meta_tags %>
diff --git a/spec/dummy/babel.config.js b/spec/dummy/babel.config.js
index 6aa1d24be2..b401544fa1 100644
--- a/spec/dummy/babel.config.js
+++ b/spec/dummy/babel.config.js
@@ -1,4 +1,5 @@
-const defaultConfigFunc = require('shakapacker/package/babel/preset');
+// eslint-disable-next-line import/extensions
+const defaultConfigFunc = require('shakapacker/package/babel/preset.js');
module.exports = function createBabelConfig(api) {
const resultConfig = defaultConfigFunc(api);
diff --git a/spec/dummy/bin/shakapacker-precompile-hook b/spec/dummy/bin/shakapacker-precompile-hook
new file mode 100755
index 0000000000..dc59fb5c9d
--- /dev/null
+++ b/spec/dummy/bin/shakapacker-precompile-hook
@@ -0,0 +1,100 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+# Shakapacker precompile hook
+# This script runs before Shakapacker compilation in both development and production.
+# See: https://github.com/shakacode/shakapacker/blob/main/docs/precompile_hook.md
+
+require "fileutils"
+
+# Find Rails root by walking upward looking for config/environment.rb
+def find_rails_root
+ dir = Dir.pwd
+ loop do
+ return dir if File.exist?(File.join(dir, "config", "environment.rb"))
+
+ parent = File.dirname(dir)
+ return nil if parent == dir # Reached filesystem root
+
+ dir = parent
+ end
+end
+
+# Build ReScript if needed
+def build_rescript_if_needed
+ # Check for both old (bsconfig.json) and new (rescript.json) config files
+ return unless File.exist?("bsconfig.json") || File.exist?("rescript.json")
+
+ puts "🔧 Building ReScript..."
+
+ # Cross-platform package manager detection
+ yarn_available = system("yarn", "--version", out: File::NULL, err: File::NULL)
+ npm_available = system("npm", "--version", out: File::NULL, err: File::NULL)
+
+ success = if yarn_available
+ system("yarn", "build:rescript")
+ elsif npm_available
+ system("npm", "run", "build:rescript")
+ else
+ warn "⚠️ Warning: Neither yarn nor npm found. Skipping ReScript build."
+ return
+ end
+
+ if success
+ puts "✅ ReScript build completed successfully"
+ else
+ warn "❌ ReScript build failed"
+ exit 1
+ end
+end
+
+# Generate React on Rails packs if needed
+# rubocop:disable Metrics/CyclomaticComplexity
+def generate_packs_if_needed
+ # Find Rails root directory
+ rails_root = find_rails_root
+ return unless rails_root
+
+ # Check if React on Rails initializer exists
+ initializer_path = File.join(rails_root, "config", "initializers", "react_on_rails.rb")
+ return unless File.exist?(initializer_path)
+
+ # Check if auto-pack generation is configured (match actual config assignments, not comments)
+ config_file = File.read(initializer_path)
+ has_auto_load = config_file =~ /^\s*config\.auto_load_bundle\s*=/
+ has_components_subdir = config_file =~ /^\s*config\.components_subdirectory\s*=/
+ return unless has_auto_load || has_components_subdir
+
+ puts "📦 Generating React on Rails packs..."
+
+ # Cross-platform bundle availability check
+ bundle_available = system("bundle", "--version", out: File::NULL, err: File::NULL)
+ return unless bundle_available
+
+ # Check if rake task exists (cross-platform)
+ task_list = `bundle exec rails -T 2>&1`
+ return unless task_list.include?("react_on_rails:generate_packs")
+
+ # Use array form for better cross-platform support
+ success = system("bundle", "exec", "rails", "react_on_rails:generate_packs")
+
+ if success
+ puts "✅ Pack generation completed successfully"
+ else
+ warn "❌ Pack generation failed"
+ exit 1
+ end
+end
+# rubocop:enable Metrics/CyclomaticComplexity
+
+# Main execution
+begin
+ build_rescript_if_needed
+ generate_packs_if_needed
+
+ exit 0
+rescue StandardError => e
+ warn "❌ Precompile hook failed: #{e.message}"
+ warn e.backtrace.join("\n")
+ exit 1
+end
diff --git a/spec/dummy/client/app/components/HelloWorld.module.scss b/spec/dummy/client/app/components/HelloWorld.module.scss
index 55339905f4..3b77eb394e 100644
--- a/spec/dummy/client/app/components/HelloWorld.module.scss
+++ b/spec/dummy/client/app/components/HelloWorld.module.scss
@@ -1,3 +1,5 @@
+@import "../assets/styles/app-variables.scss";
+
.brightColor {
color: $bright-color;
}
diff --git a/spec/dummy/config/shakapacker.yml b/spec/dummy/config/shakapacker.yml
index c58b284594..33c961b083 100644
--- a/spec/dummy/config/shakapacker.yml
+++ b/spec/dummy/config/shakapacker.yml
@@ -5,6 +5,10 @@ default: &default
source_entry_path: packs
public_root_path: public
+ # Hook to run before compilation (e.g., for ReScript builds, pack generation)
+ # See: https://github.com/shakacode/shakapacker/blob/main/docs/precompile_hook.md
+ precompile_hook: bin/shakapacker-precompile-hook
+
cache_path: tmp/cache/shakapacker
webpack_compile_output: false
ensure_consistent_versioning: true
@@ -17,6 +21,11 @@ default: &default
cache_manifest: false
nested_entries: true
+ # Hook to run before webpack compilation (e.g., for generating dynamic entry points)
+ # SECURITY: Only reference trusted scripts within your project. The hook command will be
+ # validated to ensure it points to a file within the project root.
+ precompile_hook: 'bin/shakapacker-precompile-hook'
+
development:
<<: *default
# Turn this to true if you want to use the rails/shakapacker check that the test
diff --git a/spec/dummy/config/webpack/commonWebpackConfig.js b/spec/dummy/config/webpack/commonWebpackConfig.js
index 66ed67094c..213d2d4fa9 100644
--- a/spec/dummy/config/webpack/commonWebpackConfig.js
+++ b/spec/dummy/config/webpack/commonWebpackConfig.js
@@ -24,7 +24,35 @@ const sassLoaderConfig = {
const scssConfigIndex = baseClientWebpackConfig.module.rules.findIndex((config) =>
'.scss'.match(config.test),
);
-baseClientWebpackConfig.module.rules[scssConfigIndex]?.use.push(sassLoaderConfig);
+if (scssConfigIndex !== -1 && baseClientWebpackConfig.module.rules[scssConfigIndex]?.use) {
+ baseClientWebpackConfig.module.rules[scssConfigIndex].use.push(sassLoaderConfig);
+}
+
+// Configure CSS Modules to use default exports (Shakapacker 9.0 compatibility)
+// Shakapacker 9.0 defaults to namedExport: true, but we use default imports
+// To restore backward compatibility with existing code using `import styles from`
+baseClientWebpackConfig.module.rules.forEach((rule) => {
+ if (Array.isArray(rule.use)) {
+ rule.use.forEach((loader) => {
+ if (
+ loader &&
+ typeof loader === 'object' &&
+ loader.loader &&
+ typeof loader.loader === 'string' &&
+ loader.loader.includes('css-loader') &&
+ loader.options &&
+ typeof loader.options === 'object' &&
+ loader.options.modules &&
+ typeof loader.options.modules === 'object'
+ ) {
+ // eslint-disable-next-line no-param-reassign
+ loader.options.modules.namedExport = false;
+ // eslint-disable-next-line no-param-reassign
+ loader.options.modules.exportLocalsConvention = 'camelCase';
+ }
+ });
+ }
+});
// add jquery
const exposeJQuery = {
diff --git a/spec/dummy/package.json b/spec/dummy/package.json
index 86550eade3..448093fd7a 100644
--- a/spec/dummy/package.json
+++ b/spec/dummy/package.json
@@ -29,6 +29,7 @@
"regenerator-runtime": "^0.13.4"
},
"devDependencies": {
+ "@swc/core": "^1.7.0",
"@babel/core": "7.17.9",
"@babel/plugin-transform-runtime": "7.17.0",
"@babel/preset-env": "7",
@@ -51,8 +52,9 @@
"sass": "^1.43.4",
"sass-loader": "^12.3.0",
"sass-resources-loader": "^2.1.0",
- "shakapacker": "8.2.0",
+ "shakapacker": "9.3.0",
"style-loader": "^3.3.1",
+ "swc-loader": "^0.2.6",
"terser-webpack-plugin": "5.3.1",
"url-loader": "^4.0.0",
"webpack": "5.72.0",
diff --git a/spec/dummy/yarn.lock b/spec/dummy/yarn.lock
index 7e26a59417..acda0b4689 100644
--- a/spec/dummy/yarn.lock
+++ b/spec/dummy/yarn.lock
@@ -1362,6 +1362,87 @@
dependencies:
"@sinonjs/commons" "^3.0.0"
+"@swc/core-darwin-arm64@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.14.0.tgz#1db614b52ed7369f47be2a1c6b5e80b6be923898"
+ integrity sha512-uHPC8rlCt04nvYNczWzKVdgnRhxCa3ndKTBBbBpResOZsRmiwRAvByIGh599j+Oo6Z5eyTPrgY+XfJzVmXnN7Q==
+
+"@swc/core-darwin-x64@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.14.0.tgz#900e56924994d0e723e6088e2a2e1a1c08c59a95"
+ integrity sha512-2SHrlpl68vtePRknv9shvM9YKKg7B9T13tcTg9aFCwR318QTYo+FzsKGmQSv9ox/Ua0Q2/5y2BNjieffJoo4nA==
+
+"@swc/core-linux-arm-gnueabihf@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.14.0.tgz#3c84966a8c6e308b0788d1c7875bce23c65134c6"
+ integrity sha512-SMH8zn01dxt809svetnxpeg/jWdpi6dqHKO3Eb11u4OzU2PK7I5uKS6gf2hx5LlTbcJMFKULZiVwjlQLe8eqtg==
+
+"@swc/core-linux-arm64-gnu@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.14.0.tgz#5190097d2ca4ea8b198f46a3abe2272331575b54"
+ integrity sha512-q2JRu2D8LVqGeHkmpVCljVNltG0tB4o4eYg+dElFwCS8l2Mnt9qurMCxIeo9mgoqz0ax+k7jWtIRHktnVCbjvQ==
+
+"@swc/core-linux-arm64-musl@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.14.0.tgz#420f510102a37feda0e3dfb8d21651515251476b"
+ integrity sha512-uofpVoPCEUjYIv454ZEZ3sLgMD17nIwlz2z7bsn7rl301Kt/01umFA7MscUovFfAK2IRGck6XB+uulMu6aFhKQ==
+
+"@swc/core-linux-x64-gnu@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.14.0.tgz#953f741d577a81f6e1e1b434856c48eb674cdeb7"
+ integrity sha512-quTTx1Olm05fBfv66DEBuOsOgqdypnZ/1Bh3yGXWY7ANLFeeRpCDZpljD9BSjdsNdPOlwJmEUZXMHtGm3v1TZQ==
+
+"@swc/core-linux-x64-musl@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.14.0.tgz#bdf241062d1433ba617ffe1451dccde8923a28a2"
+ integrity sha512-caaNAu+aIqT8seLtCf08i8C3/UC5ttQujUjejhMcuS1/LoCKtNiUs4VekJd2UGt+pyuuSrQ6dKl8CbCfWvWeXw==
+
+"@swc/core-win32-arm64-msvc@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.14.0.tgz#960919015bc31c46a8fc10df5c384add651df91e"
+ integrity sha512-EeW3jFlT3YNckJ6V/JnTfGcX7UHGyh6/AiCPopZ1HNaGiXVCKHPpVQZicmtyr/UpqxCXLrTgjHOvyMke7YN26A==
+
+"@swc/core-win32-ia32-msvc@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.14.0.tgz#826a76b2af0e4df4dee3674e91734cb85eb7b21f"
+ integrity sha512-dPai3KUIcihV5hfoO4QNQF5HAaw8+2bT7dvi8E5zLtecW2SfL3mUZipzampXq5FHll0RSCLzlrXnSx+dBRZIIQ==
+
+"@swc/core-win32-x64-msvc@1.14.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.14.0.tgz#75fe708a702f57f176fd640eb9af394cf767be91"
+ integrity sha512-nm+JajGrTqUA6sEHdghDlHMNfH1WKSiuvljhdmBACW4ta4LC3gKurX2qZuiBARvPkephW9V/i5S8QPY1PzFEqg==
+
+"@swc/core@^1.7.0":
+ version "1.14.0"
+ resolved "https://registry.npmjs.org/@swc/core/-/core-1.14.0.tgz#ff7d287fbac6b6fd3adedf7b440cadfd0c389df6"
+ integrity sha512-oExhY90bes5pDTVrei0xlMVosTxwd/NMafIpqsC4dMbRYZ5KB981l/CX8tMnGsagTplj/RcG9BeRYmV6/J5m3w==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+ "@swc/types" "^0.1.25"
+ optionalDependencies:
+ "@swc/core-darwin-arm64" "1.14.0"
+ "@swc/core-darwin-x64" "1.14.0"
+ "@swc/core-linux-arm-gnueabihf" "1.14.0"
+ "@swc/core-linux-arm64-gnu" "1.14.0"
+ "@swc/core-linux-arm64-musl" "1.14.0"
+ "@swc/core-linux-x64-gnu" "1.14.0"
+ "@swc/core-linux-x64-musl" "1.14.0"
+ "@swc/core-win32-arm64-msvc" "1.14.0"
+ "@swc/core-win32-ia32-msvc" "1.14.0"
+ "@swc/core-win32-x64-msvc" "1.14.0"
+
+"@swc/counter@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
+ integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
+
+"@swc/types@^0.1.25":
+ version "0.1.25"
+ resolved "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz#b517b2a60feb37dd933e542d93093719e4cf1078"
+ integrity sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+
"@types/babel__core@^7.1.14":
version "7.20.5"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
@@ -3236,6 +3317,11 @@ find-up@^5.0.0:
locate-path "^6.0.0"
path-exists "^4.0.0"
+flat@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
+ integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
+
follow-redirects@^1.0.0:
version "1.14.5"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381"
@@ -5648,13 +5734,15 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"
-shakapacker@8.2.0:
- version "8.2.0"
- resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-8.2.0.tgz#c7bed87b8be2ae565cfe616f68552be545c77e14"
- integrity sha512-Ct7BFqJVnKbxdqCzG+ja7Q6LPt/PlB7sSVBfG5jsAvmVCADM05cuoNwEgYNjFGKbDzHAxUqy5XgoI9Y030+JKQ==
+shakapacker@9.3.0:
+ version "9.3.0"
+ resolved "https://registry.npmjs.org/shakapacker/-/shakapacker-9.3.0.tgz#a73f1d17aebf85768da522ec2552d5f2867f8481"
+ integrity sha512-q3gug4dZhJRLe8LHQOwG5jx7Jik0T+ZcMxEhiTyEAuIN8cIt4eek6gCn4OQdIqhdZXAiUBCUpfIHdWt9yUO9/g==
dependencies:
js-yaml "^4.1.0"
path-complete-extname "^1.0.0"
+ webpack-merge "^5.8.0"
+ yargs "^17.7.2"
shallow-clone@^3.0.0:
version "3.0.1"
@@ -5961,6 +6049,13 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+swc-loader@^0.2.6:
+ version "0.2.6"
+ resolved "https://registry.npmjs.org/swc-loader/-/swc-loader-0.2.6.tgz#bf0cba8eeff34bb19620ead81d1277fefaec6bc8"
+ integrity sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+
symbol-observable@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
@@ -6340,6 +6435,15 @@ webpack-merge@5, webpack-merge@^5.7.3:
clone-deep "^4.0.1"
wildcard "^2.0.0"
+webpack-merge@^5.8.0:
+ version "5.10.0"
+ 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"
+ flat "^5.0.2"
+ wildcard "^2.0.0"
+
webpack-sources@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
@@ -6453,7 +6557,7 @@ yargs-parser@^21.1.1:
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
-yargs@^17.3.1:
+yargs@^17.3.1, yargs@^17.7.2:
version "17.7.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==