Welcome to the HighlightedCode project!
In this first chapter, we are going to look at the safety features of our code renderer. Before we worry about making things fast or pretty, we must ensure they are robust.
Imagine you are building a terminal application that displays code snippets. You want to syntax highlight a Python file. You ask your highlighting library to process it.
But what happens if:
In a naive application, your entire program might crash. The screen goes black, and the user sees a stack trace. This is a bad user experience.
We use a strategy called Defensive Language Fallback. Think of it like a car with a spare tire.
This ensures the car (your application) keeps moving, even if a tire blows out.
Let's say a user tries to open a file named script.unknown.
script.unknown and some code content..unknown.
The main entry point for this logic is a component called HighlightedCodeFallback. You don't need to configure the safety net; it happens automatically.
Here is how you would use it in your code:
// Example Usage
<HighlightedCodeFallback
code="console.log('Hello World');"
filePath="example.js"
dim={false}
/>
When you render this, the component calculates the file extension (js) and attempts to highlight it. If anything goes wrong inside the highlighting engine, it catches the error and displays the code safely.
Let's look under the hood. When the component renders, it follows a strict decision tree to ensure it never crashes.
skipColoring is true, return plain text immediately.filePath (e.g., .js -> js).markdown.markdown, and try again.Here is a sequence diagram showing what happens when a language isn't supported or fails.
Let's look at the actual logic inside Fallback.tsx.
(Note: The code below is simplified to remove performance optimizations for clarity. We will cover those in React Compiler Memoization.)
First, the component figures out what language to ask for based on the file path.
// Inside HighlightedCodeFallback component
// filePath might be "src/utils.ts"
const extension = extname(filePath).slice(1);
// extension becomes "ts"
// We pass this 'language' down to the worker component
return <Highlighted codeWithSpaces={code} language={extension} />;
Inside the Highlighted component, we check if the language exists before we even try to run the heavy code.
let highlightLang = "markdown"; // Default to safety
if (language && hl.supportsLanguage(language)) {
// If the highlighter knows this language, use it
highlightLang = language;
} else {
// Otherwise, log it and stick to markdown
logForDebugging(`Language not supported: ${language}`);
}
Logic: By default, we assume we are using Markdown (the spare tire). We only switch to the specialized tire if supportsLanguage returns true.
Finally, even if the language is supported, the highlighting function itself might crash due to bad input. We wrap that in a try/catch block.
try {
// Attempt the main highlight
return cachedHighlight(hl, codeWithSpaces, highlightLang);
} catch (e) {
// IF IT CRASHES:
logForDebugging(`Highlight error, falling back: ${e}`);
// Use the spare tire (Markdown)
return cachedHighlight(hl, codeWithSpaces, 'markdown');
}
This specific block is the core of Defensive Language Fallback. No matter what error cachedHighlight throws, the application catches it and renders the content as generic markdown.
In this chapter, we learned:
try/catch blocks, we ensure the user never sees a crash.Now that we know how to handle errors safely, how do we actually load the highlighter without freezing the application?
Next, we will learn about Async Highlighter Loading.
Generated by Code IQ