En este artículo, aprenderemos cómo crear un compilador de código en línea usando React.js como frontend y Express.js como backend. Los usuarios podrán escribir código C, C++, Python y Java con el resaltado de sintaxis adecuado, así como compilarlo y ejecutarlo en línea. El principal objetivo de construir un compilador en línea es facilitar a cualquier usuario que los programas de cualquier idioma puedan compilarse y ejecutarse sin descargar ningún IDE (Entorno de desarrollo integrado) o compilador.
Requisitos previos: Los requisitos previos para este proyecto son:
- Conocimientos básicos de HTML, CSS y JavaScript
- Conocimientos básicos de React.js
- Conocimientos básicos de API , Express.js , Node.js
Enfoque: Antes de construir toda la aplicación, dividamos la aplicación en dos partes. La primera parte se trata de construir el front-end usando React.js y la segunda parte está construyendo el back-end usando Express.js. En el front-end, tenemos tres secciones, un editor de texto, un cuadro de entrada y un cuadro de salida. En el back-end, creamos una API e implementamos la lógica para compilar el código fuente proporcionado desde el front-end.
Comencemos a construir el Front-end primero.
Creando una aplicación React:
Paso 1: Cree una aplicación React escribiendo el siguiente comando en la terminal:
npx create-react-app code-compiler
Paso 2: ahora, vaya a la carpeta del proyecto, es decir, al compilador de código, ejecutando el siguiente comando:
cd code-compiler
Estructura del proyecto: Se verá así:
Paso 3: Construyamos el editor de texto donde los usuarios escribirán su código. Para esto, usaremos el Editor de Mónaco, que es exactamente el editor de código que usa Microsoft VS Code IDE. Así que usaremos un paquete npm llamado ‘ @monaco-editor/react ‘ para este propósito. Instale algunos paquetes npm:
npm install @monaco-editor/react
npm install axios
npm install react-select
Paso 4: en el archivo App.js, importaremos el editor de texto y crearemos la sección de entrada y la sección de salida. Además, implementaremos dos botones, uno llamado ‘Ejecutar’ y el otro ‘Borrar’. Cada vez que el usuario haga clic en el botón Ejecutar, llamará a una API que compilará nuestro código fuente y mostrará el resultado en la pantalla de salida. El botón Borrar se utilizará para borrar la pantalla de salida cuando se haga clic.
Nombre de archivo: App.js
Javascript
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;
Hemos importado un control giratorio para indicar la carga cuando el usuario presiona el botón Ejecutar. Descargue cualquier spinner de su elección de Internet y colóquelo dentro de la carpeta ‘ src ‘.
Paso 5: Démosle un poco de estilo a nuestra aplicación.
Nombre de archivo: App.css
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; }
Paso 6: Construyamos la barra de navegación que ya hemos importado al archivo App.js. En esta barra de navegación, podemos seleccionar el tipo de idioma, elegir un tema y también podemos establecer el tamaño de fuente. Entonces, cree una carpeta llamada ‘ Componentes ‘ debajo de la carpeta src y dentro de ella cree un componente llamado ‘ Navbar.js ‘.
Nombre de archivo: Navbar.js
Javascript
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
Paso 7: Diseñemos la barra de navegación.
Nombre de archivo: Navbar.css
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; }
Ahora comencemos a construir el Back-end
Para el backend, usaremos Express.js. Aquí crearemos un punto final de API para compilar nuestro código. Así que vamos a crear una carpeta llamada ‘ servidor ‘ que contendrá toda la lógica de back-end.
Paso 1: escriba los siguientes comandos en la terminal:
mkdir server
cd server
Paso 2: Inicialicemos un proyecto node.js:
npm init
Paso 3: Instalemos algunas dependencias:
npm install express
npm install cors
npm install axios
Paso 4: Cree un archivo llamado ‘ index.js ‘. Este es el único archivo que contendrá toda la lógica de back-end. En este archivo, crearemos una ruta POST que tomará el código fuente, el idioma y la entrada, si corresponde, desde la interfaz. Después de obtenerlos, llamará a la API de compilación de código (código abierto) cuya respuesta se enviará de vuelta a la interfaz donde se mostrará el resultado en la pantalla de salida.
Nombre de archivo: index.js
Javascript
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}`); });
Ahora, hemos creado con éxito la ruta de solicitud POST a la que llamaremos desde la interfaz.
Inicie el servidor de fondo:
node index.js
El servidor escuchará en el puerto localhost 8000
Inicie la aplicación frontal:
npm start
Salida: Ahora abra su navegador y vaya a http://localhost:3000/ , verá la siguiente salida: