Skip to content

fix: enhance performance for codeblock #347

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

Merged
merged 7 commits into from
Oct 15, 2024

Conversation

thucpn
Copy link
Collaborator

@thucpn thucpn commented Oct 8, 2024

Currently, asking AI for generating inline code will make browser tag so lag.
The root cause is may because react-syntax-highlight re-render too many times.

image

Summary by CodeRabbit

  • New Features

    • Enhanced code block rendering with improved syntax highlighting using highlight.js.
    • Improved styling for code blocks and citation links in the Markdown component.
    • Expanded configurability for template installation, allowing for better handling of different frameworks and options.
  • Bug Fixes

    • Removed outdated dependencies related to the previous syntax highlighting library, ensuring smoother performance.

@thucpn thucpn requested a review from marcusschiesser October 8, 2024 00:29
Copy link

changeset-bot bot commented Oct 8, 2024

⚠️ No Changeset found

Latest commit: 991a613

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

coderabbitai bot commented Oct 8, 2024

Walkthrough

The pull request introduces modifications to the CodeBlock component by replacing the react-syntax-highlighter library with highlight.js for syntax highlighting. The component's structure is simplified, utilizing a <pre> and <code> tag instead of the previous SyntaxHighlighter component. Additionally, the package.json file reflects these changes by removing the old dependency and adding highlight.js, streamlining the project's syntax highlighting approach. The installTSTemplate function in helpers/typescript.ts is also updated to enhance template installation for different frameworks.

Changes

File Path Change Summary
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx Replaced react-syntax-highlighter with highlight.js, updated component structure for highlighting, and added className prop.
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/markdown.tsx Enhanced code block rendering and citation link handling in the Markdown component.
templates/types/streaming/nextjs/package.json Removed react-syntax-highlighter and its type definitions; added highlight.js as a dependency.
helpers/typescript.ts Updated installTSTemplate function to include new parameters and enhance framework handling.

Possibly related PRs

  • feat: use llamacloud for chat #149: The changes in this PR involve using llamacloud for chat functionality, which may relate to the updates in the CodeBlock component that also involve handling code and potentially integrating with cloud services.
  • feat: support using azure code interpreter in create-llama #158: This PR introduces support for using Azure Code Interpreter, which may connect to the changes in the CodeBlock component that involve syntax highlighting and rendering code.
  • feat: add filter for query in ts templates #172: This PR adds a filter for queries in TypeScript templates, which could relate to the changes in the CodeBlock component that affect how code is displayed and interacted with.
  • feat: In-text citing #175: The in-text citing feature may relate to the changes in the Markdown component, which also deals with rendering text and could involve citation handling.
  • feat: implement citation for TS #257: The implementation of citation management in TypeScript could connect with the Markdown component changes, which also involve handling citations.

Poem

In the code where colors play,
A new highlight shines today.
With highlight.js, we leap and bound,
Simplifying the code we found.
Goodbye to old, hello to new,
A brighter path for all to view! 🐇✨


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 3fd0aa5 and 991a613.

📒 Files selected for processing (1)
  • templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx

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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@marcusschiesser
Copy link
Collaborator

@thucpn this looks good to merge. Why it's a draft?

@thucpn
Copy link
Collaborator Author

thucpn commented Oct 8, 2024

It should fix the performance issue from react syntax highlight. But I still get a bit lagging when rendering long code. So I put it in draft for investigate more.
Having an idea about extend current SyntaxHighlight component to fix forceUpdate issue. I will try it.

@thucpn thucpn marked this pull request as ready for review October 14, 2024 09:47
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between dfd4fd5 and bdc59ef.

📒 Files selected for processing (2)
  • templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (3 hunks)
  • templates/types/streaming/nextjs/package.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (1)

Pattern templates/**: For files under the templates folder, do not report 'Missing Dependencies Detected' errors.

templates/types/streaming/nextjs/package.json (1)

Pattern templates/**: For files under the templates folder, do not report 'Missing Dependencies Detected' errors.

🔇 Additional comments (1)
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (1)

57-63: Use of useRef and useEffect for syntax highlighting is appropriate

The implementation correctly uses useRef and useEffect to apply syntax highlighting with hljs.highlightElement when language or value change.

Copy link

@coderabbitai coderabbitai bot left a 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 (4)
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (4)

57-63: LGTM: Effective implementation of highlight.js

The use of useRef and useEffect for highlighting the code with highlight.js is well-implemented. The condition to prevent unnecessary re-highlighting is a good optimization.

Consider memoizing the value prop if it's a large string to potentially reduce unnecessary re-renders:

const memoizedValue = useMemo(() => value, [value]);

Then use memoizedValue in the useEffect dependency array and when rendering.


117-128: LGTM: Proper structure for highlight.js usage

The code block structure using <pre> and <code> tags is correct for highlight.js. The ref is properly attached, and the dynamic language class is appropriately applied.

Consider moving the inline styles to a CSS file for better separation of concerns:

// In your CSS file
.code-block {
  font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
}

// In your component
<code
  ref={codeRef}
  className={`language-${language} code-block`}
>
  {value}
</code>

Line range hint 65-95: Enhance security in file name handling

While the downloadAsFile function works as intended, there's a potential security risk when handling user-provided file names. Consider sanitizing the file name to prevent potential issues with special characters or malicious inputs.

Add a sanitization step for the file name:

const sanitizeFileName = (name: string) => {
  return name.replace(/[^a-z0-9]/gi, '_').toLowerCase();
};

// In the downloadAsFile function
const sanitizedFileName = sanitizeFileName(fileName || suggestedFileName);

This ensures that the file name only contains alphanumeric characters and underscores, reducing the risk of potential security issues or errors when saving the file.


Line range hint 51-132: Consider additional performance and robustness improvements

The overall structure of the CodeBlock component is good, with proper use of memoization and hooks. However, there are a few areas where we can further improve performance and robustness:

  1. Validate the language prop against supported languages to prevent potential issues with unsupported languages.
  2. Add error handling for failed highlighting attempts.
  3. Consider using useMemo for expensive computations if value changes frequently.

Here's a suggested implementation incorporating these improvements:

const CodeBlock: FC<Props> = memo(({ language, value }) => {
  const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 });
  const codeRef = useRef<HTMLElement>(null);

  const safeLanguage = useMemo(() => {
    return Object.keys(programmingLanguages).includes(language) ? language : 'plaintext';
  }, [language]);

  const highlightedCode = useMemo(() => {
    try {
      return hljs.highlight(value, { language: safeLanguage }).value;
    } catch (error) {
      console.error('Failed to highlight code:', error);
      return hljs.highlight(value, { language: 'plaintext' }).value;
    }
  }, [safeLanguage, value]);

  useEffect(() => {
    if (codeRef.current) {
      codeRef.current.innerHTML = highlightedCode;
    }
  }, [highlightedCode]);

  // ... rest of the component

  return (
    <div className="codeblock relative w-full bg-zinc-950 font-sans">
      {/* ... */}
      <pre className="border border-zinc-700">
        <code
          ref={codeRef}
          className={`language-${safeLanguage} code-block`}
        />
      </pre>
    </div>
  );
});

This implementation validates the language, handles potential highlighting errors, and memoizes the highlighted code for better performance.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between bdc59ef and e6f01da.

📒 Files selected for processing (1)
  • templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (1)

Pattern templates/**: For files under the templates folder, do not report 'Missing Dependencies Detected' errors.

🔇 Additional comments (1)
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (1)

3-4: LGTM: Import statements updated correctly

The import statements have been appropriately updated to include highlight.js and its CSS, while also adding useRef to the React imports. These changes align well with the switch from react-syntax-highlighter to highlight.js.

Also applies to: 6-6

Copy link

@coderabbitai coderabbitai bot left a 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 (1)
helpers/typescript.ts (1)

Missing backend parameter in installTSTemplate call

  • helpers/index.ts: await installTSTemplate(props); is missing the required backend parameter.
🔗 Analysis chain

Line range hint 29-29: Ensure all calls to installTSTemplate include the new backend parameter

The function installTSTemplate now includes an additional backend parameter. Please verify that all invocations of this function are updated to include this new parameter to prevent any runtime errors.

You can run the following script to find and review all calls to installTSTemplate:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to `installTSTemplate` and check for the `backend` parameter.

# Search for the function usage and display the following 3 lines.
rg --type typescript 'installTSTemplate\(' -A 3

Length of output: 84


Script:

#!/bin/bash
# Description: Find all calls to `installTSTemplate` in TypeScript files and check for the `backend` parameter.

# Search for the function usage in .ts and .tsx files and display the following 3 lines.
rg 'installTSTemplate\(' -A 3 -g '*.ts' -g '*.tsx'

Length of output: 192

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between e6f01da and dba4f3b.

📒 Files selected for processing (1)
  • helpers/typescript.ts (1 hunks)
🧰 Additional context used

Comment on lines 122 to 123
fontFamily:
'Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace',
Copy link
Collaborator

Choose a reason for hiding this comment

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

@can't we just use the variable?

Suggested change
fontFamily:
'Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace',
fontFamily: "var(--font-mono)",

Copy link

@coderabbitai coderabbitai bot left a 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 (5)
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (4)

3-4: LGTM! Consider customizing the highlight.js theme.

The import changes align well with the PR objective of replacing react-syntax-highlighter with highlight.js. However, as per a previous review comment, you might want to consider using a custom theme for better visual integration with your application.

You can change line 4 to use a custom theme, for example:

-import "highlight.js/styles/atom-one-dark-reasonable.css";
+import "highlight.js/styles/github-dark-dimmed.css";

See all available themes here.

Also applies to: 6-6


58-64: LGTM! Effective use of hooks for syntax highlighting.

The implementation of useRef and useEffect hooks is correct and efficient for applying syntax highlighting. The check to prevent unnecessary re-highlighting is a good performance optimization.

Consider memoizing the value prop if it's an object or array to prevent unnecessary re-renders:

const memoizedValue = useMemo(() => value, [JSON.stringify(value)]);

Then update the effect dependency:

}, [language, memoizedValue]);

This ensures that the effect only runs when the actual content of value changes, not just when its reference changes.


100-102: LGTM! Proper implementation of the className prop.

The className prop is correctly implemented in the main div, allowing for custom styling of the CodeBlock component.

Consider using a utility library like clsx or classnames for more robust class name management, especially if the component's styling complexity grows:

import clsx from 'clsx';

// In the component:
className={clsx(
  'codeblock relative w-full bg-zinc-950 font-sans',
  className
)}

This approach can help manage conditional classes more easily in the future.


120-124: LGTM! Simplified and standard-compliant code rendering structure.

The new rendering structure using <pre> and <code> tags is appropriate for highlight.js and follows HTML standards for code blocks. The dynamic language class is correctly applied for syntax highlighting.

As per a previous review comment, consider using a CSS variable for the font family:

-<code ref={codeRef} className={`language-${language} font-mono`}>
+<code ref={codeRef} className={`language-${language}`} style={{ fontFamily: "var(--font-mono)" }}>

This approach allows for easier global font management and consistency across your application.

templates/types/streaming/nextjs/app/components/ui/chat/chat-message/markdown.tsx (1)

Line range hint 122-138: Improved citation link handling with a minor suggestion

The update to the 'a' component rendering function is a good improvement in handling citation links. It now correctly renders valid citations using the SourceNumberButton component and safely handles invalid ones.

However, for invalid citations (when the index is not a number), consider logging a warning or displaying a subtle error indicator instead of silently rendering nothing. This could help with debugging and provide better feedback to content creators.

Consider adding a warning log or subtle error indicator for invalid citations:

 if (!isNaN(index)) {
   return <SourceNumberButton index={index} />;
 } else {
-  // citation is not looked up yet, don't render anything
-  return <></>;
+  console.warn(`Invalid citation index: ${children[0]}`);
+  return <span title="Invalid citation" style={{ color: 'red' }}>❗</span>;
 }
🧰 Tools
🪛 Biome

[error] 115-115: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between dba4f3b and 3fd0aa5.

📒 Files selected for processing (2)
  • templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (4 hunks)
  • templates/types/streaming/nextjs/app/components/ui/chat/chat-message/markdown.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (1)

Pattern templates/**: For files under the templates folder, do not report 'Missing Dependencies Detected' errors.

templates/types/streaming/nextjs/app/components/ui/chat/chat-message/markdown.tsx (1)

Pattern templates/**: For files under the templates folder, do not report 'Missing Dependencies Detected' errors.

🔇 Additional comments (5)
templates/types/streaming/nextjs/app/components/ui/chat/chat-message/codeblock.tsx (3)

13-13: LGTM! Good addition for component flexibility.

Adding an optional className prop enhances the reusability and customization options for the CodeBlock component.


56-56: LGTM! Component signature updated correctly.

The CodeBlock component signature has been properly updated to include the new className prop, maintaining the use of memo for performance optimization.


Line range hint 1-132: Great job on the CodeBlock component refactor!

The changes successfully implement the switch from react-syntax-highlighter to highlight.js, aligning well with the PR objectives of enhancing performance for code block rendering. The implementation is clean, follows React best practices, and includes some performance optimizations.

Key improvements:

  1. Simplified rendering structure using standard HTML tags.
  2. Efficient use of useRef and useEffect for applying syntax highlighting.
  3. Added flexibility with the new className prop.

Consider the minor suggestions provided in the previous comments for further optimization and consistency. Overall, this refactor should significantly improve the performance of code rendering in the application.

templates/types/streaming/nextjs/app/components/ui/chat/chat-message/markdown.tsx (2)

117-117: LGTM: Improved CodeBlock styling

The addition of the "mb-2" class to the CodeBlock component is a good styling improvement. It likely adds a bottom margin, which should enhance the visual separation between code blocks and surrounding content.


Line range hint 1-153: Overall assessment: Good improvements with minor enhancement suggestion

The changes in this file are well-implemented and improve both the styling of code blocks and the handling of citation links. These modifications align with the PR's objective of enhancing performance, although their direct impact on performance might be minimal.

The code adheres to the provided coding guidelines, and no major issues were found. The suggestion for improving invalid citation handling is a minor enhancement that could further improve the user experience and debugging process.

🧰 Tools
🪛 Biome

[error] 115-115: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

@marcusschiesser marcusschiesser merged commit 8c80cc0 into main Oct 15, 2024
34 checks passed
@marcusschiesser marcusschiesser deleted the fix/enhance-performance-for-code-block branch October 15, 2024 05:21
@coderabbitai coderabbitai bot mentioned this pull request Dec 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants