feat: add python feature
This commit is contained in:
parent
3093f7e624
commit
46493cf1b4
3503
package-lock.json
generated
3503
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev-web": "webpack serve --open",
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
@ -20,10 +21,16 @@
|
|||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
|
"@types/webpack-env": "^1.18.5",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "15.1.3",
|
"eslint-config-next": "15.1.3",
|
||||||
|
"html-webpack-plugin": "^5.6.3",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"typescript": "^5"
|
"ts-loader": "^9.5.1",
|
||||||
|
"typescript": "^5.7.2",
|
||||||
|
"webpack": "^5.97.1",
|
||||||
|
"webpack-cli": "^6.0.1",
|
||||||
|
"webpack-dev-server": "^5.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import Docker from 'dockerode';
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
|
||||||
// 创建 Docker 客户端实例
|
// 创建 Docker 客户端实例
|
||||||
const docker = new Docker();
|
const docker = new Docker();
|
||||||
|
|
||||||
@ -15,14 +16,20 @@ export const runCode = async (params: { code: string; language: string }) => {
|
|||||||
throw new Error('Code and language are required.');
|
throw new Error('Code and language are required.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const supportedLanguages = ['c', 'java'];
|
const supportedLanguages = ['c', 'java', 'python'];
|
||||||
if (!supportedLanguages.includes(language)) {
|
if (!supportedLanguages.includes(language)) {
|
||||||
throw new Error(`Language '${language}' is not supported. Only 'c' and 'java' are supported.`);
|
throw new Error(`Language '${language}' is not supported. Only 'c', 'java', and 'python' are supported.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据语言选择文件名和编译命令
|
// 根据语言选择文件名和编译/运行命令
|
||||||
const fileName = language === 'c' ? 'main.c' : 'Main.java';
|
const fileName =
|
||||||
const compileCmd = language === 'c' ? 'gcc main.c -o main && ./main' : 'javac Main.java && java Main';
|
language === 'c' ? 'main.c' :
|
||||||
|
language === 'java' ? 'Main.java' :
|
||||||
|
'script.py';
|
||||||
|
const runCmd =
|
||||||
|
language === 'c' ? 'gcc main.c -o main && ./main' :
|
||||||
|
language === 'java' ? 'javac Main.java && java Main' :
|
||||||
|
'python3 script.py';
|
||||||
|
|
||||||
// 创建临时目录用于存储代码文件
|
// 创建临时目录用于存储代码文件
|
||||||
const tempDir = path.join('/tmp', `${Date.now()}`);
|
const tempDir = path.join('/tmp', `${Date.now()}`);
|
||||||
@ -35,7 +42,7 @@ export const runCode = async (params: { code: string; language: string }) => {
|
|||||||
// 创建并启动 Docker 容器
|
// 创建并启动 Docker 容器
|
||||||
const container = await docker.createContainer({
|
const container = await docker.createContainer({
|
||||||
Image: 'fly6516.synology.me:8080/multilang:latest',
|
Image: 'fly6516.synology.me:8080/multilang:latest',
|
||||||
Cmd: ['sh', '-c', compileCmd],
|
Cmd: ['sh', '-c', runCmd],
|
||||||
AttachStdout: true,
|
AttachStdout: true,
|
||||||
AttachStderr: true,
|
AttachStderr: true,
|
||||||
Tty: false,
|
Tty: false,
|
||||||
|
122
src/app/page.tsx
122
src/app/page.tsx
@ -1,62 +1,86 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { runCode } from '@/actions'; // 导入 Server Action
|
import { runCode } from '@/actions'; // 导入 Server Action
|
||||||
|
|
||||||
|
import './styles.css'; // 引入样式
|
||||||
|
|
||||||
|
const root = document.getElementById('root');
|
||||||
|
if (root) {
|
||||||
|
root.innerHTML = 'Hello, world!';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <reference types="webpack-env" />
|
||||||
|
|
||||||
|
if (module.hot) {
|
||||||
|
module.hot.accept(() => {
|
||||||
|
console.log('HMR is working!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启用 HMR
|
||||||
|
if (module.hot) {
|
||||||
|
module.hot.accept('./styles.css', () => {
|
||||||
|
console.log('CSS updated!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const CodeRunner = () => {
|
const CodeRunner = () => {
|
||||||
const [code, setCode] = useState('');
|
const [code, setCode] = useState('');
|
||||||
const [language, setLanguage] = useState('c');
|
const [language, setLanguage] = useState('c'); // 默认语言为 C
|
||||||
const [output, setOutput] = useState('');
|
const [output, setOutput] = useState('');
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
|
||||||
const runCodeHandler = async () => {
|
const runCodeHandler = async () => {
|
||||||
try {
|
try {
|
||||||
// 调用 Server Action 执行代码
|
// 调用 Server Action 执行代码
|
||||||
const result = await runCode({ code, language });
|
const result = await runCode({ code, language });
|
||||||
|
|
||||||
setOutput(result.output);
|
setOutput(result.output || ''); // 如果没有输出,设置为空字符串
|
||||||
setError('');
|
setError(result.error || ''); // 如果没有错误,设置为空字符串
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError((err as Error).message);
|
setError((err as Error).message);
|
||||||
setOutput('');
|
setOutput('');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
|
||||||
<h1>Code Runner</h1>
|
|
||||||
<textarea
|
|
||||||
value={code}
|
|
||||||
onChange={(e) => setCode(e.target.value)}
|
|
||||||
placeholder="Write your code here"
|
|
||||||
rows={10}
|
|
||||||
cols={50}
|
|
||||||
/>
|
|
||||||
<div>
|
<div>
|
||||||
<label>
|
<h1>Code Runner</h1>
|
||||||
Language:
|
<textarea
|
||||||
<select value={language} onChange={(e) => setLanguage(e.target.value)}>
|
value={code}
|
||||||
<option value="c">C</option>
|
onChange={(e) => setCode(e.target.value)}
|
||||||
<option value="java">Java</option>
|
placeholder="Write your code here"
|
||||||
</select>
|
rows={10}
|
||||||
</label>
|
cols={50}
|
||||||
</div>
|
/>
|
||||||
<button onClick={runCodeHandler}>Run Code</button>
|
<div>
|
||||||
|
<label>
|
||||||
|
Language:
|
||||||
|
<select value={language} onChange={(e) => setLanguage(e.target.value)}>
|
||||||
|
<option value="c">C</option>
|
||||||
|
<option value="java">Java</option>
|
||||||
|
<option value="python">Python</option> {/* 添加 Python */}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button onClick={runCodeHandler}>Run Code</button>
|
||||||
|
|
||||||
{output && (
|
{output && (
|
||||||
<div>
|
<div>
|
||||||
<h3>Output:</h3>
|
<h3>Output:</h3>
|
||||||
<pre>{output}</pre>
|
<pre>{output}</pre>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{error && (
|
{error && (
|
||||||
<div>
|
<div>
|
||||||
<h3>Error:</h3>
|
<h3>Error:</h3>
|
||||||
<pre>{error}</pre>
|
<pre>{error}</pre>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CodeRunner;
|
export default CodeRunner;
|
||||||
|
11
src/index.html
Normal file
11
src/index.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Webpack HMR</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
6
src/style.css
Normal file
6
src/style.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: lightblue;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
@ -13,6 +13,7 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
|
"allowSyntheticDefaultImports": true, // 允许合成默认导入
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
"name": "next"
|
"name": "next"
|
||||||
|
60
webpack.config.js
Normal file
60
webpack.config.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 自动生成 HTML 文件
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// 入口文件
|
||||||
|
entry: './src/app/page.tsx', // 将入口文件指定为 page.tsx
|
||||||
|
|
||||||
|
// 输出配置
|
||||||
|
output: {
|
||||||
|
filename: 'bundle.js', // 打包后的文件名
|
||||||
|
path: path.resolve(__dirname, 'dist'), // 输出文件的目录
|
||||||
|
},
|
||||||
|
|
||||||
|
// 模块解析
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.tsx', '.js', '.json'], // 支持 .ts, .tsx, .js, .json 文件
|
||||||
|
},
|
||||||
|
|
||||||
|
// 模块加载规则
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/, // 匹配 TypeScript 和 JSX 文件
|
||||||
|
use: 'ts-loader', // 使用 ts-loader 转换 TypeScript 为 JavaScript
|
||||||
|
exclude: /node_modules/, // 排除 node_modules 目录
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/, // 匹配 CSS 文件
|
||||||
|
use: ['style-loader', 'css-loader'], // 使用 style-loader 和 css-loader 加载 CSS 文件
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(jpg|jpeg|png|gif|svg)$/, // 匹配图片文件
|
||||||
|
use: ['file-loader'], // 使用 file-loader 处理图片
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// 插件
|
||||||
|
plugins: [
|
||||||
|
new webpack.HotModuleReplacementPlugin(), // 启用热更新插件
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: './src/index.html', // 自动生成 HTML 文件
|
||||||
|
filename: 'index.html', // 生成的文件名
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
// 开发服务器配置
|
||||||
|
devServer: {
|
||||||
|
static: path.join(__dirname, 'dist'), // 使用 static 配置替代 contentBase
|
||||||
|
hot: true, // 启用热更新
|
||||||
|
open: true, // 自动打开浏览器
|
||||||
|
port: 8080, // 设置开发服务器端口
|
||||||
|
historyApiFallback: true, // 支持单页应用(SPA)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 开发模式设置
|
||||||
|
mode: 'development', // 开发模式
|
||||||
|
devtool: 'source-map', // 开启源码映射,方便调试
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user