If you have any questions or feedback, pleasefill out this form
This post is translated by ChatGPT and originally written in Mandarin, so there may be some inaccuracies or mistakes.
Better-express-error
When developing with Express, encountering errors usually results in them being displayed directly on the error page or redirected to a 404 or 500 page in production.
While this might not seem like a big deal, let’s be honest—does seeing such pages make you happy?

Engineers familiar with Ruby on Rails have likely used better_errors or the built-in error trace page in Rails for debugging.
However, in Express, there hasn't been a package similar to better_errors, often leaving developers to face these ugly error messages with despair.
So, I decided to create a simple middleware to handle this. Essentially, it's an Express implementation of better_errors.
Analyzing Error Messages
TypeError: range out of bound. Please check http://kjj6198.github.io for more information.
at app.get (/Users/kalan/code/express-error/server/app.js:17:9)
at Layer.handle [as handle_request] (/Users/kalan/code/express-error/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/kalan/code/express-error/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/kalan/code/express-error/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/kalan/code/express-error/node_modules/express/lib/router/layer.js:95:5)
at /Users/kalan/code/express-error/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/Users/kalan/code/express-error/node_modules/express/lib/router/index.js:335:12)
at next (/Users/kalan/code/express-error/node_modules/express/lib/router/index.js:275:10)
at jsonParser (/Users/kalan/code/express-error/node_modules/body-parser/lib/types/json.js:109:7)
at Layer.handle [as handle_request] (/Users/kalan/code/express-error/node_modules/express/lib/router/layer.js:95:5)Upon careful observation, we can see that the format of the error message is quite orderly. The first line contains the error name and message, which is usually the most crucial information. The following lines represent the call stack. The at ... denotes a function call, with the file name and line number in parentheses.
After briefly analyzing the error message, we can convert the plain text into more useful information. By using split('\n') and applying simple regular expression matching, we can separate the file name and line number information.
Displaying Errors
The first line of the error message typically contains the most important information, as that’s where the code has failed. Therefore, we’ll place this first line in a prominent position and highlight it.

For the lines following the first, we’ll use color and size to highlight the file name, line number, and function name.

Compared to the earlier dense block of text, this simple formatting allows developers to quickly grasp what has gone wrong.
Displaying File Content
In addition to showing the error message, we also want to display the corresponding file content and its context. Therefore, the right side of the page can utilize the file name and line number provided in the error message to display the relevant file content.
For Node.js, this can be easily accomplished using fs.readFileSync.
function(filename, line, row) {
const content = fs.readFileSync(filename);
content.toString()
.split('\n')
.slice(line - 5, line + 5)
.map(content => `<span>${content}</span>`)
.join('\n');
}Here, we simply print the five lines before and after the error line. A more sophisticated approach would be to use techniques like AST to print only the relevant function content. However, for now, we will print the five lines surrounding the error.
With some adjustments and modifications, it looks like this:

Through simple highlighting, developers can quickly identify where the error occurred.
REPL
Beyond displaying errors, we want this page to allow users to input simple code snippets to verify issues and make real-time code modifications.
In Node.js, there is a VM module that allows you to execute given code within V8's Virtual Machine contexts. With this module, we can implement a REPL-like feature!
const debugContext = vm.createContext({
request: req,
response: res,
util: require("util"),
Buffer: require("buffer").Buffer,
stream: require("stream"),
console: {
log: util.format,
},
clear: "",
})By passing the variables we want to expose into the context, we can conveniently achieve debugging through a POST request that reads the front-end code.

(Note: Some adjustments are still needed)
Full Integration!

After full integration, the page will look something like this.
Compared to the original plain text, although it took some effort to adjust the page style and implement the REPL feature, the debugging process has become much smoother.
Conclusion
The complete implementation can be found in this repository. I plan to gradually refactor the implementation into middleware for easier use. Additionally, I will optimize the entire layout and code highlighting to make the overall process and interface even smoother. Although I’m not sure how long this will take, XD
If you have any suggestions, feel free to open an issue!
If you found this article helpful, please consider buying me a coffee ☕ It'll make my ordinary day shine ✨
☕Buy me a coffee