使用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
项目结构:
它将如下所示:
步骤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/ ,你将看到以下输出: