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==