Build a Node.js Interactive Web-Based Simple Code Diff Tool

In the world of software development, comparing code is a daily necessity. Whether you’re reviewing changes, merging branches, or simply trying to understand the evolution of a codebase, a good code diff tool is indispensable. Imagine a scenario: you’re collaborating on a project, and a teammate has submitted a pull request. You need to quickly and clearly see the differences between the proposed changes and the existing code. Manually comparing files line by line is time-consuming and prone to errors. This is where a code diff tool shines. In this tutorial, we’ll build a simple, interactive, web-based code diff tool using Node.js. This tool will allow you to input two code snippets and visualize the differences between them, highlighting additions, deletions, and modifications.

Why Build a Code Diff Tool?

Creating your own code diff tool offers several advantages:

  • Learning Opportunity: Building this tool provides hands-on experience with Node.js, HTML, CSS, and JavaScript, solidifying your understanding of these technologies.
  • Customization: You can tailor the tool to your specific needs, such as supporting different programming languages or adding features like syntax highlighting.
  • Practical Application: The tool will be a valuable asset in your development workflow, helping you to efficiently compare and understand code changes.

Prerequisites

Before we begin, make sure you have the following installed:

  • Node.js and npm (Node Package Manager): You can download them from the official Node.js website (nodejs.org). npm comes bundled with Node.js.
  • A Code Editor: Choose your favorite code editor, such as Visual Studio Code, Sublime Text, or Atom.

Setting Up the Project

Let’s start by creating a new project directory and initializing it with npm:

mkdir code-diff-tool
cd code-diff-tool
npm init -y

This will create a package.json file in your project directory. Next, we need to install some dependencies. We’ll use the following packages:

  • express: A web application framework for Node.js, used to create our server.
  • diff: A library for generating the diff between two strings.
  • ejs: A templating engine for rendering HTML.

Install these dependencies using npm:

npm install express diff ejs

Project Structure

Create the following file structure for your project:

code-diff-tool/
├── index.js          # Main server file
├── views/
│   └── index.ejs     # HTML template
├── public/
│   ├── style.css     # CSS styles
│   └── script.js     # JavaScript for client-side logic
└── package.json

Building the Server (index.js)

Create the index.js file and add the following code:

const express = require('express');
const { diffChars } = require('diff');
const app = express();
const port = 3000;

app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));
app.set('view engine', 'ejs');
app.set('views', './views');

app.get('/', (req, res) => {
  res.render('index', { diffResult: null });
});

app.post('/diff', (req, res) => {
  const code1 = req.body.code1;
  const code2 = req.body.code2;

  const diff = diffChars(code1, code2);
  res.render('index', { diffResult: diff });
});

app.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});

Let’s break down this code:

  • We import the necessary modules: express for the server and diffChars from the diff library.
  • We create an Express application and set the port to 3000.
  • We use express.static('public') to serve static files (CSS, JavaScript) from the public directory.
  • express.urlencoded({ extended: true }) is middleware that parses URL-encoded bodies, which is necessary to access the data submitted in the HTML form.
  • We set the view engine to ejs and specify the views directory.
  • We define two routes:
    • GET /: Renders the index.ejs template with an empty diffResult.
    • POST /diff: This route handles the form submission. It retrieves the two code snippets from the request body, uses the diffChars function to generate the diff, and renders the index.ejs template again, passing the diff result to it.
  • Finally, we start the server and listen on the specified port.

Creating the HTML Template (views/index.ejs)

Create the views/index.ejs file and add the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Code Diff Tool</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <h2>Code Diff Tool</h2>
    <form action="/diff" method="POST">
        <div class="code-input">
            <label for="code1">Code 1:</label>
            <textarea id="code1" name="code1" rows="10" cols="50"></textarea>
        </div>
        <div class="code-input">
            <label for="code2">Code 2:</label>
            <textarea id="code2" name="code2" rows="10" cols="50"></textarea>
        </div>
        <button type="submit">Compare</button>
    </form>
    <div class="diff-output">
        <% if (diffResult) { %>
            <h3>Diff Result:</h3>
            <div class="diff-container">
                <% diffResult.forEach(part => { %>
                    <span class="<%= part.added ? 'added' : part.removed ? 'removed' : 'unchanged' %>">
                        <%= part.value %>
                    </span>
                <% }); %>
            </div>
        <% } %>
    </div>
    <script src="script.js"></script>
</body>
</html>

This is an EJS template that defines the structure of our web page. Let’s break it down:

  • The HTML structure includes a title, two text areas for entering the code snippets, and a button to submit the form.
  • The form submits to the /diff route using the POST method.
  • The <% if (diffResult) { %> block conditionally displays the diff result if it exists.
  • We iterate through the diffResult array (passed from the server) and create <span> elements for each part of the diff.
  • We use CSS classes (added, removed, unchanged) to style the different parts of the diff. We will define these styles in our CSS file.

Adding Styles (public/style.css)

Create the public/style.css file and add the following styles:

body {
    font-family: sans-serif;
    margin: 20px;
}

h2, h3 {
    margin-bottom: 10px;
}

.code-input {
    margin-bottom: 20px;
}

label {
    display: block;
    margin-bottom: 5px;
}

textarea {
    width: 100%;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
}

button {
    padding: 10px 20px;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

button:hover {
    background-color: #3e8e41;
}

.diff-container {
    white-space: pre-wrap;
    font-family: monospace;
    border: 1px solid #ddd;
    padding: 10px;
    border-radius: 4px;
}

.added {
    background-color: #e6ffec;
    color: #24292e;
}

.removed {
    background-color: #ffeef0;
    color: #24292e;
    text-decoration: line-through;
}

.unchanged {
    color: #24292e;
}

These styles provide basic formatting for the HTML elements, including:

  • Font styles and margins.
  • Styles for labels, text areas, and buttons.
  • Styles for the diff container, and the added, removed, and unchanged sections.

Adding Client-Side Logic (public/script.js)

Create the public/script.js file and add the following code:

// You can add client-side JavaScript here if you need any.  For this simple tool, it's not strictly necessary.

For this simple example, we don’t need any client-side JavaScript. However, you could add features like syntax highlighting or real-time updates here.

Running the Application

Now that we have all the files in place, let’s run the application. In your terminal, navigate to your project directory and run the following command:

node index.js

This will start the server. Open your web browser and go to http://localhost:3000. You should see the code diff tool. Enter two code snippets into the text areas, click the “Compare” button, and see the differences highlighted.

Example Usage

Let’s say you have these two code snippets:

Code 1:

function greet(name) {
  console.log("Hello, " + name + "!");
}

greet("World");

Code 2:

function greet(name) {
  console.log("Greetings, " + name + "!");
}

greet("World");

When you enter these snippets into the tool, the output should highlight the change in the greeting message.

Common Mistakes and Troubleshooting

Here are some common mistakes and how to fix them:

  • Incorrect File Paths: Double-check that your file paths in index.js and index.ejs are correct.
  • Missing Dependencies: Ensure you have installed all the required dependencies using npm install.
  • Server Not Running: Make sure the server is running in your terminal. You should see a message like “Server is running at http://localhost:3000”.
  • CSS Not Loading: Verify that the link to style.css in your index.ejs file is correct and that the file exists in the public directory.
  • Form Submission Not Working: Check that the action attribute in your <form> tag is set to /diff and the method attribute is set to POST. Also, ensure that the name attributes of your <textarea> elements match the keys you’re using to access the data in your server-side code (code1 and code2).

Enhancements and Next Steps

You can enhance this tool in several ways:

  • Syntax Highlighting: Integrate a code highlighting library like Prism.js or highlight.js to improve readability.
  • Language Support: Add support for different programming languages.
  • Real-time Updates: Use WebSockets to update the diff in real-time as you type.
  • Code Folding: Implement code folding to collapse and expand sections of code.
  • Line Numbers: Add line numbers to the code snippets for easier reference.

Summary/Key Takeaways

In this tutorial, we’ve built a functional, web-based code diff tool using Node.js, Express, EJS, and the diff library. We’ve covered the essential steps, from setting up the project and installing dependencies to creating the server, HTML template, and CSS styles. This project provides a solid foundation for understanding how to compare code changes programmatically and build interactive web applications with Node.js. Remember that practice is key. The more you experiment with these concepts and build your own projects, the more comfortable you’ll become with Node.js and web development in general. Take the time to explore the enhancements, and don’t be afraid to experiment with the code and try new things. Building this tool allows you to streamline your workflow and become more efficient in your development tasks.

FAQ

Q: Can I use this tool for comparing any type of text, not just code?
A: Yes, you can. The core logic of the diff library works with any strings, so you can adapt the tool to compare any text-based content.

Q: How can I deploy this tool online?
A: You can deploy this tool to platforms like Heroku, Netlify, or AWS. You’ll need to configure the platform to run your Node.js application and serve the static files.

Q: What if I want to compare files instead of just pasting code?
A: You would need to add file upload functionality to your tool. This involves using a library like multer to handle file uploads, reading the file contents, and then passing those contents to the diff function.

Q: Is there a limit to the size of code snippets I can compare?
A: The diff library itself doesn’t have a strict limit, but very large code snippets might impact performance. You might need to implement optimizations or consider using a different diffing algorithm for extremely large files.

This simple code diff tool is a stepping stone. As you delve deeper, you’ll discover new possibilities. The ability to quickly and accurately compare code is a critical skill for any developer, and building this tool has provided you with a practical understanding of how to achieve this. Now, go forth and compare!