Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add support for RSC #1644

Open
wants to merge 54 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
0f49378
tmp
AbanoubGhadban Jul 22, 2024
c3f36cd
tmp
AbanoubGhadban Jul 29, 2024
8ef2cf1
make rsc get the right rsc bundle path
AbanoubGhadban Jul 30, 2024
08cd7c9
fix ts error after rebasing
AbanoubGhadban Nov 4, 2024
07a3073
tmp
AbanoubGhadban Nov 5, 2024
08794f6
DRY helper functions
AbanoubGhadban Dec 5, 2024
aed6bbe
remove duplicate function
AbanoubGhadban Dec 6, 2024
372984a
revert commiting some lines
AbanoubGhadban Dec 6, 2024
13888e5
refactor and add more tests for utils.rb
AbanoubGhadban Dec 18, 2024
9884405
add rsc_bundle_js_file config and update utils spec
AbanoubGhadban Dec 18, 2024
83c0d45
linting
AbanoubGhadban Dec 18, 2024
86dae94
linting
AbanoubGhadban Dec 18, 2024
9438640
don't set AsyncLocalStorage in global scope
AbanoubGhadban Dec 18, 2024
130254e
fix mock in webpack assets status checker test
AbanoubGhadban Dec 18, 2024
1338d32
mock that webpacker gem is not installed
AbanoubGhadban Dec 18, 2024
332e406
mock availablity of webpacker and shakapacker gems
AbanoubGhadban Dec 18, 2024
b3c39a2
ensure that webpacker is not used when shakapacker in use in tests
AbanoubGhadban Dec 18, 2024
1f8c5a1
remove instance variables of PackerUtils on utils tests
AbanoubGhadban Dec 18, 2024
66ea99b
make utils rspec test run using the packer installed on CI
AbanoubGhadban Dec 19, 2024
9a7c293
test bundle_js_file_path with webpacker and shakapacker
AbanoubGhadban Dec 19, 2024
47a22ce
linting
AbanoubGhadban Dec 19, 2024
530bbe1
remove webpacker test dependency
AbanoubGhadban Dec 19, 2024
a9999e4
don't mock gem availablity function
AbanoubGhadban Dec 19, 2024
53f1f7d
add rsc webpack loader
AbanoubGhadban Jan 16, 2025
a2467a7
ignore whitespace when comparing scripts
Judahmeek Jan 17, 2025
9ea28f4
linting
AbanoubGhadban Jan 25, 2025
d6c5a25
Update knip config to add rsc entry points
AbanoubGhadban Jan 25, 2025
cf90ba9
Update knip config to use .js extension for RSCWebpackLoader
AbanoubGhadban Jan 25, 2025
cf15b2a
linting
AbanoubGhadban Jan 25, 2025
edb68cc
[WIP] Hydrate components immediately after downloading chunks (#1656)
AbanoubGhadban Jan 31, 2025
a5f13fc
Fix client startup rendering when the script runs after the page loaded
AbanoubGhadban Feb 1, 2025
c02fe4c
Refactor client-side rendering and page lifecycle management
AbanoubGhadban Feb 1, 2025
6aa8e2c
Add component registry timeout configuration
AbanoubGhadban Feb 3, 2025
41ac87e
Refactor CallbackRegistry and clientStartup initialization
AbanoubGhadban Feb 3, 2025
44dee52
Update StoreRegistry error messages for clarity
AbanoubGhadban Feb 3, 2025
bdc72ed
Fix RSC stream parsing to handle incomplete chunks
AbanoubGhadban Feb 6, 2025
4bb6ce0
Refactor CallbackRegistry to improve item tracking and usage
AbanoubGhadban Feb 6, 2025
7937634
Refactor CallbackRegistry and ComponentRegistry to simplify item trac…
AbanoubGhadban Feb 7, 2025
19f4441
Update StoreRegistry test to use clearHydratedStores method
AbanoubGhadban Feb 7, 2025
e5f1b36
Update RSC test to append newline to stream chunks
AbanoubGhadban Feb 7, 2025
544a932
don't strip the html chunk
AbanoubGhadban Feb 9, 2025
a3ad230
Add "use client" directive to RSCClientRoot
AbanoubGhadban Feb 9, 2025
8f90edc
Convert RSCWebpackLoader to TypeScript
alexeyr Feb 10, 2025
d517143
Comment on the need for workaround
alexeyr Feb 10, 2025
6307be9
Fix Knip
alexeyr Feb 10, 2025
4ac1fe1
Simplify RSCWebpackLoader
alexeyr Feb 10, 2025
a9967e1
remove rsc? and stream? render options and add render_mode option
AbanoubGhadban Feb 13, 2025
434d173
Rename flight_payload_streaming to rsc_payload_streaming
AbanoubGhadban Feb 13, 2025
033ce1f
refactoring
AbanoubGhadban Feb 13, 2025
5fcbd85
Add async component retrieval and timeout handling to ComponentRegistry
AbanoubGhadban Feb 13, 2025
c1ef99f
add specs for packs generator
AbanoubGhadban Feb 14, 2025
f248e8f
Update react_on_rails_helper_spec with new props added to component d…
AbanoubGhadban Feb 14, 2025
1a7c76a
Remove webpacker dependency from Gemfile.lock
AbanoubGhadban Feb 14, 2025
f49aa8c
Remove unnecessary webpacker mocking in configuration spec
AbanoubGhadban Feb 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.versions == 'oldest' && '16' || '20' }}
node-version: ${{ matrix.versions == 'oldest' && '18' || '20' }}
Judahmeek marked this conversation as resolved.
Show resolved Hide resolved
- name: Print system information
run: |
echo "Linux release: "; cat /etc/issue
Expand Down Expand Up @@ -104,7 +104,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.versions == 'oldest' && '16' || '20' }}
node-version: ${{ matrix.versions == 'oldest' && '18' || '20' }}
- name: Print system information
run: |
echo "Linux release: "; cat /etc/issue
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/package-js-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.versions == 'oldest' && '16' || '20' }}
node-version: ${{ matrix.versions == 'oldest' && '18' || '20' }}
- name: Print system information
run: |
echo "Linux release: "; cat /etc/issue
Expand All @@ -43,3 +43,6 @@ jobs:
sudo yarn global add yalc
- name: Run JS unit tests for Renderer package
run: yarn test
# TODO: Remove this once we made these tests compatible with React 19
- name: Run JS unit tests for Renderer package with React 18 (for tests not compatible with React 19)
run: yarn test:react-18
3 changes: 3 additions & 0 deletions .github/workflows/rspec-package-specs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ jobs:
git config user.email "[email protected]"
git config user.name "Your Name"
git commit -am "stop generators from complaining about uncommitted code"
- name: Set packer version environment variable
run: |
echo "CI_PACKER_VERSION=${{ matrix.versions == 'oldest' && 'old' || 'new' }}" >> $GITHUB_ENV
AbanoubGhadban marked this conversation as resolved.
Show resolved Hide resolved
- name: Run rspec tests
run: bundle exec rspec spec/react_on_rails
- name: Store test results
Expand Down
11 changes: 11 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,15 @@ module.exports = {
preset: 'ts-jest/presets/js-with-ts',
testEnvironment: 'jsdom',
setupFiles: ['<rootDir>/node_package/tests/jest.setup.js'],
// TODO: Remove this once we made RSCClientRoot compatible with React 19
moduleNameMapper: process.env.USE_REACT_18
? {
'^react$': '<rootDir>/node_modules/react-18',
'^react/(.*)$': '<rootDir>/node_modules/react-18/$1',
'^react-dom$': '<rootDir>/node_modules/react-dom-18',
'^react-dom/(.*)$': '<rootDir>/node_modules/react-dom-18/$1',
}
: {
'react-server-dom-webpack/client': '<rootDir>/node_package/tests/emptyForTesting.js',
},
AbanoubGhadban marked this conversation as resolved.
Show resolved Hide resolved
};
14 changes: 13 additions & 1 deletion knip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ const config: KnipConfig = {
// ! at the end means files are used in production
workspaces: {
'.': {
entry: ['node_package/src/ReactOnRails.ts!', 'node_package/src/ReactOnRails.node.ts!'],
entry: [
'node_package/src/ReactOnRails.ts!',
'node_package/src/ReactOnRails.node.ts!',
'node_package/src/ReactOnRailsRSC.ts!',
'node_package/src/RSCWebpackLoader.ts!',
'node_package/src/registerServerComponent.ts!',
'node_package/src/RSCClientRoot.ts!',
],
project: ['node_package/src/**/*.[jt]s!', 'node_package/tests/**/*.[jt]s'],
babel: {
config: ['node_package/babel.config.js'],
Expand All @@ -24,6 +31,11 @@ const config: KnipConfig = {
// though we don't actually use its rules anywhere.
'eslint-plugin-jsx-a11y',
'eslint-plugin-react',
'react-server-dom-webpack',
'cross-fetch',
'jsdom',
'react-18',
'react-dom-18',
],
},
'spec/dummy': {
Expand Down
31 changes: 27 additions & 4 deletions lib/react_on_rails/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ def self.configure
end

DEFAULT_GENERATED_ASSETS_DIR = File.join(%w[public webpack], Rails.env).freeze
DEFAULT_REACT_CLIENT_MANIFEST_FILE = "react-client-manifest.json"
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of adding an additional configuration here & dedicated RORP logic, we should just have users add the manifest file to their assets-to-copy in their RORP configuration.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See the answer here

DEFAULT_COMPONENT_REGISTRY_TIMEOUT = 5000

def self.configuration
@configuration ||= Configuration.new(
Expand All @@ -17,6 +19,8 @@ def self.configuration
# generated_assets_dirs is deprecated
generated_assets_dir: "",
server_bundle_js_file: "",
rsc_bundle_js_file: "",
react_client_manifest_file: DEFAULT_REACT_CLIENT_MANIFEST_FILE,
prerender: false,
auto_load_bundle: false,
replay_console: true,
Expand All @@ -41,7 +45,11 @@ def self.configuration
make_generated_server_bundle_the_entrypoint: false,
defer_generated_component_packs: true,
# forces the loading of React components
force_load: false
force_load: false,
# Maximum time in milliseconds to wait for client-side component registration after page load.
# If exceeded, an error will be thrown for server-side rendered components not registered on the client.
# Set to 0 to disable the timeout and wait indefinitely for component registration.
component_registry_timeout: DEFAULT_COMPONENT_REGISTRY_TIMEOUT
)
end

Expand All @@ -56,8 +64,8 @@ class Configuration
:server_render_method, :random_dom_id, :auto_load_bundle,
:same_bundle_for_client_and_server, :rendering_props_extension,
:make_generated_server_bundle_the_entrypoint,
:defer_generated_component_packs,
:force_load
:defer_generated_component_packs, :force_load, :rsc_bundle_js_file,
:react_client_manifest_file, :component_registry_timeout

# rubocop:disable Metrics/AbcSize
def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
Expand All @@ -72,7 +80,8 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
same_bundle_for_client_and_server: nil,
i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil, i18n_yml_safe_load_options: nil,
random_dom_id: nil, server_render_method: nil, rendering_props_extension: nil,
components_subdirectory: nil, auto_load_bundle: nil, force_load: nil)
components_subdirectory: nil, auto_load_bundle: nil, force_load: nil,
rsc_bundle_js_file: nil, react_client_manifest_file: nil, component_registry_timeout: nil)
self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
self.generated_assets_dirs = generated_assets_dirs
self.generated_assets_dir = generated_assets_dir
Expand All @@ -96,9 +105,12 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
self.raise_on_prerender_error = raise_on_prerender_error
self.skip_display_none = skip_display_none
self.rendering_props_extension = rendering_props_extension
self.component_registry_timeout = component_registry_timeout

# Server rendering:
self.server_bundle_js_file = server_bundle_js_file
self.rsc_bundle_js_file = rsc_bundle_js_file
self.react_client_manifest_file = react_client_manifest_file
self.same_bundle_for_client_and_server = same_bundle_for_client_and_server
self.server_renderer_pool_size = self.development_mode ? 1 : server_renderer_pool_size
self.server_renderer_timeout = server_renderer_timeout # seconds
Expand Down Expand Up @@ -126,10 +138,19 @@ def setup_config_values
error_if_using_packer_and_generated_assets_dir_not_match_public_output_path
# check_deprecated_settings
adjust_precompile_task
check_component_registry_timeout
end

private

def check_component_registry_timeout
self.component_registry_timeout = DEFAULT_COMPONENT_REGISTRY_TIMEOUT if component_registry_timeout.nil?

return if component_registry_timeout.is_a?(Integer) && component_registry_timeout >= 0

raise ReactOnRails::Error, "component_registry_timeout must be a positive integer"
end

def check_autobundling_requirements
raise_missing_components_subdirectory if auto_load_bundle && !components_subdirectory.present?
return unless components_subdirectory.present?
Expand Down Expand Up @@ -243,6 +264,8 @@ def ensure_webpack_generated_files_exists

files = ["manifest.json"]
files << server_bundle_js_file if server_bundle_js_file.present?
files << rsc_bundle_js_file if rsc_bundle_js_file.present?
files << react_client_manifest_file if react_client_manifest_file.present?
Judahmeek marked this conversation as resolved.
Show resolved Hide resolved

self.webpack_generated_files = files
end
Expand Down
Loading
Loading