-
-
Notifications
You must be signed in to change notification settings - Fork 629
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
Add support for replaying logs happen on async server operations #1649
Add support for replaying logs happen on async server operations #1649
Conversation
WalkthroughThe changes introduce enhancements to the Changes
Possibly related PRs
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Outside diff range and nitpick comments (3)
node_package/src/buildConsoleReplay.ts (3)
16-19
: Excellent change to improve robustness across different execution contexts.The replacement of
instanceof Array
withArray.isArray
is a great improvement. It addresses potential issues with prototype mismatches when the code runs in different execution contexts, such as within a VM for node rendering.The updated comments provide valuable context for this change, which enhances code maintainability.
Consider adding a brief mention of why
Array.isArray
is preferred overinstanceof Array
in the comments. This could help developers who might not be familiar with the nuances of these checks. For example:// Must use Array.isArray instead of instanceof Array the history array is defined outside the vm if node renderer is used. // In this case, the Array prototype used to define the array is not the same as the one in the global scope inside the vm. +// Array.isArray is more reliable as it works correctly even when the array is created in a different realm or execution context.
18-18
: Consider removing or replacing the Flow commentThe
// $FlowFixMe
comment is typically used for Flow type checking, but this file appears to be using TypeScript. Consider removing this comment or replacing it with a TypeScript-specific comment if type assertion is needed.If type assertion is needed, you could use a TypeScript assertion comment instead:
// @ts-ignore
Or, preferably, use a type assertion:
if (!Array.isArray(console.history as any[])) {
Line range hint
29-29
: Consider using a more specific type for the caught errorInstead of using
any
for the caught error, consider using a more specific type. This will improve type safety and make the error handling more robust.You could use the
unknown
type and then narrow it down:} catch (e: unknown) { let errorMessage = 'An error occurred'; if (e instanceof Error) { errorMessage = e.message; } val = `${errorMessage}: ${arg}`; }This approach provides better type safety and more informative error messages.
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (2)
- node_package/src/buildConsoleReplay.ts (1 hunks)
- node_package/src/serverRenderReactComponent.ts (4 hunks)
Additional comments not posted (1)
node_package/src/buildConsoleReplay.ts (1)
Line range hint
1-46
: Summary of reviewThe changes made to this file improve its robustness when dealing with arrays from different execution contexts. The main functionality remains intact while addressing potential edge cases.
Key points:
- The switch to
Array.isArray
is a good improvement.- The updated comments provide valuable context for the change.
- There are opportunities for further improvements in type safety and error handling.
Overall, this change is a step in the right direction for making the code more reliable across different environments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (2)
node_package/src/buildConsoleReplay.ts (2)
14-19
: Approve changes with a minor suggestion for comment improvement.The updated function signature and comment changes look good. Accepting
consoleHistory
as a parameter improves flexibility and testability. The explanation for usingArray.isArray
is valuable.Consider adding a brief explanation of why
consoleHistory
is now a parameter. For example:export function consoleReplay(consoleHistory: typeof console['history']): string { - // console.history is a global polyfill used in server rendering. + // consoleHistory is passed as a parameter to improve flexibility and testability. + // It replaces the global console.history polyfill previously used in server rendering. // Must use Array.isArray instead of instanceof Array the history array is defined outside the vm if node renderer is used. // In this case, the Array prototype used to define the array is not the same as the one in the global scope inside the vm.
44-45
: Approve changes with a suggestion for JSDoc improvement.The updates to the
buildConsoleReplay
function are consistent with the changes made toconsoleReplay
. The modification improves the flexibility of the function.Consider adding a JSDoc comment to explain the purpose of the function and its parameter. For example:
/** * Builds a console replay script wrapped in script tags. * @param consoleHistory - The console history to be replayed. * @returns A string containing the console replay script wrapped in script tags. */ export default function buildConsoleReplay(consoleHistory: typeof console['history']): string { return RenderUtils.wrapInScriptTags('consoleReplayLog', consoleReplay(consoleHistory)); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
- node_package/src/ReactOnRails.ts (1 hunks)
- node_package/src/buildConsoleReplay.ts (2 hunks)
- node_package/src/serverRenderReactComponent.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- node_package/src/serverRenderReactComponent.ts
🔇 Additional comments (3)
node_package/src/buildConsoleReplay.ts (2)
19-19
: Approve the updated condition.The change from
instanceof Array
toArray.isArray
is correct and consistent with the updated comment. Using theconsoleHistory
parameter instead ofconsole.history
aligns with the function signature change.
Line range hint
1-46
: Summary of changes and alignment with PR objectives.The changes made to this file successfully contribute to the PR objective of adding support for replaying logs from async server operations. The modifications to
consoleReplay
andbuildConsoleReplay
functions improve flexibility and testability by accepting aconsoleHistory
parameter instead of relying on a global variable.Key improvements:
- Enhanced flexibility by parameterizing
consoleHistory
.- Improved reliability by using
Array.isArray
instead ofinstanceof Array
.- Updated comments explaining the rationale behind the changes.
These changes will facilitate better debugging and monitoring of async server operations by allowing more controlled log replay.
To fully complete the PR objectives, please ensure that:
- Tests are added or updated to cover these changes.
- Documentation is updated to reflect the new function signatures and usage.
- The CHANGELOG is updated with an entry for this feature.
node_package/src/ReactOnRails.ts (1)
260-260
: LGTM! Verify related changes and update tests/docs.The change to pass
console.history
tobuildConsoleReplay
aligns with the PR objective of supporting log replay for async server operations. This should improve debugging capabilities.Please ensure the following:
- The
buildConsoleReplay
function (likely in another file) has been updated to accept and use thisconsole.history
parameter.- Unit tests have been updated or added to cover this change.
- Documentation has been updated to reflect this new functionality.
To verify the
buildConsoleReplay
function update, you can run:Would you like assistance in updating the tests or documentation for this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM. Just questions abuot minor details.
Actually, one additional question: Can we easily test these changes? |
e42d736
to
1c93b76
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Inline review comments failed to post
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (6)
node_package/src/buildConsoleReplay.ts (4)
12-12
: LGTM! Consider adding JSDoc for the new parameter.The updated function signature improves flexibility by allowing a custom console history. The type and default value are appropriate.
Consider adding a JSDoc comment to describe the new
customConsoleHistory
parameter:/** * Generates a console replay script. * @param customConsoleHistory Optional custom console history to use instead of the global one. * @returns A string containing the console replay script. */ export function consoleReplay(customConsoleHistory: typeof console['history'] | undefined = undefined): string {
14-16
: LGTM! Consider adding a comment for clarity.The implementation correctly uses the custom console history when provided and falls back to the global
console.history
otherwise. The use of the nullish coalescing operator is appropriate.Consider adding a brief comment to explain the fallback behavior:
// Use custom history if provided, otherwise fall back to global console.history const consoleHistory = customConsoleHistory ?? console.history; // Ensure consoleHistory is an array before processing if (!(Array.isArray(consoleHistory))) { return ''; }
47-48
: LGTM! Consider adding JSDoc for consistency.The
buildConsoleReplay
function has been correctly updated to accept and pass thecustomConsoleHistory
parameter toconsoleReplay
. This change maintains consistency with theconsoleReplay
function updates.For consistency with the
consoleReplay
function, consider adding a JSDoc comment:/** * Builds a console replay script wrapped in script tags. * @param customConsoleHistory Optional custom console history to use instead of the global one. * @returns A string containing the wrapped console replay script. */ export default function buildConsoleReplay(customConsoleHistory: typeof console['history'] | undefined = undefined): string { return RenderUtils.wrapInScriptTags('consoleReplayLog', consoleReplay(customConsoleHistory)); }
Action Required: Update
buildConsoleReplay
Function CallsThe following instances of
buildConsoleReplay
are called without thecustomConsoleHistory
parameter:
node_package/src/serverRenderReactComponent.ts
node_package/src/types/index.ts
node_package/src/ReactOnRails.ts
(2 occurrences)Please update these calls to include the necessary
customConsoleHistory
parameter to ensure consistency with the new implementation.🔗 Analysis chain
Line range hint
1-48
: Overall implementation looks good and aligns with PR objectives.The changes in this file successfully implement support for custom console history in both
consoleReplay
andbuildConsoleReplay
functions. This enhancement aligns well with the PR objective of adding support for replaying logs from async server operations.A few minor suggestions for improving documentation have been made, but the core functionality appears correct and consistent. The changes maintain backward compatibility while providing the flexibility to use custom console history when needed.
To fully meet the PR objectives:
- Ensure that the async server operations are correctly capturing their console output in a way that can be passed to these functions.
- Update any calling code to utilize the new
customConsoleHistory
parameter when replaying logs from async operations.- Add or update tests to cover these changes, as mentioned in the PR checklist.
- Update the documentation to reflect this new functionality.
- Add an entry to the CHANGELOG file describing this enhancement.
To verify the usage of these updated functions, please run the following script:
This will help ensure that any existing usage of these functions is updated to take advantage of the new
customConsoleHistory
parameter where appropriate.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for usage of consoleReplay and buildConsoleReplay functions echo "Searching for consoleReplay usage:" rg --type typescript "consoleReplay\(" -C 3 echo "\nSearching for buildConsoleReplay usage:" rg --type typescript "buildConsoleReplay\(" -C 3Length of output: 338
Script:
#!/bin/bash # Description: Check for usage of consoleReplay and buildConsoleReplay functions in TypeScript files echo "Searching for consoleReplay usage in TypeScript files:" rg -g '*.ts' "consoleReplay\(" -C 3 echo -e "\nSearching for buildConsoleReplay usage in TypeScript files:" rg -g '*.ts' "buildConsoleReplay\(" -C 3Length of output: 4493
Script:
#!/bin/bash # Description: Check for buildConsoleReplay calls without customConsoleHistory parameter echo "Searching for buildConsoleReplay calls without parameters:" rg -g '*.ts' "buildConsoleReplay\s*\(" | grep -E "buildConsoleReplay\(\s*\)" echo -e "\nSearching for buildConsoleReplay calls with undefined parameter:" rg -g '*.ts' "buildConsoleReplay\(undefined\)"Length of output: 694
node_package/src/types/index.ts (1)
70-79
: LGTM! Consider clarifying the relationship betweenrenderFunction
andisRenderer
.The addition of
renderFunction
andisRenderer
properties to theRegisteredComponent
interface is well-implemented and aligns with the PR objective of supporting async server operations. The detailed comments provide clear explanations of their purposes.To further improve clarity, consider adding a note about the relationship between these two properties. For example:
// Note: All renderer functions are render functions, but not all render functions are renderer functions. // A component can have renderFunction: true and isRenderer: false, but not vice versa.This addition would help developers understand the hierarchy and constraints between these two properties.
node_package/src/serverRenderReactComponent.ts (1)
191-191
: Fix typo and improve comment clarityThere's a typo in the comment: "cleanining" should be "cleaning". Also, consider rephrasing the comment for better readability.
Apply this diff to correct the typo and enhance the comment:
-// Promises only supported in node renderer and node renderer takes care of cleanining console history +// Promises are only supported in the Node renderer, which takes care of cleaning console history
🛑 Comments failed to post (1)
node_package/src/serverRenderReactComponent.ts (1)
79-81:
⚠️ Potential issueSet
hasErrors
totrue
when promises are not supportedIn the
processRenderingResult
function, when the result is a promise andrenderingReturnsPromises
isfalse
, an error is logged inprocessPromise
, buthasErrors
remainsfalse
. To accurately reflect that an error occurred during rendering, consider settinghasErrors
totrue
in this case.Apply this diff to set
hasErrors
appropriately:if (isPromise(result)) { - return { result: processPromise(result, options.renderingReturnsPromises), hasErrors: false }; + const hasErrors = !options.renderingReturnsPromises; + return { result: processPromise(result, options.renderingReturnsPromises), hasErrors }; }This will ensure that the
hasErrors
flag correctly indicates an issue when promises are not supported.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.if (isPromise(result)) { const hasErrors = !options.renderingReturnsPromises; return { result: processPromise(result, options.renderingReturnsPromises), hasErrors }; }
1c93b76
to
9ec2c20
Compare
…ions get console replay messages after promise resolves or rejects use isPromise to check if the result is a promise make consoleReplay function accept the list of logs to be added to the script make consoleHistory argument of consoleReplay optional add comments add comments update comment remove FlowFixMe comment
4c57f78
to
2697ef7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
- lib/react_on_rails/server_rendering_js_code.rb (1 hunks)
- node_package/src/buildConsoleReplay.ts (2 hunks)
- node_package/src/serverRenderReactComponent.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- node_package/src/buildConsoleReplay.ts
🧰 Additional context used
🔇 Additional comments (6)
lib/react_on_rails/server_rendering_js_code.rb (1)
43-43
: 🛠️ Refactor suggestionConsider enhancing the console history initialization
The addition of
console.history = [];
is a good step towards capturing console output during server-side rendering, which can be valuable for debugging async operations. However, there are a few points to consider:
This initialization occurs on every render, potentially overwriting previous logs. Consider if this is the intended behavior or if accumulating logs across renders would be more beneficial.
There's no clear mechanism in the provided code to retrieve or use this history after rendering. Ensure that there's a corresponding feature to access and utilize these logs.
To improve code clarity, consider adding a comment explaining the purpose of this initialization, e.g.:
// Initialize console history for capturing logs during server-side rendering console.history = [];To ensure this change is properly utilized, let's verify its usage:
node_package/src/serverRenderReactComponent.ts (5)
111-115
: Excellent addition to preserve console logs during async operations.This proactive approach ensures that console logs are not lost, regardless of the Node renderer's configuration. The detailed comment provides clear context, which is crucial for maintaining this code in the future.
118-118
: Consistent use of captured console history.This change ensures that all console logs, including those from async operations, are included in the replay script. It's a logical follow-up to the console history capture introduced earlier.
122-123
: Consistent error handling with preserved console logs.This change ensures that console logs are included in the replay script even when an error occurs during async operations. It maintains consistency with the success case and improves debugging capabilities in error scenarios.
134-134
: Consistent update to createPromiseResult call.This change ensures that the entire renderState is passed to
createPromiseResult
, maintaining consistency with the updates made to that function. It's a necessary adjustment to support the new error handling and console log preservation features.
141-141
: Improved type safety with updated function signature.The new return type
null | string | Promise<RenderResult>
accurately reflects the possible outcomes of theserverRenderReactComponent
function. This change enhances type safety and makes the function's behavior more explicit, which will help prevent type-related errors and improve code maintainability.
} | ||
|
||
const consoleReplayScript = buildConsoleReplay(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent console log handling in non-promise scenarios.
The buildConsoleReplay
call here doesn't use the captured console history, unlike in the createPromiseResult
function. This inconsistency may lead to loss of console logs in non-promise scenarios.
Consider updating this line to use the captured console history:
- const consoleReplayScript = buildConsoleReplay();
+ const consoleReplayScript = buildConsoleReplay(console.history);
This change would ensure consistent handling of console logs across all scenarios.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const consoleReplayScript = buildConsoleReplay(); | |
const consoleReplayScript = buildConsoleReplay(console.history); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (3)
node_package/src/serverRenderReactComponent.ts (3)
111-124
: Improved handling of console logs in async operationsThe changes to the
createPromiseResult
function effectively address the issue of potentially losing console logs during async operations. By capturing the console history before awaiting the promise, you ensure that all logs, including those from async operations, are included in the replay script.The added comment provides clear context for why this change was necessary, which is helpful for future maintenance.
Consider renaming
consoleHistory
tocapturedConsoleHistory
to make it even more explicit that this is a snapshot of the console history at a specific point in time:- const consoleHistory = console.history; + const capturedConsoleHistory = console.history; try { const html = await renderState.result; - const consoleReplayScript = buildConsoleReplay(consoleHistory); + const consoleReplayScript = buildConsoleReplay(capturedConsoleHistory); return createResultObject(html, consoleReplayScript, renderState); } catch (e: unknown) { const errorRenderState = handleRenderingError(e, { componentName, throwJsErrors }); - const consoleReplayScript = buildConsoleReplay(consoleHistory); + const consoleReplayScript = buildConsoleReplay(capturedConsoleHistory); return createResultObject(errorRenderState.result, consoleReplayScript, renderState); }
Line range hint
141-187
: Improved structure and clarity inserverRenderReactComponentInternal
The restructuring of the
serverRenderReactComponentInternal
function significantly improves its readability and clarity. The added comments provide valuable context for each step of the rendering process, which will be helpful for future maintenance and understanding of the code.The use of newly added helper functions (
validateComponent
,processRenderingResult
,handleRenderingError
,createFinalResult
) improves modularity and makes the main function more concise and focused on its primary responsibilities.Consider adding a try-catch block around the
createFinalResult
call to ensure that any unexpected errors during this step are also properly handled:// 3. Constructs a JSON object with the following properties: // - html: string | null (The rendered component HTML) // - consoleReplayScript: string (Script to replay console outputs on the client) // - hasErrors: boolean (Indicates if any errors occurred during rendering) // - renderingError: Error | null (The error object if an error occurred, null otherwise) // 4. For Promise results, it awaits resolution before creating the final JSON - return createFinalResult(renderState, componentName, throwJsErrors); + try { + return createFinalResult(renderState, componentName, throwJsErrors); + } catch (e: unknown) { + console.error('Unexpected error during final result creation:', e); + return JSON.stringify(createResultObject(null, '', { hasErrors: true, error: e as Error })); + }This addition ensures that any unexpected errors during the final result creation are caught and returned as a proper error response, maintaining consistency with the error handling approach used elsewhere in the function.
189-193
: Improved compatibility and documentation for console history resetThe addition of comments explaining the console history reset and the conditional reset based on the rendering environment improves both the code's compatibility and its documentation. This change ensures that the console history is properly managed across different rendering scenarios.
To further improve clarity, consider slightly modifying the comments to explicitly state when the reset is necessary:
- // This is necessary when ExecJS and old versions of node renderer are used. - // New versions of node renderer reset the console history automatically. + // This reset is necessary when using ExecJS or old versions of the node renderer. + // New versions of the node renderer reset the console history automatically, so this is a fallback. console.history = [];This minor change makes it clearer that the reset is a fallback mechanism for specific scenarios, which could help prevent confusion for developers working with newer versions of the node renderer.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- node_package/src/serverRenderReactComponent.ts (3 hunks)
🧰 Additional context used
🔇 Additional comments (1)
node_package/src/serverRenderReactComponent.ts (1)
Line range hint
1-110
: Improved code structure and error handlingThe addition of new types (
RenderState
andRenderOptions
) and the introduction of several helper functions (validateComponent
,processServerRenderHash
,processPromise
,processReactElement
,handleRenderingError
) significantly improve the code organization and readability. These changes provide better separation of concerns and standardize error handling across the module.The
validateComponent
function adds a crucial safety check against using renderers directly, which could prevent potential misuse of the API.
return createPromiseResult({ ...renderState, result }, componentName, throwJsErrors); | ||
} | ||
|
||
const consoleReplayScript = buildConsoleReplay(); | ||
return JSON.stringify(createResultObject(result, consoleReplayScript, renderState)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent console history handling in createFinalResult
The use of the spread operator in the createPromiseResult
call is a good practice for maintaining immutability. However, there's an inconsistency in how the console history is handled for non-promise results.
For consistency with the promise case and to ensure all console logs are captured, consider modifying the buildConsoleReplay
call for non-promise results:
- const consoleReplayScript = buildConsoleReplay();
+ const consoleReplayScript = buildConsoleReplay(console.history);
This change ensures that all console logs are included in the replay script, regardless of whether the result is a promise or not.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
return createPromiseResult({ ...renderState, result }, componentName, throwJsErrors); | |
} | |
const consoleReplayScript = buildConsoleReplay(); | |
return JSON.stringify(createResultObject(result, consoleReplayScript, renderState)); | |
} | |
return createPromiseResult({ ...renderState, result }, componentName, throwJsErrors); | |
} | |
const consoleReplayScript = buildConsoleReplay(console.history); | |
return JSON.stringify(createResultObject(result, consoleReplayScript, renderState)); | |
} |
Summary
Remove this paragraph and provide a general description of the code changes in your pull
request... were there any bugs you had fixed? If so, mention them. If
these bugs have open GitHub issues, be sure to tag them here as well,
to keep the conversation linked together.
Pull Request checklist
Remove this line after checking all the items here. If the item is not applicable to the PR, both check it out and wrap it by
~
.Add the CHANGELOG entry at the top of the file.
Other Information
Remove this paragraph and mention any other important and relevant information such as benchmarks.
This change is
Summary by CodeRabbit
Bug Fixes
console.history
to ensure accurate console replay functionality across different execution contexts.console.history
based on the rendering outcome, ensuring it resets appropriately.New Features
isPromise
function to handle a broader range of input types for improved flexibility.RegisteredComponent
interface to improve component registration and rendering capabilities.console.history
as an empty array during server rendering for better console log management.