前言
初学者学习编程语言时,通常需要安装编程语言对应的环境,以Python为例,要学习Python,你就需要下载Python解释器并安装到本地,对于没有编程经验的人而言,这一步难倒了很多人,所以很多编程学习网站提供了在线编程的功能,学习者可以在网站上直接编写Python代码,然后点击运行,便可以在网页中得到相应的结果,这是怎么做到的?
最近刚好在做直播任务,即每周要做一定量的抖音直播,昨日直播时,临时起意,打算实现这个功能并将查资料、研究、开发的过程作为直播内容,开播时,我也不知道自己能不能弄出来,但因为刚做直播没多久,没啥人看,也就没啥包袱,直接开整,最后还是让我弄出来了。
本篇文章就记录一下开发过程。
前端开发
经过简单的调研,放弃一开始想用Vue3开发的想法,直接使用HTML、CSS、JS搞则可,再上个Jquery,来使用Ajax,大体的流程为:
Code => Ajax => Python Web(Flask) => Run Code => Result
代码通过Ajax发给后端服务(Flask构建),不同编程语言使用不同的解释器去执行相应的代码,将执行的结果返回。
创建online-ide的目录,在目录下,构建如下结构:
C:\USERS\ADMIN\WORKPLACE\ONLINE-IDE
├─back-end├─serve.py
└─front-end├─ide.html├─css└─style.css├─js└─ide.js└─lib
front-end用于放前端代码,back-end用于放后端代码,我们将页面的主代码写到ide.html中,代码非常简单,就是用div构建不同的部分,然后用css简单修饰一下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Online IDE</title><!-- <link rel="stylesheet" href="css/style.css"/> --><link rel="stylesheet" href="front-end/css/style.css">
</head>
<body><div class="header"> Online IDE </div><div class="control-panel"><!-- 选择编程语言 -->选择编程语言: <select name="languages" id="languages" class="languages" onchange="changeLanguage()"><option value="c">C</option><option value="cpp">C++</option><option value="nodejs">Node.js</option><option value="python">Python</option></select></div><div class="editor" id="editor"><!-- 编写代码的地方 --></div><div class="button-container"><!-- 点击按钮,运行代码 --><button class="btn" onclick="runCode()"> 运行 </button></div><div class="output"><!-- 代码结果输出 --></div>
</body>
</html>
代码中有相应的注释,就不赘述了。
这里有个核心就是前端要有代码编辑区域,单纯的div是无法满足代码编辑需求的,比如代码高亮,简单的语法报错等,通过简单搜索,发现ace(https://github.com/ajaxorg/ace)这个项目,该项目通过JS实现了支持代码高亮的代码编辑器。
阅读ace的文档发现项目作者提供了打包好的版本ace-builds(https://github.com/ajaxorg/ace-builds/),我们可以直接使用。
通过git clone拉取ace-builds项目,然后将src中的所有代码文件都赋值front-end/lib中,这些就是不同编程语言对应着其中的文件。
获取了ace后,我们还需要使用它,在ide.js中,我们写入如下代码:
let editor;window.onload = function() {// 载入aceeditor = ace.edit("editor");// 设置编辑器主题editor.setTheme("ace/theme/monokai");// 设置编辑器解析的编程语言editor.session.setMode("ace/mode/c_cpp");}// 选择不同编程语言时,需要切换ace的modefunction changeLanguage() {let language = $("#languages").val();if (language == 'c' || language == 'cpp') {editor.session.setMode("ace/mode/c_cpp");} else if (language == 'python'){editor.session.setMode("ace/mode/python");}else if (language == 'nodejs'){editor.session.setMode("ace/mode/javascript");};}// 用户写完代码,点击运行时,将代码通过Ajax发送至Python后端function runCode() {$.ajax({url: "/run_code",method: "POST",data: {language: $("#languages").val(),code: editor.getSession().getValue()},success: function(response) {console.log('success');console.log(response);$('.output').text(response);}})}
至此,前端就开发完了。
后端开发
后端我选择Flask来开发,非常快,直接基于Flask docs里提供的代码,复制粘贴,再修修改改则可,我们将代码写到back-end的serve.py中,代码如下:
import subprocess
import os
import time
from flask import Flask
from flask import render_template
from flask import requesttemplate_dir = os.path.abspath("../front-end")
static_folder = os.path.abspath("../front-end")
app = Flask(__name__, static_folder=static_folder, template_folder=template_dir)@app.route("/run_code", methods=['GET', 'POST'])
def run_code():if request.method == 'POST':"""1.接收到前端信息2.将其存入文件中3.使用相关的解释器去执行文件中的代码4.将执行的结果返回给前端"""code = request.values.get('code')language = request.values.get('language')code_file_path = os.path.join(os.path.abspath('codes')) + str(time.time()) + '.code'with open(code_file_path, 'w') as f:f.write(code)if language == 'python':py_path = 'c:\\users\\admin\\appdata\\local\\programs\\python\\python38\\python.exe'process = subprocess.Popen([py_path, code_file_path],stdout=subprocess.PIPE,stderr=subprocess.PIPE)stdout, stderr = process.communicate()output = stdout + stderrelif language == 'nodejs':node_path = r'C:\Program Files\nodejs\node.exe'process = subprocess.Popen([node_path, code_file_path],stdout=subprocess.PIPE,stderr=subprocess.PIPE)stdout, stderr = process.communicate()output = stdout + stderrreturn outputelif request.method == 'GET':return render_template("ide.html", name="run code")if __name__ == "__main__":app.run(port=8001)
上述代码没啥难度,就是设置了一个run_code接口,如果是GET请求,则返回HTML页面(ide.html),如果是POST,则按编程语言的类型选择相应的解释器,去执行相应的代码。
通过Python的subprocess,利用shell的形式执行代码。
效果
运行项目,先用Python来实现斐波那契数列,效果如下:
换成JavaScript来实现斐波那契数列,效果如下:
结尾
哦豁,实现下来,比我想象的简单,整个直播的过程对我来说有点像限时编程,播完后,有点累,但感觉开发出来挺爽的。
Enjoy Code,我们下篇文章见。