使用React.js和Node.js构建在线代码编译器

使用React.js和Node.js构建在线代码编译器

在这篇文章中,我们将学习如何使用React.js作为前端和Express.js作为后端构建一个在线代码编译器。用户将能够使用正确的语法高亮编写C、C++、Python和Java代码,并在线编译和执行它。构建在线编译器的主要目标是为用户提供方便,使得可以编译和运行任何语言的程序,而无需下载任何IDE(集成开发环境)或编译器。

先决条件: 这个项目的先决条件是:

  • HTML、CSS和JavaScript的基础知识
  • React.js的基础知识
  • API、Express.js和Node.js的基础知识

方法: 在构建整个应用程序之前,让我们将应用程序分为两部分。第一部分是使用React.js构建前端,第二部分是使用Express.js构建后端。在前端,我们有三个部分,一个文本编辑器,一个输入框和一个输出框。在后端,我们创建一个API并实现从前端提供的源代码编译的逻辑。

让我们首先开始构建前端。

创建一个React应用程序:

步骤1: 在终端中输入以下命令来创建一个React应用程序:

npx create-react-app code-compiler

步骤2: 现在,通过运行以下命令转到项目文件夹,即 code-compiler:

cd code-compiler

项目结构:

它将如下所示:

使用React.js和Node.js构建在线代码编译器

步骤3: 让我们构建一个文本编辑器,用户可以在其中编写代码。为此,我们将使用 Monaco Editor 这是微软VS Code IDE使用的代码编辑器。因此,我们将使用一个名为’@monaco-editor/react’的npm包来实现这个目的。安装一些npm包:

npm install @monaco-editor/react
npm install axios
npm install react-select

步骤4: 在App.js文件中,我们将导入文本编辑器并创建输入部分和输出部分。此外,我们还将实现两个按钮,一个名为’Run’,另一个名为’Clear’。每当用户点击’Run’按钮时,它将调用一个API来编译我们的源代码,并在输出屏幕上显示结果。当点击Clear按钮时,将用于清除输出屏幕。

文件名: App.js

import { useState } from 'react';
import './App.css';
import Editor from "@monaco-editor/react";
import Navbar from './Components/Navbar';
import Axios from 'axios';
import spinner from './spinner.svg';
 
function App() {
 
    // State variable to set users source code
    const [userCode, setUserCode] = useState(``);
 
    // State variable to set editors default language
    const [userLang, setUserLang] = useState("python");
 
    // State variable to set editors default theme
    const [userTheme, setUserTheme] = useState("vs-dark");
 
    // State variable to set editors default font size
    const [fontSize, setFontSize] = useState(20);
 
    // State variable to set users input
    const [userInput, setUserInput] = useState("");
 
    // State variable to set users output
    const [userOutput, setUserOutput] = useState("");
 
    // Loading state variable to show spinner
    // while fetching data
    const [loading, setLoading] = useState(false);
 
    const options = {
        fontSize: fontSize
    }
 
    // Function to call the compile endpoint
    function compile() {
        setLoading(true);
        if (userCode === ``) {
            return
        }
 
        // Post request to compile endpoint
        Axios.post(`http://localhost:8000/compile`, {
            code: userCode,
            language: userLang,
            input: userInput
        }).then((res) => {
            setUserOutput(res.data.output);
        }).then(() => {
            setLoading(false);
        })
    }
 
    // Function to clear the output screen
    function clearOutput() {
        setUserOutput("");
    }
 
    return (
        <div className="App">
            <Navbar
                userLang={userLang} setUserLang={setUserLang}
                userTheme={userTheme} setUserTheme={setUserTheme}
                fontSize={fontSize} setFontSize={setFontSize}
            />
            <div className="main">
                <div className="left-container">
                    <Editor
                        options={options}
                        height="calc(100vh - 50px)"
                        width="100%"
                        theme={userTheme}
                        language={userLang}
                        defaultLanguage="python"
                        defaultValue="# Enter your code here"
                        onChange={(value) => { setUserCode(value) }}
                    />
                    <button className="run-btn" onClick={() => compile()}>
                        Run
                    </button>
                </div>
                <div className="right-container">
                    <h4>Input:</h4>
                    <div className="input-box">
                        <textarea id="code-inp" onChange=
                            {(e) => setUserInput(e.target.value)}>
                        </textarea>
                    </div>
                    <h4>Output:</h4>
                    {loading ? (
                        <div className="spinner-box">
                            <img src={spinner} alt="Loading..." />
                        </div>
                    ) : (
                        <div className="output-box">
                            <pre>{userOutput}</pre>
                            <button onClick={() => { clearOutput() }}
                                className="clear-btn">
                                Clear
                            </button>
                        </div>
                    )}
                </div>
            </div>
        </div>
    );
}
 
export default App;

我们已经导入了一个旋转器来指示当用户点击“运行”按钮时的加载状态。从互联网上下载任何你选择的旋转器,然后将其放入“ src ”文件夹中。

步骤5: 让我们给我们的应用程序加上一些样式。

文件名:App.css

.App {
    max-height: 100vh;
    width: 100%;
    overflow-y: hidden;
    background-color: #474747;
}
 
.main {
    display: flex;
    height: calc(100vh - 50px);
}
 
.left-container {
    position: relative;
    flex: 60%;
    height: calc(100vh - 50px);
}
 
.right-container {
    flex: 40%;
    height: calc(100vh - 50px);
    display: flex;
    flex-direction: column;
    background-color: #242424;
    border-left: 3px solid #1f65e6;
    padding: 5px;
}
 
.input-box {
    flex: 50%;
}
 
.input-box textarea {
    font-size: 16px;
}
 
.spinner-box {
    flex: 50%;
    background-color: #242424;
    overflow-y: auto;
    display: flex;
    justify-content: center;
    align-items: center;
}
 
.spinner-box img {
    width: 200px;
}
 
.output-box {
    flex: 50%;
    background-color: #242424;
    overflow-y: auto;
    color: white;
    position: relative;
}
 
.clear-btn {
    position: absolute;
    bottom: 14px;
    right: 18px;
    width: 80px;
    height: 40px;
    font-size: 22px;
    font-weight: bold;
    color: white;
    background-color: #1f65e6;
    border: none;
    border-radius: 4px;
    transition: 0.3s;
    cursor: pointer;
}
 
.output-box pre {
    font-size: 15px;
    white-space: pre-wrap;
}
 
h4 {
    color: #afec3f;
}
 
#code-inp {
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    resize: none;
    background-color: #242424;
    color: whitesmoke;
    padding: 5px;
}
 
#code-inp:focus {
    outline: none;
}
 
.run-btn {
    position: absolute;
    bottom: 10px;
    right: 18px;
    width: 80px;
    height: 40px;
    font-size: 22px;
    font-weight: bold;
    background-color: #afec3f;
    border: none;
    border-radius: 4px;
    transition: 0.3s;
    cursor: pointer;
}
 
.run-btn:active {
    background-color: #6e9427;
}

步骤6: 让我们构建导航栏,我们已经将其导入到 App.js 文件中。在这个导航栏中,我们可以选择语言类型,选择主题,还可以设置字体大小。因此,在 src 文件夹下创建一个名为“ Components ”的文件夹,然后在其中创建一个名为“ Navbar.js ”的组件。

文件名: Navbar.js

import React from 'react';
import Select from 'react-select';
import '../Styles/Navbar.css';
 
const Navbar = ({ userLang, setUserLang, userTheme,
    setUserTheme, fontSize, setFontSize }) => {
    const languages = [
        { value: "c", label: "C" },
        { value: "cpp", label: "C++" },
        { value: "python", label: "Python" },
        { value: "java", label: "Java" },
    ];
    const themes = [
        { value: "vs-dark", label: "Dark" },
        { value: "light", label: "Light" },
    ]
    return (
        <div className="navbar">
            <h1>Geeks Code Compiler</h1>
            <Select options={languages} value={userLang}
                onChange={(e) => setUserLang(e.value)}
                placeholder={userLang} />
            <Select options={themes} value={userTheme}
                onChange={(e) => setUserTheme(e.value)}
                placeholder={userTheme} />
            <label>Font Size</label>
            <input type="range" min="18" max="30"
                value={fontSize} step="2"
                onChange={(e) => { setFontSize(e.target.value) }} />
        </div>
    )
}
 
export default Navbar

步骤7: 设计导航栏。

文件名:Navbar.css

.navbar {
    display: flex;
    align-items: center;
    padding-left: 20px;
    height: 50px;
    text-align: center;
    color: #afec3f;
    background-color: #474747;
    gap: 20px;
}
 
#no {
    height: 36px;
    width: 80px;
    font-size: 16px;
    color: rgb(185, 185, 185);
    border: 1px solid #afec3f;
    border-radius: 4px;
    background-color: #474747;
}
 
#no:focus {
    outline: none;
}
 
.css-2b097c-container {
    width: 120px;
    color: black;
    background-color: #474747;
}
 
.css-yk16xz-control {
    background-color: #474747 !important;
    border-color: #afec3f !important;
}

现在,让我们开始构建后端

对于后端,我们将使用Express.js。在这里,我们将为我们的代码创建一个API端点来编译。所以让我们创建一个名为 server 的文件夹,其中包含所有的后端逻辑。

步骤1: 在终端中输入以下命令:

mkdir server
cd server

步骤2: 让我们初始化一个node.js项目:

npm init

步骤3: 让我们安装一些依赖项:

npm install express
npm install cors
npm install axios

步骤4:创建一个名为‘index.js’的文件。这是唯一一个包含所有后端逻辑的文件。在这个文件中,我们将创建一个POST路由,用于从前端获取源代码、编程语言和输入(如果有)。在获取到这些信息后,它会调用代码编译API(开源),将其响应发送回前端,结果将显示在输出屏幕上。

文件名:index.js

const express = require("express");
const cors = require("cors");
const Axios = require("axios");
const app = express();
const PORT = 8000;
 
app.use(cors());
app.use(express.json());
 
app.post("/compile", (req, res) => {
    //getting the required data from the request
    let code = req.body.code;
    let language = req.body.language;
    let input = req.body.input;
 
    if (language === "python") {
        language = "py"
    }
 
    let data = ({
        "code": code,
        "language": language,
        "input": input
    });
    let config = {
        method: 'post',
        url: 'https://codexweb.netlify.app/.netlify/functions/enforceCode',
        headers: {
            'Content-Type': 'application/json'
        },
        data: data
    };
    //calling the code compilation API
    Axios(config)
        .then((response) => {
            res.send(response.data)
            console.log(response.data)
        }).catch((error) => {
            console.log(error);
        });
})
 
app.listen(process.env.PORT || PORT, () => {
    console.log(`Server listening on port ${PORT}`);
});

现在,我们已经成功创建了前端将调用的POST请求路由。

启动后端服务器:

node index.js

服务器将侦听本地端口8000

启动前端应用程序:

npm start

输出: 现在打开你的浏览器并访问 http://localhost:3000/ ,你将看到以下输出:

使用React.js和Node.js构建在线代码编译器

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程