Front End Project Structure
Install MUI npm install @mui/material @emotion/react @emotion/styled
Install Monaco Editor npm i @monaco-editor/react
Creating AppBar.js inside widgets folder
import * as React from 'react';
import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import IconButton from '@mui/material/IconButton';
import MenuIcon from '@mui/icons-material/Menu';
export default function MyAppBar() {
return (
<Box sx={{ flexGrow: 1 }}>
<AppBar position="sticky" elevation={0} >
<Toolbar variant="dense">
<IconButton edge="start" color="inherit" aria-label="menu" sx={{ mr: 2 }}>
<MenuIcon />
</IconButton>
<Typography variant="h6" color="inherit" component="div">
My Code Editor
</Typography>
</Toolbar>
</AppBar>
</Box>
);
}
Create Code Component inside the pages folder
import Container from '@mui/material/Container';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import { CodeEditor } from '../components/CodeEditor';
import { Output } from '../components/Output';
import { useMonaco } from '@monaco-editor/react';
import MyAppBar from '../widgets/AppBar';
import { useState } from 'react';
export const Code = ()=>{
const [display, setDisplay]= useState('');
const showResult = (res)=>{
console.log('Data is ',res);
setDisplay(res.data.result);
}
return (<>
<MyAppBar/>
<Grid sx={{ flexGrow: 1 }} container spacing={2}>
<Grid item md={8}>
<CodeEditor showResult={showResult}/>
</Grid>
<Grid item md={4}>
<Output result = {display}/>
</Grid>
</Grid>
</>);
}
Create editor Component
import Editor, { useMonaco } from "@monaco-editor/react";
import { useRef } from "react";
import Button from '@mui/material/Button';
import { sendCode } from "../services/api-client";
import TextField from '@mui/material/TextField';
export const CodeEditor = ({showResult})=>{
const editorRef = useRef(null);
const fileName = useRef('');
const getCode = async ()=>{
const fName = fileName.current.value;
const val = editorRef.current?.getValue();
console.log('val ',val);
const result = await sendCode(val, fName);
showResult(result);
}
const options = {"fontSize": 20, selectOnLineNumbers: true,cursorStyle: 'line',
colorDecorators: true
,scrollbar: {
// Subtle shadows to the left & top. Defaults to true.
useShadows: false,
// Render vertical arrows. Defaults to false.
verticalHasArrows: true,
// Render horizontal arrows. Defaults to false.
horizontalHasArrows: true,
// Render vertical scrollbar.
// Accepted values: 'auto', 'visible', 'hidden'.
// Defaults to 'auto'
vertical: 'visible',
// Render horizontal scrollbar.
// Accepted values: 'auto', 'visible', 'hidden'.
// Defaults to 'auto'
horizontal: 'visible',
verticalScrollbarSize: 17,
horizontalScrollbarSize: 17,
arrowSize: 30,
},};
const handleEditorDidMount = (editor, monaco) =>{
editorRef.current = editor;
editor.focus();
// let options = {"fontSize": 20, selectOnLineNumbers: true,cursorStyle: 'line',scrollbar: {
// // Subtle shadows to the left & top. Defaults to true.
// useShadows: false,
// // Render vertical arrows. Defaults to false.
// verticalHasArrows: true,
// // Render horizontal arrows. Defaults to false.
// horizontalHasArrows: true,
// // Render vertical scrollbar.
// // Accepted values: 'auto', 'visible', 'hidden'.
// // Defaults to 'auto'
// vertical: 'visible',
// // Render horizontal scrollbar.
// // Accepted values: 'auto', 'visible', 'hidden'.
// // Defaults to 'auto'
// horizontal: 'visible',
// verticalScrollbarSize: 17,
// horizontalScrollbarSize: 17,
// arrowSize: 30,
// },}
//editor.updateOptions(options);
}
return (
<>
<TextField inputRef={fileName} id="outlined-basic" label="FileName" variant="outlined" />
<Editor
className="style"
theme="vs-dark"
onMount={handleEditorDidMount}
height="80%"
width="100%"
defaultLanguage="java"
defaultValue="// Write Code Here"
options={options}
/>
<Button onClick={getCode} color='success' variant="contained">Compile and Run</Button>
</>
);
}
Create Output Component
import * as React from 'react';
import Box from '@mui/material/Box';
export const Output = ({result})=>{
return (<div>
<Box
sx={{
width: "90%",
height: "70vh",
p: 2, border: '1px dashed grey'
}}
>
{result}
</Box>
</div>)
}
Install axios for BackEnd API Call. npm i axios
Create api-client.js inside the services folder
import axios from 'axios';
export const sendCode = async (code, fileName)=>{
const URL = 'http://localhost:1234/compile-run';
const codeObject = {'code':code, 'filename':fileName};
const result = await axios.post(URL,codeObject);
return result;
}
Let's start with BackEnd Now
Install express and cors (npm i express cors)
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors());
app.use(express.json());
app.use('/', require('./routes/route'));
const server = app.listen(1234, err=>{
if(err){
console.log('Server Crash ', err);
}
else{
console.log('Server Start ', server.address().port);
}
})
const express = require('express');
const router = express.Router();
const childProcess = require('child_process');
const path = require('path');
router.post('/compile-run',(request, response)=>{
const code = request.body.code;
const fileName = request.body.filename;
console.log('Body is ', request.body);
const fs = require('fs');
const parent = path.normalize(__dirname+'/..');
const fullPath = path.join(parent,'/mycode',fileName);
const sourceFile=fullPath+".java";
console.log('Source File Path ', sourceFile);
fs.writeFileSync(sourceFile,code);
try{
let result= childProcess.execSync('javac '+sourceFile);
const mycodeDir = path.join(parent,'/mycode');
console.log('Code DIR ', mycodeDir);
console.log('My File ',fileName);
console.log('PWD ',result.toString());
const commands = ` cd ${mycodeDir}
pwd ${fileName}
java ${fileName}
`;
result = childProcess.execSync(commands);
console.log(result.toString());
response.status(200).json({result:result.toString()});
}
catch(err){
response.status(500).json({result:JSON.stringify(err)});
}
});
module.exports = router;
That's All Folks, Happy Coding :)